Custom domains (bring your own domain)
Every paid account gets a ready-to-use platform subdomain (something like
a1b2c3.replylayer.net) the moment it's ready to send. Mailboxes created
there work out of the box, and it never counts against your custom-domain
limit. Use it for testing, internal agents, or anything where branded
addressing doesn't matter. Trial (sandbox) accounts send from a temporary
shared trial address instead — see Plans & limits — and get
their own platform subdomain the moment they upgrade.
Bring your own domain (BYOD) lets you send and receive from a subdomain you
control — ai.acme.com, bot.example.io, whatever fits your product. You keep
full authority over your DNS: you add a handful of records ReplyLayer gives you,
at whatever provider already hosts your zone (Route 53, Cloudflare, GoDaddy,
etc.). ReplyLayer verifies those records, then routes mail for the subdomain.
This guide covers the managed transport, where ReplyLayer handles outbound delivery and inbound routing for you. A delegated domain can alternatively run its own SMTP and IMAP servers (self-hosted transport) instead of the managed path.
What ReplyLayer does — and does not — do
ReplyLayer:
- Registers your subdomain with its delivery infrastructure.
- Returns the exact DNS records you need to add (SPF, DKIM, tracking, MX, a DMARC policy, and an ownership-proof record).
- Polls those records in the background and flips the domain to verified once they're all live.
- Routes inbound mail and signs outbound mail for the subdomain once verified.
ReplyLayer does not:
- Create or manage DNS zones. It never touches your root zone and never needs credentials to your DNS provider. You add the records yourself.
- Modify your DNS after setup. Health checks are read-only.
- Remove your records when you delete the domain. It can't — it doesn't control your DNS. Deleting a domain in ReplyLayer stops routing on its side; you remove the DNS records yourself when you're done.
A custom subdomain is a subdomain of a domain you already own. ReplyLayer does not register root domains or issue TLS certificates for you.
Who can manage domains
Domain management requires an admin-role API key or a dashboard session. Mailbox-scoped agent keys are rejected — an agent can't add, verify, or delete a domain. This keeps domain setup a deliberate, human-or-admin operation.
The setup flow
1. Request the domain
Submit the subdomain you want to use:
curl -X POST https://api.replylayer.ai/v1/domains \
-H "Authorization: Bearer $REPLYLAYER_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{"domain": "ai.acme.com"}'import { ReplyLayer } from '@replylayer/sdk';
const rl = new ReplyLayer({ apiKey: process.env.REPLYLAYER_ADMIN_KEY! });
const domain = await rl.domains.create({ domain: 'ai.acme.com' });
console.log(domain.verification_status, domain.dns_records_json);rly domain create ai.acme.comThe first custom domain on an account goes through a brief review before its
DNS records are issued. When that happens the create response comes back with
verification_status: "requested" and a message telling you it's pending
review. Once approved, the domain advances to pending_dns and its
dns_records_json array appears — poll GET /v1/domains/:id (or watch the
Domains page in the dashboard) for the transition. Subsequent domains on the
same account skip the review and land in pending_dns immediately.
2. Add the DNS records
The response's dns_records_json array is the canonical list of records to
create. Each entry carries type, name, value, an optional priority
(for MX records), a purpose tag, and a per-record validation flag that flips
true as ReplyLayer confirms the record is live. Copy name and value
verbatim — the exact values are generated per domain.
purpose | Record type | What it's for |
|---|---|---|
ownership_proof | TXT | Proves you control the subdomain. ReplyLayer checks this record directly; verification can't complete without it. |
spf | TXT | Authorizes ReplyLayer to send on the subdomain's behalf. |
dkim | CNAME or TXT | Cryptographically signs your outbound mail. |
tracking | CNAME | Serves open/click/unsubscribe tracking links from your subdomain. |
inbound_mx | MX (two records) | Routes inbound mail for the subdomain to ReplyLayer. |
dmarc | TXT | Publishes a DMARC policy for the subdomain. |
The DMARC record is generated for you and defaults to a non-disruptive monitoring policy with relaxed alignment:
v=DMARC1; p=none; rua=mailto:[email protected]; adkim=r; aspf=r;p=none means "observe, don't reject" — nothing your subdomain sends is blocked
by the policy. Once you've validated delivery, you can tighten it to
quarantine or reject in your own DNS. If you already run a DMARC-management
tool, merge its rua= destination into this record rather than replacing it, and
keep the mailto:[email protected] address in place.
Tips that trip people up:
- Some DNS providers treat the Name field as relative to your domain and
append it automatically — silently publishing doubled names like
mail.example.com.example.com. If every record shows invalid even though you've added them, look up the published names (dig TXT _replylayer-verify.mail.example.com) — if they're doubled, enter only the leading part (mail,_replylayer-verify.mail, …) without your domain. - If your subdomain already has an SPF (
TXT) record with differentinclude:directives, merge them into one record. Two separate SPF records is an invalid configuration and will fail verification. - DNS usually propagates within 5–60 minutes, though some providers take longer.
3. Verify
ReplyLayer polls your records automatically in the background. To check immediately after adding them, trigger a check:
curl -X POST https://api.replylayer.ai/v1/domains/$DOMAIN_ID/verify \
-H "Authorization: Bearer $REPLYLAYER_ADMIN_KEY"const result = await rl.domains.verify(domainId);
console.log(result.verification_status, result.message);rly domain verify <domain-id>This runs the same logic as the background poller: it re-checks each record and
the ownership-proof record, and promotes the domain to provider_verified
inline if everything passes. If it's still waiting, the response message says
which gate is outstanding; inspect dns_records_json for the specific record
that hasn't validated yet. The verify call is rate-limited to one per 60
seconds per domain — a 429 RATE_LIMITED response carries a Retry-After
header. The background poller keeps checking regardless, so you never have to
call this endpoint.
Verification states
verification_status is the field to watch. The managed flow moves through:
verification_status | What it means | What to do |
|---|---|---|
requested | Submitted; first-time domains are in review before records are issued | Wait for approval; poll for pending_dns |
pending_dns | Records issued; ReplyLayer is waiting for them to go live | Add every record from dns_records_json, then verify |
provider_verified | All records valid + ownership proven; the domain is operational | Create mailboxes on it |
unhealthy | Was operational, but a later health check found a record had drifted | Fix the drifted record; it recovers automatically |
failed | Terminal — setup was abandoned/expired, or the domain stayed unhealthy too long. The name becomes re-claimable | Resubmit POST /v1/domains to start over |
rejected | Terminal — the first-time review was declined | Contact support |
Once verified, ReplyLayer keeps checking your records periodically. If DNS drifts
later — an SPF edit, a changed DKIM target, an MX change — the domain moves to
unhealthy. Fix the record and it returns to provider_verified on the next
check. Persistent, unrecovered drift eventually lands the domain in failed.
failed and rejected are terminal. A failed domain's name is freed for
re-claiming, so you can simply submit it again to restart setup.
Sending from a custom domain
New mailboxes pick up your account's default sending domain. The first custom
domain to reach provider_verified is auto-promoted to default if you don't
already have one. To choose the default explicitly:
curl -X PATCH https://api.replylayer.ai/v1/domains/$DOMAIN_ID/set-default \
-H "Authorization: Bearer $REPLYLAYER_ADMIN_KEY"await rl.domains.setDefault(domainId);Only a verified, non-suspended domain can be set as the default; anything else
returns 400 DOMAIN_NOT_READY.
A mailbox's address is fixed at creation — verifying a custom domain does not move existing mailboxes onto it. To use branded addressing, create a fresh mailbox on the custom domain after it's verified. Inbound mail to any mailbox on the domain works as soon as its MX records resolve.
Your platform subdomain: naming and readiness
The platform subdomain minted at upgrade starts with a random slug. Before the
first mailbox exists on it, you can swap the random slug for a vanity slug
(acme-corp.replylayer.net) from the dashboard. Slugs are governed by a
published policy — infrastructure terms, brand and provider names, common
phishing/impersonation terms, and visually-confusable lookalikes are reserved
(422 SLUG_RESERVED), and some categories require a manual support review
(422 SLUG_REQUIRES_REVIEW). Slugs are 3–32 characters, lowercase letters,
digits and hyphens. Once any mailbox exists on the subdomain, its name is
fixed — contact support to change it.
There is no shared paid sending domain: if you create a mailbox while your
platform subdomain is still verifying, the API answers
409 DOMAIN_PROVISIONING_PENDING (retry shortly — rly mailbox create waits
automatically, and the response carries a Retry-After). A rare setup failure
surfaces as 409 DOMAIN_PROVISIONING_FAILED — retry later or contact support.
GET /v1/domains shows the subdomain's live verification_status.
Upgrading from the trial also retires the temporary trial address: the sandbox mailbox is paused — its history stays readable and exportable, but it no longer sends or receives. Your production identity is the platform subdomain (or your own domain) going forward.
Removing a domain
curl -X DELETE https://api.replylayer.ai/v1/domains/$DOMAIN_ID \
-H "Authorization: Bearer $REPLYLAYER_ADMIN_KEY"await rl.domains.delete(domainId);Delete refuses while the domain still has active mailboxes (409 ACTIVE_MAILBOXES) — remove or reassign them first. Platform subdomains can't be
deleted via the API. After a successful delete, ReplyLayer stops routing for the
subdomain; your DNS records are left in place (ReplyLayer can't touch them),
so remove them at your provider when you're finished. Inbound mail to the
subdomain will bounce and sending from it will fail once routing is torn down.
Limits and edge cases
- How many custom domains you can have depends on your plan, and sandbox accounts can't add custom domains at all. See plans & limits.
- If another account has already claimed the exact subdomain,
POST /v1/domainsreturns409 DOMAIN_TAKENwith anexpires_athint for when the stale claim lapses. Contact support if it's genuinely your domain. - A malformed subdomain is rejected up front with
400 INVALID_DOMAIN.
For the full list of error codes and their shapes, see the error reference.
Related
- Self-hosted transport — run your own SMTP and IMAP servers for a delegated domain instead of the managed path.
- Plans & limits — per-plan custom-domain counts.
- Error reference — every error code, one catalog.