Domains
More ways to use this page
Add a sending domain
POST/v1/
TypeScript account
Python account
Key ak_… an account key
Creates the domain with its own DKIM key and answers the two DNS records to add: a CNAME for the return path and a TXT record for the DKIM key. The domain may send once both records are seen, which Sendora checks on its own and on request. Domains belong to the account: every server sends from them, and an account key manages them; a server key cannot.
Request body
domainstringrequiredThe domain mail is sent from, such as example.se; lower-cased and IDNA-encoded.
{
"domain": "example.se"
}Responses
201A sending domain and the two records it needs.
domainIdstring (uuid)requireddomainstringrequiredverifiedbooleanrequiredTrue while both records count as found; only then may mail go out. A lookup that fails at the resolver never changes it, and a record found missing on a verified domain starts a 24-hour warning (failingSince) through which the domain stays verified.
createdAtstring (date-time)requiredlastCheckedAtstring (date-time) or nullrequiredWhen the records were last looked up.
failingSincestring (date-time) or nullrequiredWhen a check first found a record of this verified domain missing or wrong. Mail keeps going out, the records are looked up hourly, and the first check 24 hours after this that still misses one ends the verification. Null unless the domain is verified and in that warning; verified and each record tell the rest.
returnPathobjectrequiredThe return-path record, which also satisfies SPF.
type"CNAME"requiredhoststringrequiredThe name to create the record under.
valuestringrequiredThe value the record must hold.
verifiedbooleanrequiredverifiedAtstring (date-time) or nullrequired
dkimobjectrequiredThe DKIM public key record.
type"TXT"requiredhoststringrequiredThe name to create the record under.
valuestringrequiredThe value the record must hold.
verifiedbooleanrequiredverifiedAtstring (date-time) or nullrequired
Example (22 lines)
{
"domainId": "0d7f6a1e-4c0b-4b7e-9d3c-2a1f5e8b9c01",
"domain": "example.se",
"verified": false,
"createdAt": "2026-09-15T12:00:00.000Z",
"lastCheckedAt": null,
"failingSince": null,
"returnPath": {
"type": "CNAME",
"host": "sendora-bounces.example.se",
"value": "bounces.sendora.se",
"verified": false,
"verifiedAt": null
},
"dkim": {
"type": "TXT",
"host": "s1._domainkey.example.se",
"value": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...",
"verified": false,
"verifiedAt": null
}
}Errors
Every error answers error, the code, and message, a sentence for a person. A code that adds fields is shown in full below the table.
| Code | Status | Meaning |
|---|---|---|
invalid_ | 400 | The body, the query or a header does not match what the route takes. |
unauthorized | 401 | The key is missing, malformed or revoked. |
wrong_ | 403 | The key is of the other kind: a server key (sk_) where an account key (ak_) is needed, or the reverse. The message names the kind the operation takes. |
domain_ | 409 | The account already has that domain. |
invalid_request
issuesarray of objectOne entry per invalid field; absent when a header is wrong.
pathstringrequiredThe field, dotted, such as to.0.email; empty when the whole body is wrong.
messagestringrequired
Example
{
"error": "invalid_request",
"message": "The request is invalid: to.0: Invalid email address",
"issues": [
{
"path": "to.0",
"message": "Invalid email address"
}
]
}domain_exists
domainIdstring (uuid)requiredThe id of the domain the account already has.
Example
{
"error": "domain_exists",
"message": "Your account already has that domain.",
"domainId": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
}