POST/api/v1/projects/{project_id}/domains
Needs scope: writeIdempotency-KeyMCP tool: add_sending_domain
operationId add_sending_domain
Add a sending domain
Adds a domain to the project, pending, with a DKIM key pair of its own
(RSA 2048; the private key is stored sealed and no answer shows it), and
records domain.created. The answer lists the DNS records to create.
Needs scope write. A domain is unique in its project.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
project_idrequired |
path | string · uuid | The project’s id |
Idempotency-Key |
header | string
1–128 characters · pattern |
A key of the client’s choosing, one per request it means to send once (a UUID will do). A repeat with the same key and the same body within 24 h creates nothing again and gets the first answer, marked Idempotent-Replayed: true. The key belongs to the API key that sent it. Only a 2xx answer is kept: after any other answer the key is free again. |
Request body
application/json · required
- AddSendingDomainRequest object
-
Who applies the records:
porkbun, ormanualfor entry by hand.- porkbun
- manual
-
domainstringrequiredThe domain of the sender addresses: a host name, a subdomain or an international name (kept in punycode).
example
news.example.com -
bounce_subdomainstringThe domain of the return path (
MAIL FROM), belowdomain; left out:bounce.<domain>.example
bounce.news.example.com -
dkim_selectorstringThe DKIM selector: labels of letters, digits and inner hyphens, at most 63 characters; left out:
pw1.example
pw1 -
ip_poolstringThe IP pool of the node’s config to send from (
GET /api/v1/serverlists them); left out:default.example
default -
tracking_hoststring | nullA host for tracking and unsubscribe links;
nullor left out: none (links use the node’sweb.public_url).example
links.example.com
Responses
201
The domain and the records it needs
| Header | Type | Description |
|---|---|---|
Idempotent-Replayed | string · enum | true when the answer is a replay of an earlier request with the same Idempotency-Key; absent otherwise. |
Location | string | The domain’s URL |
- AddedSendingDomain object · extends SendingDomain · all fields required
-
bounce_subdomainstringexample
bounce.news.example.com -
checksarray of DomainCheckOne entry per check that ran, in the canonical order; empty until the domain is first verified.
3 fields
- DomainCheck object · all fields required
-
detailstring | nullWhat was found instead of what was expected;
nullwhenok. -
namestringspf_bounce,mx_bounce,dkim,dmarc,tracking_cname,tracking_tlsorptr.example
dkim -
statusCheckStatusHow one verification check came out.
- ok
- missing
- mismatch
- warning
-
created_atstring · date-time -
dkim_public_keystringThe DKIM public key: base64 of its DER
SubjectPublicKeyInfo, thep=of the DKIM record (RSA 2048). -
dkim_selectorstringexample
pw1 -
dns_providerDnsProviderWho applies a domain’s DNS records.
- porkbun
- manual
-
domainstringIn punycode for an international name.
example
news.example.com -
idstring · uuidexample
01900000-0000-7000-8000-000000000001 -
ip_poolstringexample
default -
last_checked_atstring · date-time | nullWhen the records were last checked (RFC 3339);
nulluntil then. -
project_idstring · uuid -
required_recordsarray of RequiredRecordWhat to create in DNS, in this order.
6 fields
- RequiredRecord object · all fields required
-
contentstringThe whole value; a TXT value over 255 characters is split into strings by the DNS provider, not here.
example
v=spf1 ip4:203.0.113.10 -all -
create_only_if_absentbooleanCreate it only if the name has no record of this type, and never change one that is there (the DMARC record).
-
namestringThe owner name, without a trailing dot.
example
bounce.news.example.com -
priorityinteger · int32 | nullThe MX priority;
nullfor other types.≥ 0 · example
10 -
purposeRecordPurposeWhat a required record is for.
- spf_bounce
- mx_bounce
- dkim
- dmarc
- tracking_cname
-
typeRecordTypeThe type of a DNS record.
- txt
- mx
- cname
-
statusDomainStatusWhere a sending domain stands.
- pending
- verified
- failed
-
tracking_hoststring | nullnull: none. -
updated_atstring · date-time
409
The project has the domain, or is deleted (conflict); or a request with the same Idempotency-Key has not answered yet (idempotency_key_in_progress)
422
Invalid fields, every one in errors (validation_failed): unknown_field, required, invalid_type, invalid, unknown_ip_pool; or the node has no usable web.public_url (precondition_failed, not_configured); or the Idempotency-Key was used in the last 24 h for another request (idempotency_key_reused), or is not 1 to 128 visible ASCII characters (validation_failed, field Idempotency-Key)
429
The key is over its rate limit, api.rate_limit_per_minute requests a minute on this node (rate_limited)
| Header | Type | Description |
|---|---|---|
Retry-After | integer | Seconds until the key’s next request passes; rounded up. |
504
Postwind’s storage did not answer within its time limit (storage_timeout). A change the request makes may still take effect: check before repeating it. A repeat with the same Idempotency-Key never runs it twice: it is 409 idempotency_key_in_progress until the key’s 24 h end