Skip to content
Esc
  • OverviewGuidesWhat exists today, and where to start.
  • QuickstartGuidesKey, domain, first send — in that order.
  • AuthenticationGuidesBearer keys, the mandatory User-Agent, and what each refusal means.
  • ErrorsGuidesThe whole vocabulary, with the status each name carries.
  • IdempotencyGuidesRetry a send without sending it twice.
  • PaginationGuidesCursors are item IDs, not page numbers.
  • Rate limitsGuidesTen a second per team, and the headers that tell you where you are.
  • EventsGuidesEvery event a webhook can carry, with one real payload each.
  • DomainsGuidesThe records, where they go at each registrar, and what the page does while you wait.
  • TrackingGuidesOpens and clicks: one record, two toggles, and what an open really means.
  • ReceivingGuidesInbound mail, and the Inbox: a webhook fires, you read it, you answer it.
  • InboxGuidesChannels, personal mailboxes and seats: who sees what, and where a reply goes.
  • Node SDKGuidesThe rasket package: typed from the API's own document, retries only what is safe.
  • Python SDKGuidesThe rasket package on PyPI: the Node client's methods, in snake_case, over httpx.
  • MCP serverGuidesConnect Claude, ChatGPT or any MCP client: your scopes, no key.
  • AI assistGuidesSubject lines, drafts and diagnosis — in the dashboard and over the API, off until you allow it.
  • AgentsGuidesLet an AI agent set Rasket up: the skill, the rules file, MCP, and the recipe they share.
  • OAuthGuidesLet another app act for a team: register, authorize with PKCE, exchange, refresh.
  • Single sign-onGuidesOIDC login for your team, a domain proved by DNS, enforcement and break-glass.
  • IntegrationsGuidesVercel, Netlify and Cloudflare, plus Zapier and n8n for workflows without code.
  • SMTPGuidesSend from anything that speaks SMTP: settings, setup guides, limits and replies.
  • ZapierGuidesSend email, add contacts and react to email events from a Zap, with no code.
  • n8nGuidesThe Rasket node and trigger for n8n workflows: install, connect, every operation.
  • VercelGuidesAdd Rasket on Vercel: a Sending key in each project as RASKET_API_KEY, no copying.
  • EmailsAPI referenceSend, batch, retrieve, list, reschedule, cancel, attachments.
  • DomainsAPI referenceAdd a domain, publish its records, verify it.
  • API keysAPI referenceCreate, list, rename and revoke credentials.
  • WebhooksAPI referencePayloads, signature verification, retries and replay.
  • SuppressionsAPI referenceAddresses we will not send to, and why.
  • LogsAPI referenceEvery request made with this team's credentials.
  • MetricsAPI referenceDelivery, bounce, complaint and engagement counts.
  • TemplatesAPI referenceVersioned email content with typed variables, addressed by ID or alias.
  • ContactsAPI referenceYour audience: contacts, their typed properties, segments and topic choices.
  • SegmentsAPI referenceAudiences defined by a filter, by hand, or both.
  • TopicsAPI referenceWhat contacts subscribe to, and the preference page's list.
  • CampaignsAPI referenceCampaigns, at /broadcasts: one message to a segment, from draft to results.
  • ImportsAPI referenceCSV uploads: column mapping, conflicts and counts.
  • AutomationsAPI referenceWorkflows that run per contact: the graph, its versions, and every run.
  • Custom eventsAPI referenceThe names your product fires, and what starts a workflow.
  • ReceivingAPI referenceMail sent to you: the message, its attachments, its raw source.
  • OAuthAPI referenceClient registration, the token endpoint, and the grants a team has given.
  • TeamAPI referenceThe team a credential belongs to: its plan, sender identity, AI flag and members.
  • BillingAPI referencePlan, usage, invoices and add-ons, and the hosted pages where a customer pays.
  • AI helpersAPI referenceSubject lines, a first draft, and why an email did what it did.

API referenceDomains

Domains

A domain is the identity your mail is signed with. Add it, publish its DNS records, verify it, and it can send.

The records

POST /domains answers with a records array. Publish the entries for what you use, exactly as given, at your DNS provider. Names are relative to your DNS zone: the table shows them for a domain at the root of its zone, and for send.acme.example each one carries .send — rasket._domainkey.send, send.send, links.send.

The DNS records a domain needs
RecordTypeNameValue
DKIMTXTrasket._domainkeyA bare p=… value. The key is 2048-bit, so the value is published as two quoted strings — most providers do that for you when you paste it.
MAIL FROMCNAMEsend<code>.rasket.net for the domain's region — us1.rasket.net for us-east-1. This is what makes bounces come back to us instead of to your own mail server, and what your SPF check passes on. Publish it DNS only, never proxied. Some domains are given an MX and a TXT at send instead; publish whichever records returns — both work.
ReceivingMX@Our inbound mail host for your region, priority 10, at receiving_host (@ by default). Only in us-east-1 and eu-west-1, and only needed once you turn receiving on.
TrackingCNAMElinkslinks1.rasket-dns.com. Only needed if you turn on open or click tracking, and never proxied.

The first two are what sending needs. The Receiving and Tracking rows are in the array from the start, whatever the toggles say, but only have to verify once you turn receiving, or open or click tracking, on — a domain verifies for sending without them. The tracking guide covers it. No CAA record is required for any of them.

Send from a subdomain — send.acme.example rather than acme.example. A subdomain keeps your transactional reputation separate from whatever else your root domain does, and it means these records never collide with the ones your mail provider already publishes.

Publishing them for you

POST /domains/{domain_id}/autoconfigure writes the records through your DNS provider. Cloudflare is the only provider we can configure today. It takes an API token created from the Zone → DNS → Edit template and scoped to this domain's zone; a token covering more than one zone is refused, and a global API key is refused outright.

  • Only the records for capabilities you have enabled are published. Turn tracking on first if you want its record written too.
  • We never delete a record and never overwrite one we did not create. Anything already sitting at one of our names comes back in conflicts for you to resolve.
  • The token is deleted as soon as the records are written unless you pass keep_token. DELETE /domains/{domain_id}/autoconfigure/credential removes a kept one — that stops us using it, not anyone else, so revoke it at Cloudflare too.

Regions

region selects where your mail is signed and relayed from. It is a deliverability and latency choice, not a data residency one: it does not decide where your data is stored. A domain's region is fixed once it is created.

Verification

  • POST /domains/{domain_id}/verify checks now and returns the domain with each record's status. A second call within 15 seconds returns the current state without checking again.
  • We also re-check every domain on a schedule, so a record you publish will verify on its own without you polling.
  • A record that verified and later stops resolving is reported as drifted rather than silently ignored.
  • A record's status is about DNS only. A Receiving MX can read verified while capabilities.receiving is disabled: the record is in place, and receiving is off until you turn it on.

Claiming a domain someone else verified

A domain can be verified on one team at a time, so adding one another team already holds answers 409 resource_locked. POST /domains/claim is how you take it over, and the only way: prove you control the name in DNS.

The claim comes back with a TXT record to publish at the root of the domain. Its value always starts rasket-domain-verification=:

TXT  @  rasket-domain-verification=8Kx2mQ7vN4pR9wL1sT6yU3bC5dF0gH8jK2nM4qP7rS9
  • When the record resolves, the domain moves to your team and the previous owner's copy is switched off. There is no other route — no support ticket and no override.
  • The transfer waits if the current owner verified the domain in the last 72 hours, sent from it in the last 24 hours, or has mail scheduled from it. blocked_reason says which, and we re-check every hour.
  • A claim expires after 7 days. The domain arrives with fresh DKIM records of its own — the previous owner's values are never reusable — so publish those and verify as normal.

TLS

tls is opportunistic by default: we use TLS to the receiving server when it offers it. Setting it to enforced changes what happens when it does not — messages to mail servers that do not support TLS will not be sent and will appear as email.failed. That is the trade: no plaintext delivery, at the cost of some mail not arriving.

DMARC

DMARC is not required to verify a domain and we do not publish one for you. It is worth adding, starting at p=none and tightening once the reports look right:

TXT  _dmarc  v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com

If your domain already publishes _dmarc with p=reject and the MAIL FROM records above are not yet verified, mail you send through us may be rejected outright until alignment is in place. Publish the records first, verify, then send.

Endpoints

Add a domain

POST /domains

Register a sending domain and get the DNS records to publish.

Body

  • namestringRequired

    The domain to send from. A subdomain such as send.acme.example is recommended.

  • regionstring

    us-east-1, eu-west-1, sa-east-1 or ap-northeast-1. Defaults to us-east-1. Receiving is available in us-east-1 and eu-west-1 only.

8 more fields (open_tracking, click_tracking, tracking_subdomain, custom_return_path, receiving_host, confirm_replace_mx, tls, capabilities)
  • open_trackingboolean

    Rewrite the body to add a tracking pixel. Off by default.

  • click_trackingboolean

    Rewrite links so clicks are recorded. Off by default.

  • tracking_subdomainstring

    The label tracking links are served from. Defaults to links.

  • custom_return_pathstring

    The label the sending records are published at. Leave it out and we pick the first label no other email service uses at your domain: rasket, then rasketmail, rk, rasket1, rasket2. A label that already holds another service's records answers 422 invalid_parameter with details.reason return_path_in_use and a free details.suggestion.

  • receiving_hoststring

    Where the domain receives mail: @ by default (anything@<name>), or a label such as inbound for anything@inbound.<name>. An MX at @ takes the domain's mail from its current mailbox provider.

  • confirm_replace_mxboolean

    Only with receiving enabled. If the receiving name's MX already delivers to another mailbox provider, the request is refused with 409 receiving_mx_in_use unless this is true. Use a receiving_host label instead to leave that mail where it is.

  • tlsstring

    opportunistic (the default) or enforced. Enforced refuses to deliver without TLS.

  • capabilitiesobject

    { sending, receiving }, each enabled or disabled. Defaults to sending on, receiving off; at least one must be on. Receiving in a region without it is 400 validation_error.

Request

curl -X POST "https://api.rasket.com/domains" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "send.acme.example",
  "region": "eu-west-1"
}'

Response 201

{
  "id": "d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34",
  "name": "send.acme.example",
  "created_at": "2026-09-09T09:02:44.301Z",
  "status": "not_started",
  "region": "eu-west-1",
  "open_tracking": false,
  "click_tracking": false,
  "tracking_subdomain": "links",
  "receiving_host": "@",
  "custom_return_path": "rasket",
  "capabilities": {
    "sending": "enabled",
    "receiving": "disabled"
  },
  "managed": false,
  "records": [
    {
      "record": "DKIM",
      "name": "rasket._domainkey.send",
      "type": "TXT",
      "ttl": "Auto",
      "status": "not_started",
      "value": "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA…"
    },
    {
      "record": "SPF",
      "name": "rasket.send",
      "type": "CNAME",
      "ttl": "Auto",
      "status": "not_started",
      "value": "eu1.rasket.net"
    },
    {
      "record": "Tracking",
      "name": "links.send",
      "type": "CNAME",
      "ttl": "Auto",
      "status": "not_started",
      "value": "links1.rasket-dns.com"
    }
  ]
}
  • Publish the records for each capability you turned on (DKIM and the SPF CNAME for sending), then call verify. Nothing sends until the domain is verified.
  • records lists every group whatever the toggles say — Tracking, and in us-east-1 and eu-west-1 a Receiving MX at receiving_host — so you can see what turning one on would need. Record names are relative to your DNS zone: for send.acme.example in acme.example, the return-path CNAME sits at rasket.send.
  • region is where your mail is sent from, not where your data is stored.
  • A name another team has already verified answers 409 resource_locked.
  • custom_return_path in the response is the label we chose when you named none.

List domains

GET /domains

Every domain on the team.

Query parameters

  • limitinteger

    How many items to return, 1–100. Defaults to 20.

  • afterstring

    Return the page that follows this item ID. Mutually exclusive with before.

  • beforestring

    Return the page that precedes this item ID. Mutually exclusive with after.

  • searchstring

    Text in the domain name. Case-insensitive, 1–200 characters.

  • statusstring

    Only domains in these states, comma-separated: not_started, pending, verified, partially_verified, partially_failed, failed.

Request

curl -X GET "https://api.rasket.com/domains" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "list",
  "has_more": false,
  "data": [
    {
      "id": "d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34",
      "name": "send.acme.example",
      "status": "verified",
      "created_at": "2026-09-09T09:02:44.301Z",
      "region": "eu-west-1",
      "open_tracking": false,
      "click_tracking": false,
      "capabilities": {
        "sending": "enabled",
        "receiving": "disabled"
      },
      "managed": false
    }
  ]
}
  • The list omits records. Retrieve one domain to see the current state of each record.

Retrieve a domain

GET /domains/{domain_id}

One domain, with the live status of every record.

Path parameters

  • domain_idstringRequired

    The domain's ID.

Request

curl -X GET "https://api.rasket.com/domains/d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "domain",
  "id": "d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34",
  "name": "send.acme.example",
  "status": "verified",
  "created_at": "2026-09-09T09:02:44.301Z",
  "region": "eu-west-1",
  "open_tracking": false,
  "click_tracking": false,
  "tracking_subdomain": "links",
  "receiving_host": "@",
  "custom_return_path": "rasket",
  "capabilities": {
    "sending": "enabled",
    "receiving": "disabled"
  },
  "managed": false,
  "records": [
    {
      "record": "DKIM",
      "name": "rasket._domainkey.send",
      "type": "TXT",
      "ttl": "Auto",
      "status": "not_started",
      "value": "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA…"
    },
    {
      "record": "SPF",
      "name": "rasket.send",
      "type": "CNAME",
      "ttl": "Auto",
      "status": "not_started",
      "value": "eu1.rasket.net"
    },
    {
      "record": "Tracking",
      "name": "links.send",
      "type": "CNAME",
      "ttl": "Auto",
      "status": "not_started",
      "value": "links1.rasket-dns.com"
    }
  ]
}

Update a domain

PATCH /domains/{domain_id}

Change tracking, TLS, the tracking subdomain, the return path or where the domain receives mail.

Path parameters

  • domain_idstringRequired

    The domain's ID.

Body

  • open_trackingboolean

    Turn the tracking pixel on or off.

  • click_trackingboolean

    Turn link rewriting on or off.

7 more fields (tls, tracking_subdomain, receiving_host, custom_return_path, confirm_replace_mx, capabilities, region)
  • tlsstring

    opportunistic or enforced.

  • tracking_subdomainstring

    Changing this publishes a new record and re-verifies tracking.

  • receiving_hoststring

    A label or @. Changing it moves the Receiving MX to the new name and re-verifies receiving; mail is accepted at the new address once that MX verifies.

  • custom_return_pathstring

    Changing it moves the sending records to the new label: publish them there and keep the old ones until the new ones verify. The domain keeps sending meanwhile. A label that already holds another service's records answers 422 invalid_parameter.

  • confirm_replace_mxboolean

    Turning receiving on, or moving receiving_host, at a name whose MX already delivers to another mailbox provider is 409 receiving_mx_in_use unless this is true.

  • capabilitiesobject

    { sending, receiving }, each enabled or disabled; name one or both. At least one must stay on.

  • regionstring

    Fixed at creation. Sending it is 422 invalid_parameter.

Request

curl -X PATCH "https://api.rasket.com/domains/d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0" \
  -H "Content-Type: application/json" \
  -d '{
  "click_tracking": true
}'

Response 200

{
  "object": "domain",
  "id": "d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34"
}
  • The domain's name and region are fixed at creation. Delete and re-add to change either.

Verify a domain

POST /domains/{domain_id}/verify

Check the published records now and get the domain back with each record's status.

Path parameters

  • domain_idstringRequired

    The domain's ID.

Request

curl -X POST "https://api.rasket.com/domains/d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34/verify" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "domain",
  "id": "d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34",
  "name": "send.acme.example",
  "status": "verified",
  "created_at": "2026-09-09T09:02:44.301Z",
  "region": "eu-west-1",
  "open_tracking": false,
  "click_tracking": false,
  "tracking_subdomain": "links",
  "receiving_host": "@",
  "custom_return_path": "rasket",
  "capabilities": {
    "sending": "enabled",
    "receiving": "disabled"
  },
  "managed": false,
  "records": [
    {
      "record": "DKIM",
      "name": "rasket._domainkey.send",
      "type": "TXT",
      "ttl": "Auto",
      "status": "not_started",
      "value": "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA…"
    },
    {
      "record": "SPF",
      "name": "rasket.send",
      "type": "CNAME",
      "ttl": "Auto",
      "status": "not_started",
      "value": "eu1.rasket.net"
    },
    {
      "record": "Tracking",
      "name": "links.send",
      "type": "CNAME",
      "ttl": "Auto",
      "status": "not_started",
      "value": "links1.rasket-dns.com"
    }
  ]
}
  • The check runs immediately and the call waits up to 10 seconds for it.
  • A second call within 15 seconds returns the current state without checking again. So does a call while a check is already running, or one whose check does not finish in time; the scheduled check then finishes it.
  • We also re-check every domain on a schedule, so a published record verifies on its own within the hour.
  • Verification reads DNS. A record published seconds ago may still be cached as absent by the resolver.

Delete a domain

DELETE /domains/{domain_id}

Delete a domain.

Path parameters

  • domain_idstringRequired

    The domain's ID.

Request

curl -X DELETE "https://api.rasket.com/domains/d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "domain",
  "id": "d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34",
  "deleted": true
}
  • Emails already sent from the domain are kept; scheduled ones that have not gone out will fail.
  • Any sending_access key restricted to this domain stops being able to send.

Regenerate the DKIM key

POST /domains/{domain_id}/dkim/regenerate

Mint a new signing key, optionally a shorter one, and republish the DKIM record.

Path parameters

  • domain_idstringRequired

    The domain's ID.

Body

  • key_bitsintegerRequired

    2048 to rotate at the default size, or 1024 for a DNS panel that will not accept the ~392-character TXT value a 2048-bit key produces.

Request

curl -X POST "https://api.rasket.com/domains/d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34/dkim/regenerate" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0" \
  -H "Content-Type: application/json" \
  -d '{
  "key_bits": 1024
}'

Response 200

{
  "object": "domain",
  "id": "d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34",
  "name": "send.acme.example",
  "status": "verified",
  "created_at": "2026-09-09T09:02:44.301Z",
  "region": "eu-west-1",
  "open_tracking": false,
  "click_tracking": false,
  "tracking_subdomain": "links",
  "receiving_host": "@",
  "custom_return_path": "rasket",
  "capabilities": {
    "sending": "enabled",
    "receiving": "disabled"
  },
  "managed": false,
  "records": [
    {
      "record": "DKIM",
      "name": "rasket._domainkey.send",
      "type": "TXT",
      "ttl": "Auto",
      "status": "not_started",
      "value": "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA…"
    },
    {
      "record": "SPF",
      "name": "rasket.send",
      "type": "CNAME",
      "ttl": "Auto",
      "status": "not_started",
      "value": "eu1.rasket.net"
    },
    {
      "record": "Tracking",
      "name": "links.send",
      "type": "CNAME",
      "ttl": "Auto",
      "status": "not_started",
      "value": "links1.rasket-dns.com"
    }
  ]
}
  • Publish the DKIM record's new value before your next send. The old key stops signing immediately, and the domain is not verified for sending again until we see the new record.
  • One call per minute per domain. Verifying the domain within that minute also counts.

Claim a domain

POST /domains/claim

Take over a domain another team has already verified, by proving you control it.

Body

  • namestringRequired

    The domain to claim. Adding it with POST /domains answered 409 for this name.

8 more fields (region, custom_return_path, tracking_subdomain, receiving_host, open_tracking, click_tracking, tls, capabilities)
  • regionstring

    Where your mail will be sent from once the claim completes. It does not have to match the current owner's.

  • custom_return_pathstring

    The return-path label, as on POST /domains. Leave it out and we pick a free one.

  • tracking_subdomainstring

    As on POST /domains; applies to the domain once the claim completes.

  • receiving_hoststring

    As on POST /domains; applies to the domain once the claim completes.

  • open_trackingboolean

    As on POST /domains; applies to the domain once the claim completes.

  • click_trackingboolean

    As on POST /domains; applies to the domain once the claim completes.

  • tlsstring

    As on POST /domains; applies to the domain once the claim completes.

  • capabilitiesobject

    As on POST /domains; applies to the domain once the claim completes.

Request

curl -X POST "https://api.rasket.com/domains/claim" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "example.com",
  "region": "us-east-1"
}'

Response 201

{
  "object": "domain_claim",
  "id": "c1f2b3a4-1176-453e-8fc1-35364d380206",
  "name": "example.com",
  "status": "pending",
  "domain_id": "d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34",
  "region": "us-east-1",
  "record": {
    "record": "Claim",
    "name": "example.com",
    "type": "TXT",
    "ttl": "Auto",
    "status": "pending",
    "value": "rasket-domain-verification=8Kx2mQ7vN4pR9wL1sT6yU3bC5dF0gH8jK2nM4qP7rS9"
  },
  "blocked_reason": null,
  "failure_reason": null,
  "created_at": "2026-09-09T00:00:00.000Z",
  "expires_at": "2026-09-16T00:00:00.000Z"
}
  • Publish the returned TXT record at the root of the domain. We check it on a schedule; when it resolves, the domain moves to your team and the previous owner's copy is switched off.
  • The transfer waits if the current owner verified the domain in the last 72 hours, sent from it in the last 24 hours, or has scheduled mail from it. blocked_reason says which, and we re-check every hour.
  • A claim expires after 7 days. Calling this again while a claim is open returns that claim unchanged with 200 rather than starting a second one.
  • The domain arrives with new DKIM records of its own: the previous owner's values are never reusable. Publish them and verify the domain as normal.

Retrieve a domain claim

GET /domains/{domain_id}/claim

The latest claim for a domain, and the record that proves ownership.

Path parameters

  • domain_idstringRequired

    The placeholder domain the claim created — not the claim's own ID.

Request

curl -X GET "https://api.rasket.com/domains/d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34/claim" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "domain_claim",
  "id": "c1f2b3a4-1176-453e-8fc1-35364d380206",
  "name": "example.com",
  "status": "pending",
  "domain_id": "d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34",
  "region": "us-east-1",
  "record": {
    "record": "Claim",
    "name": "example.com",
    "type": "TXT",
    "ttl": "Auto",
    "status": "pending",
    "value": "rasket-domain-verification=8Kx2mQ7vN4pR9wL1sT6yU3bC5dF0gH8jK2nM4qP7rS9"
  },
  "blocked_reason": null,
  "failure_reason": null,
  "created_at": "2026-09-09T00:00:00.000Z",
  "expires_at": "2026-09-16T00:00:00.000Z"
}
  • Poll this to follow a claim: pending while we look for the record, blocked with a reason while the current owner is still active, completed once the domain is yours.

Verify a domain claim

POST /domains/{domain_id}/claim/verify

Ask for the ownership record to be checked sooner.

Path parameters

  • domain_idstringRequired

    The placeholder domain the claim created — not the claim's own ID.

Request

curl -X POST "https://api.rasket.com/domains/d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34/claim/verify" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "domain_claim",
  "id": "c1f2b3a4-1176-453e-8fc1-35364d380206",
  "name": "example.com",
  "status": "pending",
  "domain_id": "d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34",
  "region": "us-east-1",
  "record": {
    "record": "Claim",
    "name": "example.com",
    "type": "TXT",
    "ttl": "Auto",
    "status": "pending",
    "value": "rasket-domain-verification=8Kx2mQ7vN4pR9wL1sT6yU3bC5dF0gH8jK2nM4qP7rS9"
  },
  "blocked_reason": null,
  "failure_reason": null,
  "created_at": "2026-09-09T00:00:00.000Z",
  "expires_at": "2026-09-16T00:00:00.000Z"
}
  • The claim stays pending while the check runs; read the claim back to see the result.
  • One call per minute per domain. Verifying the domain within that minute also counts.

Auto configure DNS

POST /domains/{domain_id}/autoconfigure

Publish this domain's records through the customer's DNS provider.

Path parameters

  • domain_idstringRequired

    The domain's ID.

Body

  • providerstringRequired

    cloudflare. The only provider we can configure today.

  • tokenstringRequired

    A Cloudflare API token created from the Zone → DNS → Edit template, scoped to this domain's zone and no other. Global API keys are refused.

  • keep_tokenboolean

    true to keep the token so you can re-apply records later. It is deleted as soon as the records are written otherwise.

Request

curl -X POST "https://api.rasket.com/domains/d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34/autoconfigure" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0" \
  -H "Content-Type: application/json" \
  -d '{
  "provider": "cloudflare",
  "token": "your-cloudflare-api-token",
  "keep_token": false
}'

Response 200

{
  "object": "domain",
  "id": "d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34",
  "created": ["DKIM:TXT:rasket._domainkey.send", "SPF:CNAME:rasket.send"],
  "updated": [],
  "conflicts": [],
  "credential_kept": false
}
  • Only records for capabilities you have enabled are published. Turning on receiving or tracking first, then running this, is what publishes those records.
  • We never delete a record, and never overwrite one we did not create. Anything already sitting at one of our names comes back in conflicts for you to resolve.
  • The token is encrypted at rest and only ever used for this domain's zone. Revoke it at Cloudflare when you are done — deleting it here stops us using it, not anyone else.
  • One call per minute per domain. Verifying the domain within that minute also counts.

Delete the stored DNS token

DELETE /domains/{domain_id}/autoconfigure/credential

Remove the provider credential kept for this domain.

Path parameters

  • domain_idstringRequired

    The domain's ID.

Request

curl -X DELETE "https://api.rasket.com/domains/d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34/autoconfigure/credential" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "domain",
  "id": "d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34",
  "deleted": true
}
  • Records already published are untouched; only our copy of the token goes away.
  • Answers 404 when no token is stored for this domain.

Compare a domain's records with DNS

GET /domains/{domain_id}/records

Each record to publish, beside what DNS answered for it on the last check.

Path parameters

  • domain_idstringRequired

    The domain's ID.

Request

curl -X GET "https://api.rasket.com/domains/d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34/records" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "domain_records",
  "domain_id": "d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34",
  "sending_verified": false,
  "tracking_verified": false,
  "receiving_verified": false,
  "receiving_host": "@",
  "receiving_address": null,
  "records": [
    {
      "record": "DKIM",
      "name": "rasket._domainkey.send",
      "type": "TXT",
      "ttl": "Auto",
      "value": "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA…",
      "status": "failed",
      "observed": [],
      "reason": "not_found",
      "last_checked_at": "2026-09-09T09:30:00.000Z"
    }
  ]
}
  • A record with nothing in observed was not found at its name. One whose observed value differs from value was published wrong.
  • This reads the last check. Ask for a new one with POST /domains/{domain_id}/verify.

Read the brand certificate

GET /domains/{domain_id}/logo/certificate

See where this domain's brand certificate has got to.

Path parameters

  • domain_idstringRequired

    The domain's ID.

Request

curl -X GET "https://api.rasket.com/domains/d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34/logo/certificate" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "domain_brand_certificate",
  "domain_id": "d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34",
  "state": "active",
  "csr_pem": "-----BEGIN CERTIFICATE REQUEST-----\nMIICrTCC…\n-----END CERTIFICATE REQUEST-----\n",
  "subject": {
    "common_name": "mail.example.com",
    "organization": "Acme Corporation",
    "organizational_unit": null,
    "locality": "Portland",
    "state": "Oregon",
    "country": "US"
  },
  "requested_at": "2026-09-09T09:30:00.000Z",
  "url": "https://share.example.com/bimi/d91b8a2e-2f3d-4f2a-9a0b-3c1e5f7a9b21/5f2a9b21d91b8a2e2f3d4f2a9a0b3c1e5f7a9b21d91b8a2e2f3d4f2a9a0b3c1e.pem",
  "bytes": 6144,
  "sha256": "5f2a9b21d91b8a2e2f3d4f2a9a0b3c1e5f7a9b21d91b8a2e2f3d4f2a9a0b3c1e",
  "issuer": "DigiCert Inc",
  "expires_at": "2027-09-09T09:30:00.000Z",
  "installed_at": "2026-09-16T11:02:00.000Z",
  "published": true,
  "reason": null
}
  • state is none, awaiting_certificate, active, logo_changed or expired. Only active is published.
  • logo_changed means the logo was replaced after the certificate was issued. Nothing is thrown away: put the previous logo back, or ask your authority to re-issue for the new one.
  • The private key never leaves us and is in no response.

Create a certificate signing request

POST /domains/{domain_id}/logo/certificate

Generate the request to take to a certificate authority.

Path parameters

  • domain_idstringRequired

    The domain's ID.

Body

  • common_namestringRequired

    The domain the logo is published for, such as mail.example.com.

  • organizationstringRequired

    Your organisation's legal name, exactly as registered. The authority checks it against your documents.

  • organizational_unitstring

    An optional division within the organisation.

  • localitystringRequired

    City or town.

  • statestringRequired

    State, province or region.

  • countrystringRequired

    Two-letter country code, such as US.

Request

curl -X POST "https://api.rasket.com/domains/d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34/logo/certificate" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0" \
  -H "Content-Type: application/json" \
  -d '{
  "common_name": "mail.example.com",
  "organization": "Acme Corporation",
  "locality": "Portland",
  "state": "Oregon",
  "country": "US"
}'

Response 200

{
  "object": "domain_brand_certificate",
  "domain_id": "d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34",
  "state": "awaiting_certificate",
  "csr_pem": "-----BEGIN CERTIFICATE REQUEST-----\nMIICrTCC…\n-----END CERTIFICATE REQUEST-----\n",
  "subject": {
    "common_name": "mail.example.com",
    "organization": "Acme Corporation",
    "organizational_unit": null,
    "locality": "Portland",
    "state": "Oregon",
    "country": "US"
  },
  "requested_at": "2026-09-09T09:30:00.000Z",
  "url": null,
  "bytes": null,
  "sha256": null,
  "issuer": null,
  "expires_at": null,
  "installed_at": null,
  "published": false,
  "reason": "Take the request below to a certificate authority. When they issue your certificate, paste it here."
}
  • This needs a paid plan, and the domain needs a brand logo: a certificate is issued for the logo it will be published with.
  • You buy the certificate from the authority. We charge nothing for it and never see the transaction.
  • Calling this again while a request is open returns the same request, because that one may already be with the authority. Delete the certificate first to start over.

Install the issued certificate

PATCH /domains/{domain_id}/logo/certificate

Store the chain the authority issued and publish it as the record's `a=` tag.

Path parameters

  • domain_idstringRequired

    The domain's ID.

Body

  • pemstringRequired

    The certificate chain, PEM-encoded: your certificate first, then each one that issued the one above it. Never a private key.

Request

curl -X PATCH "https://api.rasket.com/domains/d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34/logo/certificate" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0" \
  -H "Content-Type: application/json" \
  -d '{
  "pem": "-----BEGIN CERTIFICATE-----\nMIIFyzCC…\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEwTCC…\n-----END CERTIFICATE-----\n"
}'

Response 200

{
  "object": "domain_brand_certificate",
  "domain_id": "d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34",
  "state": "active",
  "csr_pem": "-----BEGIN CERTIFICATE REQUEST-----\nMIICrTCC…\n-----END CERTIFICATE REQUEST-----\n",
  "subject": {
    "common_name": "mail.example.com",
    "organization": "Acme Corporation",
    "organizational_unit": null,
    "locality": "Portland",
    "state": "Oregon",
    "country": "US"
  },
  "requested_at": "2026-09-09T09:30:00.000Z",
  "url": "https://share.example.com/bimi/d91b8a2e-2f3d-4f2a-9a0b-3c1e5f7a9b21/5f2a9b21d91b8a2e2f3d4f2a9a0b3c1e5f7a9b21d91b8a2e2f3d4f2a9a0b3c1e.pem",
  "bytes": 6144,
  "sha256": "5f2a9b21d91b8a2e2f3d4f2a9a0b3c1e5f7a9b21d91b8a2e2f3d4f2a9a0b3c1e",
  "issuer": "DigiCert Inc",
  "expires_at": "2027-09-09T09:30:00.000Z",
  "installed_at": "2026-09-16T11:02:00.000Z",
  "published": true,
  "reason": null
}
  • The chain is accepted only if its first certificate carries the public key of this domain's request, it is inside its validity window, and each certificate is signed by the one after it.
  • Publish the default._bimi record again afterwards: its value has changed.

Remove the brand certificate

DELETE /domains/{domain_id}/logo/certificate

Delete the request and the certificate, and go back to the self-asserted record.

Path parameters

  • domain_idstringRequired

    The domain's ID.

Request

curl -X DELETE "https://api.rasket.com/domains/d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34/logo/certificate" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "domain_brand_certificate",
  "domain_id": "d91a7b60-1a5f-4a2e-9d1b-0d9f2c7a1e34",
  "deleted": true
}
  • The logo is untouched. default._bimi goes back to the value it had before the certificate.
  • A domain with no certificate answers the same way, so this is safe to call twice.