Bring your own records
Connect a domain with records only you know, such as email (SES, Workspace) and verification tokens, and see what such a connection does and does not get.
By default a connection's record set is derived by the platform: a CNAME
(or root equivalent) pointing web traffic at our edge, plus www when you ask
for it. Some integrations need records only you know: Amazon SES mints
three Easy-DKIM CNAMEs per domain, Google Workspace has its own MX set, a
partner wants a verification TXT. Those ride the same flow as the web
records: the same detection, the same rails, the same polling, the same
widget.
Supplying the records
Server to server (an API key, never a widget token):
curl -X PUT https://api.customdomain.ai/v1/connections/<ID>/records \
-H "Authorization: Bearer cd_live_..." \
-H "Content-Type: application/json" \
-d '{
"records": [
{ "type": "CNAME", "host": "abc123._domainkey.mail.acme.com", "value": "abc123.dkim.amazonses.com" },
{ "type": "CNAME", "host": "def456._domainkey.mail.acme.com", "value": "def456.dkim.amazonses.com" },
{ "type": "MX", "host": "mail.acme.com", "value": "10 feedback-smtp.us-east-1.amazonses.com" },
{ "type": "TXT", "host": "mail.acme.com", "value": "v=spf1 include:amazonses.com ~all" }
]
}'PUT /v1/connections/{id}/records replaces the connection's desired
set with yours. From then on the poller verifies your records, the widget's
manual screen shows your records, and live means your records resolve.
The poller compares values for CNAME, A, AAAA, APEXCNAME and TXT
records (a TXT counts when it contains your value). MX, SPFM and CAA
records are written, but they are not value-checked, so a set made only of
those can go live without confirming them in DNS.
See Create a connection: supplying your own
records.
Pre-flight with the real set. Pass the same records to
POST /v1/domains:check so conflict detection and the automatic→manual
fallback prediction run against what you'll actually write, not the default
web record. The check also returns integration_warnings (addressed to
you, the developer, never shown to the end user) when the set is
misconfigured in a way that only bites in production. The one warning today is
supplied_apex_unrealizable: you supplied a root record pointing at a
hostname, and this provider has no root-CNAME type (see
Root domains).
SPF safely. Never write a second v=spf1 TXT: a domain may have only
one. Use the SPFM meta-record and the engine merges your mechanisms into
whatever SPF already exists. See Email DNS.
Which rails carry your records
| Rail | Your records |
|---|---|
| Sign in with the provider (OAuth) | Written as supplied |
| API key | Written as supplied |
| One-click setup (Domain Connect) | Refused: a provider-hosted template can't carry a caller-authored set. The start returns an error; use another rail. |
| Manual | Shown to the end user exactly as supplied |
What an email-only connection does not get
A connection whose records contain no web record pointing at our edge
(only MX, TXT, DKIM CNAMEs) is a record-delivery connection. It
goes live when the records resolve, it fires the same webhooks, and it is
listed like any other. It is not served by the edge:
- No TLS certificate is issued for it.
- If someone points the root
Arecord at our edge anyway, the edge answers with a clear "this domain isn't set up to be served here" page, not your app. The ask gate only approves hosts whose record set includes an edgeCNAME/ALIASor ourArecords (reasonno_edge_record).
If you want both email and web on the domain, include the edge record in the set you supply (or create the web connection normally and add the email records to it).
Rules and limits
- Server-side only. The call needs an API key; a widget token is
refused (
403): a page in a browser must not choose the records we write. - Replace, don't patch. The whole set is replaced on each
PUT. - Before anything is written. Once the connection's records have been
applied (or it is live), the set is frozen: a
PUTwith a different set returns409with disconnect and reconnect the domain to change them. Changing a live connection's target out from under DNS is what that refusal prevents. Re-sending the identical set is accepted and returns200unchanged, so a retry is safe. - In the connection's zone. The zone is the registrable domain, so a
connection on
mail.acme.comaccepts any host at or underacme.com. A relative host (@,_dmarc,sel._domainkey) is anchored to the connection's own name (_dmarcbecomes_dmarc.mail.acme.com). An absolute host outside the zone is refused with400 invalid_request. - Supported types.
A,AAAA,CNAME,APEXCNAME,MX,TXT,CAAandSPFM. Anything else (NS,SRV, the forwarding pseudo-types) is refused. Send between 1 and 25 records. - Root records. A
CNAMEat the zone root is rewritten to the engine's apex type and realized per provider (or refused where it can't be), under the same rules as Root domains.
Records you later stop needing are not deleted at the provider by this endpoint; removal is a disconnect concern.
When to use this instead of the widget's default
- SES / SendGrid / Postmark domain authentication: the DKIM selectors are per-account and unknowable to us.
- A verification
TXTfor a third party: same reason. - An
MXset your platform manages for the customer.
For plain web connections, don't supply records: the derived set already
handles root vs subdomain per provider, www, and the edge target.
Root domains (apex)
Why acme.com differs from www.acme.com, what each DNS provider can hold at the root, and how CustomDomain™ connects it with ALIAS-style records or A records.
Email DNS & SPF merge
Add MX, SPF, DKIM and DMARC records alongside a connection, and see how SPFM merges your mechanisms into an existing SPF record without overwriting it.