Cloudflare × WAB DNS Discovery

One-click enable or disable the WAB DNS Discovery TXT record for any domain managed in Cloudflare. Uses the Cloudflare API directly from your browser — your token never leaves your device.

1. Cloudflare Credentials

Create a scoped token at dash.cloudflare.com → API Tokens. Select template Edit zone DNS and restrict to the zone you need.

2. Domain

3. Actions

How it works

1
Fetch the WAB record template for your domain (GET /api/discovery/provider/record-template) to get the exact TXT value.
2
Resolve the Cloudflare Zone ID from the domain name (GET /zones?name=…).
3
Enable: look up existing _wab TXT record → create it if absent, or update it if the value changed.
Disable: look up the record → delete it if found.
4
Call GET /api/discovery/provider/status?domain=… to confirm WAB sees the record live (DNS propagation may take up to 60 s).

Code Snippets

Node.js
cURL
Python
// npm install node-fetch
const fetch = require('node-fetch');

const CF_TOKEN = process.env.CF_API_TOKEN;
const DOMAIN   = 'example.com';
const WAB_ENDPOINT = `https://${DOMAIN}/.well-known/wab.json`;
const TXT_VALUE = `v=wab1; endpoint=${WAB_ENDPOINT}`;

async function cfHeaders() {
  return { Authorization: `Bearer ${CF_TOKEN}`, 'Content-Type': 'application/json' };
}

async function getZoneId(domain) {
  const r = await fetch(`https://api.cloudflare.com/client/v4/zones?name=${domain}`, { headers: await cfHeaders() });
  const j = await r.json();
  if (!j.success || !j.result[0]) throw new Error('Zone not found');
  return j.result[0].id;
}

async function enableWAB() {
  const zoneId = await getZoneId(DOMAIN);
  const base = `https://api.cloudflare.com/client/v4/zones/${zoneId}/dns_records`;
  // check existing
  const list = await (await fetch(`${base}?type=TXT&name=_wab.${DOMAIN}`, { headers: await cfHeaders() })).json();
  if (list.result && list.result[0]) {
    // update
    const id = list.result[0].id;
    await fetch(`${base}/${id}`, { method: 'PUT', headers: await cfHeaders(),
      body: JSON.stringify({ type: 'TXT', name: `_wab.${DOMAIN}`, content: TXT_VALUE, ttl: 3600 }) });
    console.log('Updated _wab TXT record');
  } else {
    await fetch(base, { method: 'POST', headers: await cfHeaders(),
      body: JSON.stringify({ type: 'TXT', name: `_wab.${DOMAIN}`, content: TXT_VALUE, ttl: 3600 }) });
    console.log('Created _wab TXT record');
  }
}

async function disableWAB() {
  const zoneId = await getZoneId(DOMAIN);
  const base = `https://api.cloudflare.com/client/v4/zones/${zoneId}/dns_records`;
  const list = await (await fetch(`${base}?type=TXT&name=_wab.${DOMAIN}`, { headers: await cfHeaders() })).json();
  if (list.result && list.result[0]) {
    await fetch(`${base}/${list.result[0].id}`, { method: 'DELETE', headers: await cfHeaders() });
    console.log('Deleted _wab TXT record');
  } else {
    console.log('No _wab record found (already disabled)');
  }
}

enableWAB().catch(console.error);
# 1. Get Zone ID
ZONE=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=example.com" \
  -H "Authorization: Bearer $CF_API_TOKEN" | jq -r '.result[0].id')

# 2. Create TXT record
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE/dns_records" \
  -H "Authorization: Bearer $CF_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "type":    "TXT",
    "name":    "_wab.example.com",
    "content": "v=wab1; endpoint=https://example.com/.well-known/wab.json",
    "ttl":     3600
  }'

# Delete (disable)
REC=$(curl -s "https://api.cloudflare.com/client/v4/zones/$ZONE/dns_records?type=TXT&name=_wab.example.com" \
  -H "Authorization: Bearer $CF_API_TOKEN" | jq -r '.result[0].id')
curl -s -X DELETE "https://api.cloudflare.com/client/v4/zones/$ZONE/dns_records/$REC" \
  -H "Authorization: Bearer $CF_API_TOKEN"
import os, requests

CF_TOKEN = os.environ['CF_API_TOKEN']
DOMAIN   = 'example.com'
HEADERS  = {'Authorization': f'Bearer {CF_TOKEN}', 'Content-Type': 'application/json'}
TXT_VAL  = f'v=wab1; endpoint=https://{DOMAIN}/.well-known/wab.json'

def zone_id():
    r = requests.get(f'https://api.cloudflare.com/client/v4/zones?name={DOMAIN}', headers=HEADERS)
    return r.json()['result'][0]['id']

def enable_wab():
    zid = zone_id()
    base = f'https://api.cloudflare.com/client/v4/zones/{zid}/dns_records'
    lst = requests.get(f'{base}?type=TXT&name=_wab.{DOMAIN}', headers=HEADERS).json()
    payload = {'type': 'TXT', 'name': f'_wab.{DOMAIN}', 'content': TXT_VAL, 'ttl': 3600}
    if lst['result']:
        requests.put(f'{base}/{lst["result"][0]["id"]}', json=payload, headers=HEADERS)
        print('Updated')
    else:
        requests.post(base, json=payload, headers=HEADERS)
        print('Created')

def disable_wab():
    zid = zone_id()
    base = f'https://api.cloudflare.com/client/v4/zones/{zid}/dns_records'
    lst = requests.get(f'{base}?type=TXT&name=_wab.{DOMAIN}', headers=HEADERS).json()
    if lst['result']:
        requests.delete(f'{base}/{lst["result"][0]["id"]}', headers=HEADERS)
        print('Deleted')
    else:
        print('Already disabled')

enable_wab()

← Back to Provider Onboarding · Provider Sandbox · DNS Discovery