DomaineeDocs
Domains

Apply DNS with a customer token

POST /v1/domains/{id}/dns/apply — point a domain using a scoped API token the customer supplies.

POST /v1/domains/{id}/dns/apply

Writes the DNS records for you, using a scoped API token your customer supplies for their own DNS provider.

This is the third of three ways to get a domain pointed, and it exists for the gap between the other two. Connect instructions tell the customer exactly what to type. Domain Connect removes the typing where the provider supports it. This covers the technical customer on Cloudflare or DigitalOcean, who would rather paste a scoped token than click through a DNS panel and whose provider will never be reachable through Domain Connect.

Supported providers

providerToken needs
cloudflareZone:Zone:Read and Zone:DNS:Edit, scoped to the one zone
digitaloceanwrite scope on Domains

Anything else returns unsupported_provider. Use the connect instructions instead.

The token

Send it in the body, never the query string. Request URLs end up in access logs; bodies do not.

Domainee uses the token for the duration of the request and then discards it. It is never stored, never logged, and never returned in a response. There is nothing to revoke afterwards and nothing for you to rotate.

Tell your customers to scope the token to the single zone being connected. Neither provider needs account-wide access for this.

Request

curl -X POST https://api.domainee.dev/v1/domains/$DOMAIN_ID/dns/apply \
  -H "Authorization: Bearer $DOMAINEE_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "provider": "cloudflare",
    "token": "<the customer'\''s scoped DNS token>"
  }'

Response — 200 OK

{
  "applied": {
    "provider": "cloudflare",
    "written": [
      { "type": "A", "name": "acme.com", "value": "75.2.52.197", "ttl": 300 },
      { "type": "A", "name": "acme.com", "value": "3.33.255.144", "ttl": 300 }
    ],
    "removed": 1
  },
  "domain": { "...": "the refreshed Domain object" }
}

removed counts conflicting records deleted to make room. The domain is re-probed immediately, so domain.status is current rather than waiting up to five minutes for the next scheduled check.

What it touches

Only the records that would conflict at the hostname being pointed: A, AAAA, CNAME and ALIAS at that exact name. Everything else in the zone is left alone, including MX, TXT, SPF, DKIM, DMARC and every other hostname. Your customer's email keeps working.

At a root domain we write the anycast A records rather than a CNAME. A CNAME at a zone apex is exclusive, so using one there would mean deleting the MX records sitting beside it.

On Cloudflare, records are created with proxy disabled deliberately. An orange-clouded record makes Cloudflare terminate TLS itself and our certificate is never issued. Writing the record ourselves is what removes that failure mode for good.

Errors

CodeStatusMeaning
auth_failed400The provider rejected the token, or it lacks the scopes above.
zone_not_found404The provider has no zone for this domain, or the token cannot see it.
write_failed422The provider accepted the token but refused a record. Message contains their reason.
unsupported_provider422We can't write to that provider.
no_anycast_configured422Apex domain on a deployment with no anycast addresses.
not_found404Domain doesn't exist in this workspace.

No MCP tool, on purpose

Unlike the rest of this feature set, this is not exposed to AI agents. Routing a customer's DNS credentials through an agent's context is a bad trade for the convenience. Agents get get_connect_instructions instead, which needs no secrets at all.

On this page