---
title: "Upgrade sending domain DNS"
method: POST
path: "/websites/{domain}/dns-upgrade"
tags: ["Websites"]
---

# Upgrade sending domain DNS

`POST /websites/{domain}/dns-upgrade`

## Request

- Base URL: `https://api.sequenzy.com/api/v1`
- URL: `https://api.sequenzy.com/api/v1/websites/{domain}/dns-upgrade`
- Auth: HTTP bearer

Starts moving a verified sending domain onto the current per-domain CNAME record set without removing it. The domain keeps sending on its current records while the upgrade is in progress, and sender profiles, sequences and tracking stay as they are. Publish the CNAMEs in website.dnsUpgrade.records next to your current records; remove nothing yet. About an hour after the required ones (DKIM and the return path) are visible on public DNS (Google and Cloudflare resolvers), the domain switches by itself; the wait lets cached "does not exist" answers expire. Sequenzy prepares the sending setup of the domain separately and switches only once it is confirmed, so sending is normally not interrupted and no emails are held. If that is not possible for a domain, emails sent through Amazon SES can be held for a few minutes while SES confirms the new setup, then they go out. The domain also gets a new 2048-bit DKIM key; you still publish the same four CNAMEs. An older SES-only domain needs a working DMARC record first, otherwise the request returns 400. Call POST /websites/{domain}/verify after publishing to check now; it does not skip the wait. After the switch, website.dnsUpgrade lists the old records to delete after deleteOldRecordsAfter; for an older SES-only domain these include the old return path records (MX and TXT at send.<domain>) and the DKIM TXT, and DMARC stays. Requires websites:write.

## Path parameters

- `domain` string, required

## Request body

- object
  - `mailFromPrefix` string: Return-path subdomain label for the new records. Defaults to rp; if rp is taken or already has DNS records, rp1, then sqrp. The SES return path is this label followed by 2 (rp2 by default), moving to bounces or sesbounces if that name is in use; publish the returned names. One DNS label of letters, numbers or hyphens; inbound is not allowed, and a label that already has DNS records, or is the current return path or the tracking domain label, is rejected with 400.

## Response `200`

Upgrade started. website.dnsUpgrade.status is in_progress and records lists the CNAMEs to publish.

- object
  - `success` boolean
  - `website` Website
    - `id` string
    - `domain` string
    - `status` 'not_started' | 'pending' | 'verified' | 'failed' | 'misconfigured': Stored DNS verification status. This does not imply that a sending transport is ready.
    - `dnsVerified` boolean: Whether the customer DNS records are verified.
    - `readyToSend` boolean: Whether the domain is fully ready to send (DNS verified and activation finished).
    - `readiness` object: Customer-facing sending readiness. When readyToSend is false, reason says why; dns_* reasons describe your DNS records, while activation reasons resolve on Sequenzy's side.
      - `status` 'setup_required' | 'verifying_dns' | 'activating' | 'ready' | 'blocked'
      - `reason` 'dns_not_started' | 'dns_pending' | 'dns_failed' | 'activation_pending' | 'activation_failed' | 'sending_unavailable' | 'null', nullable
    - `message` string: Creation or setup summary when returned by a mutating operation.
    - `dnsRecords` object, nullable: The DNS records and their per-record verification status. Publish the DKIM record, DMARC when present, and the bounce records described by bounceRecords (returnPathCnameRecord when bounceRecords.style is cname, otherwise spfRecord and mxRecord; never both at the same name). Receiving mail is set up separately with receiving domains (/receiving-domains); the inbound* fields some older domains still return are deprecated. GET returns stored results; POST verify performs a fresh check.
      - `platformDnsRecords` object[]: Present on domains added with the per-domain CNAME record set. Publish these CNAMEs instead of the DKIM TXT record in byodkimRecord (a TXT published there still verifies, but a key change then needs a DNS change). Branch on whether this field is present. Only entries with required true block verification. dkim_spare lets Sequenzy change the DKIM key without a DNS change from you; ses_return_path, once it resolves, aligns SPF with your domain on every email.
        - `purpose` 'dkim' | 'dkim_spare' | 'ses_return_path', required
        - `type` 'CNAME', required
        - `name` string, required
        - `value` string, required
        - `required` boolean, required
        - `status` 'pending' | 'verified' | 'misconfigured', required
        - `diagnostic` object: Why the record is not verified yet, when known.
      - `returnPathCnameRecord` object: The single bounce CNAME, present when bounceRecords.style is cname. It replaces spfRecord and mxRecord, which stay listed because verification checks them through the CNAME. Never publish it alongside them.
        - `name` string, required
        - `value` string, required
      - `returnPathCnameStatus` 'pending' | 'verified' | 'misconfigured'
      - `returnPathCnameDiagnostic` object: Why the bounce CNAME is not verified yet, when known.
      - `inboundVerificationRecord` object: Deprecated. Receiving is now set up with receiving domains (/receiving-domains). This field reflects a reply setup from before receiving domains, is only present on domains that had one, and is no longer used to route mail. It held the TXT record an older inbound reply host needed for Amazon SES ownership; a migrated host's records now appear on its receiving domain.
        - `name` string, required
        - `value` string, required: Public domain-ownership token, not an API credential.
      - `inboundVerificationStatus` 'pending' | 'verified' | 'misconfigured': Deprecated. Receiving is now set up with receiving domains (/receiving-domains). This field reflects a reply setup from before receiving domains, is only present on domains that had one, and is no longer used to route mail. It held the stored ownership status of the older inbound reply host.
      - `inboundRoutingStatus` 'pending' | 'active' | 'failed': Deprecated. Receiving is now set up with receiving domains (/receiving-domains). This field reflects a reply setup from before receiving domains, is only present on domains that had one, and is no longer used to route mail. Returned when the domain has a stored inbound MX record. Read the receiving domain's status instead.
      - `inboundRoutingError` string, nullable: Deprecated. Receiving is now set up with receiving domains (/receiving-domains). This field reflects a reply setup from before receiving domains, is only present on domains that had one, and is no longer used to route mail. Null when no error was stored; omitted when the domain has no stored inbound MX record. Read the receiving domain's error instead.
      - `trackingRecord` object: CNAME record for the company tracking domain, present when the company has one. It is optional and never gates verification or sending; publish it with the other records to brand tracked links. Proxying must be off.
        - `name` string, required
        - `value` string, required
      - `trackingStatus` 'not_started' | 'pending' | 'verified' | 'failed' | 'null', nullable: Verification status of trackingRecord, including its HTTPS certificate. Informational; it never affects the domain's status.
    - `tracking` object: Link tracking for this domain. Every sending domain uses the company tracking domain, which never gates verification or sending; until it verifies, links use the shared Sequenzy tracking domain. Manage it with the Tracking Domain endpoints.
      - `policy` 'required' | 'legacy': Always legacy. Kept for compatibility.
      - `required` boolean: Always false; tracking never gates sending. Kept for compatibility.
      - `hostname` string, nullable: The company tracking hostname, or null when links use the shared Sequenzy tracking domain.
      - `status` 'not_started' | 'pending' | 'verified' | 'failed' | 'null', nullable: Verification status of hostname, including HTTPS. not_started until you confirm DNS setup with Verify Sending Domain or check it with Verify Tracking Domain.
      - `ready` boolean: Whether hostname is verified and serving HTTPS.
      - `error` string, nullable: Last tracking verification error, if any.
      - `cnameRecord` object, nullable: The CNAME to publish for hostname.
        - `type` 'CNAME'
        - `name` string
        - `value` string
    - `dkim` object: Normalized DKIM type, status, and diagnostics.
    - `spf` object: Normalized SPF status, expected record, and diagnostics.
    - `mailFrom` object: Normalized custom MAIL FROM MX status and diagnostics.
    - `bounceRecords` object: How the bounce subdomain is published. With style cname (domains added since the single CNAME shipped), publish cnameRecord instead of the spf.record and mailFrom.mxRecord records, which verification keeps checking through the CNAME. With style mx_txt (domains added earlier), publish those two records. The style is set when the domain is added.
      - `style` 'cname' | 'mx_txt', required
      - `cnameRecord` object, nullable, required: The CNAME to publish when style is cname, otherwise null.
        - `name` string, required
        - `value` string, required
      - `status` 'pending' | 'verified' | 'misconfigured', required: verified once SPF and MX both resolve correctly at the bounce subdomain, whichever records produce them.
      - `diagnostic` object, nullable, required: For style cname, why the CNAME is not verified yet (missing, pointing elsewhere, other records on the name, or a proxied record). Null for style mx_txt; read spf.diagnostic and mailFrom.diagnostic instead.
    - `dnsUpgrade` object: Upgrade of this domain to the current per-domain CNAME record set, without removing the domain. available: a verified domain on the previous record set, including an older SES-only domain that has a working DMARC record; start it with POST /websites/{domain}/dns-upgrade. in_progress: publish records next to your current records, which keep working until the switch; about an hour after every required record is visible on public DNS, the domain switches by itself. completed: shown for 30 days after the switch; delete oldRecords after deleteOldRecordsAfter. unavailable: everything else (already on the current records, not verified, verification paused, an older SES-only domain without a working DMARC record, a domain on Amazon's three-CNAME DKIM records or in the middle of an earlier records migration, a Sequenzy-managed domain, or a domain the upgrade has not been offered to yet).
      - `status` 'available' | 'in_progress' | 'completed' | 'unavailable', required
      - `startedAt` string, date-time, nullable, required: When the upgrade started. Set while in_progress.
      - `records` object[], nullable, required: The CNAMEs to add next to your current records. Set while in_progress, otherwise null. Only entries with required true hold back the switch; publish all of them.
        - `purpose` 'dkim' | 'dkim_spare' | 'return_path' | 'ses_return_path', required: dkim is the DKIM selector the domain switches to; dkim_spare lets Sequenzy change the key later without a DNS change; return_path and ses_return_path are the two return paths (rp and rp2 by default).
        - `type` 'CNAME', required
        - `name` string, required
        - `value` string, required
        - `required` boolean, required: True for dkim and return_path.
        - `status` 'pending' | 'verified' | 'misconfigured', required
        - `diagnostic` object: Why the record is not verified yet, when known.
      - `completedAt` string, date-time, nullable, required: When the domain switched to the new records. Set when completed.
      - `replacedRecords` object[], nullable, required: Your current records that the upgrade replaces, which you can optionally remove about a week after the switch (the DKIM TXT at sequenzy._domainkey and the current return path records). Set while available or in_progress, otherwise null. Keep them until then.
        - `type` 'TXT' | 'MX' | 'CNAME', required
        - `name` string, required
        - `removed` boolean, required: True once the record is gone from public DNS.
      - `oldRecords` object[], nullable, required: Records the domain no longer uses (the DKIM TXT at sequenzy._domainkey and the previous return path records). Set when completed. Keep them until deleteOldRecordsAfter so receivers can still check signatures and return bounces for email sent before the switch. removed turns true once a record is gone from public DNS (checked on each verification).
        - `type` 'TXT' | 'MX' | 'CNAME', required
        - `name` string, required
        - `removed` boolean, required: True once the record is gone from public DNS.
      - `deleteOldRecordsAfter` string, date-time, nullable, required: The old records can be deleted from this time, 8 days after the switch; deleting them is optional. Set when completed.
    - `lastVerifiedAt` string, date-time, nullable
    - `nextVerificationAt` string, date-time, nullable
    - `createdAt` string, date-time

## Other responses

- `400`: The domain can't be upgraded (not offered to this domain yet, in which case the error is "DNS upgrades are not available for this domain.", not verified, verification paused, already on the current records, an older record set that can't be upgraded in place, or an older SES-only domain without a working DMARC record, in which case the error is "Add a DMARC record for this domain before upgrading its DNS records."), or mailFromPrefix is invalid or already in use (it already has DNS records, or is the current return path or tracking label)
- `401`: Unauthorized
- `403`: The API key lacks websites:write
- `404`: Domain not found
- `409`: An upgrade is already in progress, or the domain changed during the request. Read the website and retry.
- `422`: mailFromPrefix is not a string of 1 to 63 characters
- `500`: The new DNS records could not be prepared. Nothing changed; try again in a few minutes.

## Changes

- **2026-10-17** `42ac3429b60e`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/sequenzy/apis/sequenzy-api/changes/websites/:domain/dns-upgrade/post.md)

---

[API](https://skmtc.dev/sequenzy/apis/sequenzy-api.md) - [All operations](https://skmtc.dev/sequenzy/apis/sequenzy-api/llms.txt) - [OpenAPI document](https://skmtc.dev/sequenzy/apis/sequenzy-api/revisions/8156dc12d8b4?raw)
