Sign in to fill these examples with your own keys. Sign in Start free trial

Sending domains

Create, verify, import DKIM, refresh keys, suspend, resume, and delete domains.

A sending domain holds its DKIM, return-path, and DMARC records. Sending waits until DKIM verifies. By default DKIM is a CNAME to PostShiba, and the return-path CNAME at rp.{name} must verify too. To bring an existing key, for example when migrating from another provider, set dkim_manual and dkim_private_key and publish the TXT record yourself. A domain with an imported key can send before rp.{name} verifies. Your first domain becomes the account primary, and every outbound message is also DKIM-signed with the primary domain.

GET /api/v1/teams/:obfuscated_team_id/sending_domains

List sending domains and their DNS records.

request.sh
1curl -sS -X GET \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 https://app.postshiba.com/api/v1/teams/KjkAJW/sending_domains
response.json
1[ 2 { 3 "id": "HsVtYk", 4 "name": "mail.example.com", 5 "tenant_id": "WbLcFd", 6 "tenant": "default", 7 "dkim_status": "pending", 8 "return_path_status": "pending", 9 "dmarc_status": "pending", 10 "sending_allowed": false, 11 "dkim_selector": "ps1", 12 "dkim_manual": false, 13 "dkim_txt": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA", 14 "dkim_cname_host": "ps1._domainkey.mail.example.com", 15 "dkim_cname_target": "HsVtYk.customers.capsule.test", 16 "dmarc_host": "_dmarc.mail.example.com", 17 "dmarc_record": "v=DMARC1; p=none;", 18 "return_path_host": "rp.mail.example.com", 19 "return_path_target": "rp.capsule.test", 20 "last_verification_error": null, 21 "suspended": false, 22 "operator_held": false, 23 "primary": false, 24 "queued_messages": 0, 25 "queue_flushed_at": null 26 } 27]

GET /api/v1/sending_domains/:id

Get one domain, including DKIM CNAME, return-path, and DMARC.

  • id: Public sending domain id
request.sh
1curl -sS -X GET \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 https://app.postshiba.com/api/v1/sending_domains/:sending_domain_id
response.json
1{ 2 "id": "HsVtYk", 3 "name": "mail.example.com", 4 "tenant_id": "WbLcFd", 5 "tenant": "default", 6 "dkim_status": "pending", 7 "return_path_status": "pending", 8 "dmarc_status": "pending", 9 "sending_allowed": false, 10 "dkim_selector": "ps1", 11 "dkim_manual": false, 12 "dkim_txt": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA", 13 "dkim_cname_host": "ps1._domainkey.mail.example.com", 14 "dkim_cname_target": "HsVtYk.customers.capsule.test", 15 "dmarc_host": "_dmarc.mail.example.com", 16 "dmarc_record": "v=DMARC1; p=none;", 17 "return_path_host": "rp.mail.example.com", 18 "return_path_target": "rp.capsule.test", 19 "last_verification_error": null, 20 "suspended": false, 21 "operator_held": false, 22 "primary": false, 23 "queued_messages": 0, 24 "queue_flushed_at": null 25}

POST /api/v1/teams/:obfuscated_team_id/sending_domains

Create a domain. Name must be a fully qualified host such as mail.example.com. Optional tenant_id. Defaults to the team's default tenant. Optional dkim_selector, dkim_manual, and dkim_private_key (PEM) to import an existing key. dkim_manual skips our CNAME and checks the TXT at the selector instead. Queues a DNS check.

request.sh
1curl -sS -X POST \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 -H 'Content-Type: application/json' \ 4 -d '{"sending_domain":{"name":"mail.example.com","tenant_id":"WbLcFd"}}' \ 5 https://app.postshiba.com/api/v1/teams/KjkAJW/sending_domains
response.json
1{ 2 "id": "HsVtYk", 3 "name": "mail.example.com", 4 "tenant_id": "WbLcFd", 5 "tenant": "default", 6 "dkim_status": "pending", 7 "return_path_status": "pending", 8 "dmarc_status": "pending", 9 "sending_allowed": false, 10 "dkim_selector": "ps1", 11 "dkim_manual": false, 12 "dkim_txt": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA", 13 "dkim_cname_host": "ps1._domainkey.mail.example.com", 14 "dkim_cname_target": "HsVtYk.customers.capsule.test", 15 "dmarc_host": "_dmarc.mail.example.com", 16 "dmarc_record": "v=DMARC1; p=none;", 17 "return_path_host": "rp.mail.example.com", 18 "return_path_target": "rp.capsule.test", 19 "last_verification_error": null, 20 "suspended": false, 21 "operator_held": false, 22 "primary": false, 23 "queued_messages": 0, 24 "queue_flushed_at": null 25}

PATCH /api/v1/sending_domains/:id

Change the DKIM selector, switch dkim_manual, or import a PEM private key. Breaks authentication and sending until the new record verifies. Never returns dkim_private_key.

  • id: Public sending domain id
request.sh
1curl -sS -X PATCH \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 -H 'Content-Type: application/json' \ 4 -d '{"sending_domain":{"dkim_selector":"s1","dkim_manual":true,"dkim_private_key":"YOUR_PEM"}}' \ 5 https://app.postshiba.com/api/v1/sending_domains/:sending_domain_id
response.json
1{ 2 "id": "HsVtYk", 3 "name": "mail.example.com", 4 "tenant_id": "WbLcFd", 5 "tenant": "default", 6 "dkim_status": "pending", 7 "return_path_status": "pending", 8 "dmarc_status": "pending", 9 "sending_allowed": false, 10 "dkim_selector": "ps1", 11 "dkim_manual": true, 12 "dkim_txt": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA", 13 "dkim_cname_host": "ps1._domainkey.mail.example.com", 14 "dkim_cname_target": null, 15 "dmarc_host": "_dmarc.mail.example.com", 16 "dmarc_record": "v=DMARC1; p=none;", 17 "return_path_host": "rp.mail.example.com", 18 "return_path_target": "rp.capsule.test", 19 "last_verification_error": null, 20 "suspended": false, 21 "operator_held": false, 22 "primary": false, 23 "queued_messages": 0, 24 "queue_flushed_at": null 25}

POST /api/v1/sending_domains/:id/refresh

Issue new DKIM keys. Breaks authentication and sending until you publish the new CNAME or TXT and verify.

  • id: Public sending domain id
request.sh
1curl -sS -X POST \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 -H 'Content-Type: application/json' \ 4 https://app.postshiba.com/api/v1/sending_domains/:sending_domain_id/refresh
response.json
1{ 2 "id": "HsVtYk", 3 "name": "mail.example.com", 4 "tenant_id": "WbLcFd", 5 "tenant": "default", 6 "dkim_status": "pending", 7 "return_path_status": "pending", 8 "dmarc_status": "pending", 9 "sending_allowed": false, 10 "dkim_selector": "ps1", 11 "dkim_manual": false, 12 "dkim_txt": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA", 13 "dkim_cname_host": "ps1._domainkey.mail.example.com", 14 "dkim_cname_target": "HsVtYk.customers.capsule.test", 15 "dmarc_host": "_dmarc.mail.example.com", 16 "dmarc_record": "v=DMARC1; p=none;", 17 "return_path_host": "rp.mail.example.com", 18 "return_path_target": "rp.capsule.test", 19 "last_verification_error": null, 20 "suspended": false, 21 "operator_held": false, 22 "primary": false, 23 "queued_messages": 0, 24 "queue_flushed_at": null 25}

POST /api/v1/sending_domains/:id/verify

Run a DNS check now and return current statuses. A miss rechecks at 30 seconds, 2 minutes, and 5 minutes.

  • id: Public sending domain id
request.sh
1curl -sS -X POST \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 -H 'Content-Type: application/json' \ 4 https://app.postshiba.com/api/v1/sending_domains/:sending_domain_id/verify
response.json
1{ 2 "id": "HsVtYk", 3 "name": "mail.example.com", 4 "tenant_id": "WbLcFd", 5 "tenant": "default", 6 "dkim_status": "pending", 7 "return_path_status": "pending", 8 "dmarc_status": "pending", 9 "sending_allowed": false, 10 "dkim_selector": "ps1", 11 "dkim_manual": false, 12 "dkim_txt": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA", 13 "dkim_cname_host": "ps1._domainkey.mail.example.com", 14 "dkim_cname_target": "HsVtYk.customers.capsule.test", 15 "dmarc_host": "_dmarc.mail.example.com", 16 "dmarc_record": "v=DMARC1; p=none;", 17 "return_path_host": "rp.mail.example.com", 18 "return_path_target": "rp.capsule.test", 19 "last_verification_error": null, 20 "suspended": false, 21 "operator_held": false, 22 "primary": false, 23 "queued_messages": 0, 24 "queue_flushed_at": null 25}

POST /api/v1/sending_domains/:id/suspend

Pause sending for this domain.

  • id: Public sending domain id
request.sh
1curl -sS -X POST \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 -H 'Content-Type: application/json' \ 4 https://app.postshiba.com/api/v1/sending_domains/:sending_domain_id/suspend
response.json
1{ 2 "id": "HsVtYk", 3 "name": "mail.example.com", 4 "tenant_id": "WbLcFd", 5 "tenant": "default", 6 "dkim_status": "pending", 7 "return_path_status": "pending", 8 "dmarc_status": "pending", 9 "sending_allowed": false, 10 "dkim_selector": "ps1", 11 "dkim_manual": false, 12 "dkim_txt": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA", 13 "dkim_cname_host": "ps1._domainkey.mail.example.com", 14 "dkim_cname_target": "HsVtYk.customers.capsule.test", 15 "dmarc_host": "_dmarc.mail.example.com", 16 "dmarc_record": "v=DMARC1; p=none;", 17 "return_path_host": "rp.mail.example.com", 18 "return_path_target": "rp.capsule.test", 19 "last_verification_error": null, 20 "suspended": true, 21 "operator_held": false, 22 "primary": false, 23 "queued_messages": 0, 24 "queue_flushed_at": null 25}

POST /api/v1/sending_domains/:id/resume

Resume sending for this domain. Returns 422 {error: operator_held} while PostShiba support has turned the domain off, 403 {error: dbl_listed} while the domain is on the Spamhaus DBL, and 503 {error: dbl_unavailable} when the listing cannot be re-checked.

  • id: Public sending domain id
request.sh
1curl -sS -X POST \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 -H 'Content-Type: application/json' \ 4 https://app.postshiba.com/api/v1/sending_domains/:sending_domain_id/resume
response.json
1{ 2 "id": "HsVtYk", 3 "name": "mail.example.com", 4 "tenant_id": "WbLcFd", 5 "tenant": "default", 6 "dkim_status": "pending", 7 "return_path_status": "pending", 8 "dmarc_status": "pending", 9 "sending_allowed": false, 10 "dkim_selector": "ps1", 11 "dkim_manual": false, 12 "dkim_txt": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA", 13 "dkim_cname_host": "ps1._domainkey.mail.example.com", 14 "dkim_cname_target": "HsVtYk.customers.capsule.test", 15 "dmarc_host": "_dmarc.mail.example.com", 16 "dmarc_record": "v=DMARC1; p=none;", 17 "return_path_host": "rp.mail.example.com", 18 "return_path_target": "rp.capsule.test", 19 "last_verification_error": null, 20 "suspended": false, 21 "operator_held": false, 22 "primary": false, 23 "queued_messages": 0, 24 "queue_flushed_at": null 25}

POST /api/v1/sending_domains/:id/flush_queue

Drop queued mail for this domain. Mail sent in the next 5 minutes is dropped too. Dropped mail bounces with flushed by sender and does not suppress the recipient.

  • id: Public sending domain id
request.sh
1curl -sS -X POST \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 -H 'Content-Type: application/json' \ 4 https://app.postshiba.com/api/v1/sending_domains/:sending_domain_id/flush_queue
response.json
1{ 2 "id": "HsVtYk", 3 "name": "mail.example.com", 4 "tenant_id": "WbLcFd", 5 "tenant": "default", 6 "dkim_status": "pending", 7 "return_path_status": "pending", 8 "dmarc_status": "pending", 9 "sending_allowed": false, 10 "dkim_selector": "ps1", 11 "dkim_manual": false, 12 "dkim_txt": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA", 13 "dkim_cname_host": "ps1._domainkey.mail.example.com", 14 "dkim_cname_target": "HsVtYk.customers.capsule.test", 15 "dmarc_host": "_dmarc.mail.example.com", 16 "dmarc_record": "v=DMARC1; p=none;", 17 "return_path_host": "rp.mail.example.com", 18 "return_path_target": "rp.capsule.test", 19 "last_verification_error": null, 20 "suspended": false, 21 "operator_held": false, 22 "primary": false, 23 "queued_messages": 0, 24 "queue_flushed_at": "2026-10-14T00:00:00Z" 25}

POST /api/v1/sending_domains/:id/make_primary

Make this the account primary. Outbound mail is also DKIM-signed with this domain.

  • id: Public sending domain id
request.sh
1curl -sS -X POST \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 -H 'Content-Type: application/json' \ 4 https://app.postshiba.com/api/v1/sending_domains/:sending_domain_id/make_primary
response.json
1{ 2 "id": "HsVtYk", 3 "name": "mail.example.com", 4 "tenant_id": "WbLcFd", 5 "tenant": "default", 6 "dkim_status": "pending", 7 "return_path_status": "pending", 8 "dmarc_status": "pending", 9 "sending_allowed": false, 10 "dkim_selector": "ps1", 11 "dkim_manual": false, 12 "dkim_txt": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA", 13 "dkim_cname_host": "ps1._domainkey.mail.example.com", 14 "dkim_cname_target": "HsVtYk.customers.capsule.test", 15 "dmarc_host": "_dmarc.mail.example.com", 16 "dmarc_record": "v=DMARC1; p=none;", 17 "return_path_host": "rp.mail.example.com", 18 "return_path_target": "rp.capsule.test", 19 "last_verification_error": null, 20 "suspended": false, 21 "operator_held": false, 22 "primary": true, 23 "queued_messages": 0, 24 "queue_flushed_at": null 25}

POST /api/v1/sending_domains/:id/move

Move this domain to another tenant on the team. Only the new tenant's SMTP credentials can send from it afterwards. Its inboxes move with it, and the old tenant's suppressions are copied to the new tenant in the background. Requires tenant_id.

  • id: Public sending domain id
request.sh
1curl -sS -X POST \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 -H 'Content-Type: application/json' \ 4 -d '{"sending_domain":{"tenant_id":"WbLcFd"}}' \ 5 https://app.postshiba.com/api/v1/sending_domains/:sending_domain_id/move
response.json
1{ 2 "id": "HsVtYk", 3 "name": "mail.example.com", 4 "tenant_id": "WbLcFd", 5 "tenant": "default", 6 "dkim_status": "pending", 7 "return_path_status": "pending", 8 "dmarc_status": "pending", 9 "sending_allowed": false, 10 "dkim_selector": "ps1", 11 "dkim_manual": false, 12 "dkim_txt": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA", 13 "dkim_cname_host": "ps1._domainkey.mail.example.com", 14 "dkim_cname_target": "HsVtYk.customers.capsule.test", 15 "dmarc_host": "_dmarc.mail.example.com", 16 "dmarc_record": "v=DMARC1; p=none;", 17 "return_path_host": "rp.mail.example.com", 18 "return_path_target": "rp.capsule.test", 19 "last_verification_error": null, 20 "suspended": false, 21 "operator_held": false, 22 "primary": false, 23 "queued_messages": 0, 24 "queue_flushed_at": null 25}

POST /api/v1/sending_domains/:id/can_i_send_this

Mint a CanISendThis inbox and send a test from hello@domain.

  • id: Public sending domain id
request.sh
1curl -sS -X POST \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 -H 'Content-Type: application/json' \ 4 https://app.postshiba.com/api/v1/sending_domains/:sending_domain_id/can_i_send_this
response.json
1{ 2 "token": "tok_cist", 3 "email": "tok_cist@canisendthis.com", 4 "poll_after_seconds": 2, 5 "poll_path": "/api/v1/sending_domains/HsVtYk/can_i_send_this", 6 "report_url": "https://canisendthis.com/tok_cist" 7}

GET /api/v1/sending_domains/:id/can_i_send_this

Poll the CanISendThis report for a minted token.

  • id: Public sending domain id
  • token: Inbox token from POST
request.sh
1curl -sS -X GET \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 https://app.postshiba.com/api/v1/sending_domains/:sending_domain_id/can_i_send_this
response.json
1{ 2 "status": "ready", 3 "report": { 4 "subject": "Can I Send This check for mail.example.com", 5 "from": "hello@mail.example.com", 6 "score": { 7 "pass": 8, 8 "total": 10 9 }, 10 "checks": [ 11 { 12 "id": "spf", 13 "kind": "pass", 14 "detail": "SPF aligned" 15 } 16 ], 17 "spf": { 18 "kind": "pass", 19 "detail": "aligned" 20 }, 21 "dkim": { 22 "kind": "pass", 23 "detail": "valid" 24 }, 25 "dmarc": { 26 "kind": "none", 27 "detail": "" 28 }, 29 "spamassassin": { 30 "score": 1.2 31 }, 32 "report_url": "https://canisendthis.com/tok_cist" 33 } 34}

DELETE /api/v1/sending_domains/:id

Remove a domain. Live inboxes block. Disabled inboxes do not.

  • id: Public sending domain id
request.sh
1curl -sS -X DELETE \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 https://app.postshiba.com/api/v1/sending_domains/:sending_domain_id