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.com

The 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.

purposeRecord typeWhat it's for
ownership_proofTXTProves you control the subdomain. ReplyLayer checks this record directly; verification can't complete without it.
spfTXTAuthorizes ReplyLayer to send on the subdomain's behalf.
dkimCNAME or TXTCryptographically signs your outbound mail.
trackingCNAMEServes open/click/unsubscribe tracking links from your subdomain.
inbound_mxMX (two records)Routes inbound mail for the subdomain to ReplyLayer.
dmarcTXTPublishes 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 different include: 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_statusWhat it meansWhat to do
requestedSubmitted; first-time domains are in review before records are issuedWait for approval; poll for pending_dns
pending_dnsRecords issued; ReplyLayer is waiting for them to go liveAdd every record from dns_records_json, then verify
provider_verifiedAll records valid + ownership proven; the domain is operationalCreate mailboxes on it
unhealthyWas operational, but a later health check found a record had driftedFix the drifted record; it recovers automatically
failedTerminal — setup was abandoned/expired, or the domain stayed unhealthy too long. The name becomes re-claimableResubmit POST /v1/domains to start over
rejectedTerminal — the first-time review was declinedContact 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/domains returns 409 DOMAIN_TAKEN with an expires_at hint 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.