Domains and DNS API
Domain choices
Section titled “Domain choices”A domain choice is {"type": "generated" | "test" | "custom", "name"?: string}; a plain string is a custom domain. It is accepted by POST /api/v1/sites (domain), Compose public_services[].domain, and template deploys (domains.<service>). A service without a choice gets the organization default: the test domain when FALAK_TEST_DOMAIN is set, else a generated name, else a domain is required.
| Type | Result |
|---|---|
generated |
<label>.<ipv4-with-dashes>.<suffix>, e.g. minio-files.63-182-218-247.sslip.io. Label: the site slug (Compose: <service>-<slug>). IP: the leader’s public IPv4, or the load balancer’s. 422 when generated names are off or the server has no public IPv4 yet. |
test |
<slug>.<FALAK_TEST_DOMAIN> (Compose: <service>-<slug>.… after the first service) |
custom |
Your domain, with automatic TLS once DNS points at the server |
GET /api/v1/domains/options — edge.view
Section titled “GET /api/v1/domains/options — edge.view”What a create form offers for a set of servers, or for an existing site.
GET /api/v1/domains/options?server=01k…,01k…GET /api/v1/domains/options?server[]=01k…&server[]=01k…GET /api/v1/domains/options?site=shop{"data": { "test_domain": null, "generated": {"suffix": "sslip.io", "ipv4": "63.182.218.247", "target": "app-1", "available": true, "reason": null}, "default": "generated", "targets": [{"server_id": "01k…", "name": "app-1", "ipv4": "63.182.218.247", "ipv6": null, "load_balancer": false}]}}targets lists where DNS must point: the site’s load balancer, else each server, leader first.
GET /api/v1/dns/check — edge.view
Section titled “GET /api/v1/dns/check — edge.view”Resolves a name from the control plane and compares it with the targets. Rate limited to 60/minute.
GET /api/v1/dns/check?name=shop.example.com&server=01k…GET /api/v1/dns/check?name=shop.example.com&site=shop&tls=1The name is resolved over DNS-over-HTTPS (FALAK_DNS_RESOLVER=doh, default resolver https://cloudflare-dns.com/dns-query) or the system resolver (system), with a 3-second timeout.
{"data": { "name": "shop.example.com", "status": "ok", "message": "Points to app-2 (63.182.218.247)", "addresses": ["63.182.218.247"], "cnames": [], "targets": [], "matched": [], "instructions": {"zone": "example.com", "host": "shop", "apex": false, "ttl": 300, "records": [{"type": "A", "name": "shop.example.com", "host": "shop", "value": "63.182.218.247", "target": "app-2"}], "alternative": {"type": "CNAME", "host": "shop", "value": "shop.63-182-218-247.sslip.io"}, "notes": ["…"]}, "certificate": null, "checked_at": "2026-09-28T12:00:00+00:00"}}status |
Meaning |
|---|---|
ok |
Every address is a target |
mismatch |
Resolves elsewhere (“Resolves to 1.2.3.4 — expected …”), or has extra records to remove |
proxied |
Cloudflare proxy addresses; HTTP-01 fails until the record is “DNS only” |
missing |
No A/AAAA record yet |
error |
Lookup failed, invalid name, or no server IP to compare with |
instructions lists the records to add: an A per target IPv4, an AAAA per IPv6, apex vs subdomain, and for subdomains of single-target sites a CNAME to the generated name as an alternative.
With site and tls=1, certificate reports what the site’s server serves for the name — {status: issued|pending, issuer, expires_at, message} — probed only when the name already points at the site.
Rate limits
Section titled “Rate limits”GET (edge.view), PUT and DELETE (edge.manage) on /api/v1/sites/{site}/domains/{domain}/rate-limit: a domain’s Cloudflare rate limit. {domain} is the domain’s id or name. Rate limited to 30/minute. See Cloudflare → Rate limits.
{"data": { "domain": "shop.example.com", "rule": {"path": "/login", "requests": 20, "period": 10, "action": "block", "timeout": 10}, "zone": "example.com", "proxied": true, "limits": {"plan": "free", "rules": 1, "host": false, "periods": [10], "timeouts": [10], "challenge_timeout": false, "note": "…"}, "zone_rule": null}}limitsisnulloutside a managed zone.zone_rule({domain, path}) is another domain’s Free-plan rule that applies to this domain too.PUT {path?, requests, period, action: block|managed_challenge, timeout}writes the zone’s rules and returns the same shape. Formanaged_challengewithchallenge_timeout: false(below Enterprise),timeoutis ignored and stored as0.422when the domain isn’t proxied, the plan doesn’t allow the window or duration or has no rule left, or Cloudflare refuses (the token needs Zone → Zone WAF → Edit).DELETEremoves the rule.