usend Docs
API endpoints

Domains

Add, verify, configure and delete sending domains.

See Verify a domain for a guide.

The domain object

JSON
{
  "object": "domain",
  "id": "d91cd9bd-1176-453e-8fc1-35364d380206",
  "name": "acme.com",
  "status": "verified",
  "created_at": "2026-10-11T08:00:00.000Z",
  "region": "us-east-1",
  "open_tracking": false,
  "click_tracking": false,
  "receiving_enabled": false,
  "custom_return_path": "send",
  "dns_verified_at": "2026-10-11T08:06:12.000Z",
  "verified_at": "2026-10-11T08:09:40.000Z",
  "records": [
    { "record": "DKIM", "name": "rs1._domainkey", "type": "TXT", "ttl": "Auto", "status": "verified", "value": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..." },
    { "record": "SPF", "name": "send-ses", "type": "CNAME", "ttl": "Auto", "status": "verified", "value": "rp-ses-us-east-1.usend.et" },
    { "record": "DMARC", "name": "_dmarc", "type": "TXT", "ttl": "Auto", "status": "pending", "value": "v=DMARC1; p=none;" }
  ]
}
FieldDescription
statusnot_started, pending, verified, temporary_failure or failed. See domain status.
custom_return_pathThe return-path label.
dns_verified_atWhen the required DNS records first verified.
verified_atWhen the domain first became verified.
recordsThe DNS records to publish. name is relative to the domain (@ is the domain itself). Each has its own status: not_started, pending, verified or failed. A Receiving MX record with a priority is added when receiving_enabled is true.
dns_providerOnly on GET /domains/{id}: cloudflare when the domain's DNS is on Cloudflare, otherwise empty.

Create a domain

POST /domains

NameTypeRequiredDescription
namestringYesThe domain, for example acme.com or mail.acme.com.
custom_return_pathstringNoReturn-path label. Default send. One DNS label, up to 59 characters.
cURL
curl -X POST https://api.usend.et/domains \
  -H "Authorization: Bearer us_123456789" \
  -H "Content-Type: application/json" \
  -d '{ "name": "acme.com" }'

Returns the domain object with status not_started. Adding a domain your organization already has fails with 409 conflict.

Retrieve a domain

GET /domains/{id}

NameTypeRequiredDescription
idstringYesThe domain ID (path).
cURL
curl https://api.usend.et/domains/d91cd9bd-1176-453e-8fc1-35364d380206 \
  -H "Authorization: Bearer us_123456789"

Returns the domain object, including dns_provider.

List domains

GET /domains

cURL
curl https://api.usend.et/domains \
  -H "Authorization: Bearer us_123456789"
Response
{
  "object": "list",
  "data": [
    {
      "object": "domain",
      "id": "d91cd9bd-1176-453e-8fc1-35364d380206",
      "name": "acme.com",
      "status": "verified",
      "...": "..."
    }
  ]
}

Each item is a full domain object (without dns_provider). Domains are not paginated.

Update a domain

PATCH /domains/{id}

NameTypeRequiredDescription
idstringYesThe domain ID (path).
open_trackingbooleanNoTrack opens. See Tracking.
click_trackingbooleanNoTrack clicks.
receiving_enabledbooleanNoReceive email for this domain. See Receiving.
custom_return_pathstringNoNew return-path label. Changing it sets the domain back to pending until the new record verifies.
cURL
curl -X PATCH https://api.usend.et/domains/d91cd9bd-1176-453e-8fc1-35364d380206 \
  -H "Authorization: Bearer us_123456789" \
  -H "Content-Type: application/json" \
  -d '{ "open_tracking": true, "click_tracking": true }'

Returns the updated domain object.

Verify a domain

POST /domains/{id}/verify

Starts verification. It runs in the background: poll GET /domains/{id} for the result.

cURL
curl -X POST https://api.usend.et/domains/d91cd9bd-1176-453e-8fc1-35364d380206/verify \
  -H "Authorization: Bearer us_123456789"
Response
{ "object": "domain", "id": "d91cd9bd-1176-453e-8fc1-35364d380206" }

Auto-configure DNS

POST /domains/{id}/auto-configure

Publishes the domain's records in Cloudflare with a token you provide for this request only. The token is never stored. See Auto-configure with Cloudflare.

NameTypeRequiredDescription
idstringYesThe domain ID (path).
providerstringNocloudflare (the only supported provider).
api_tokenstringYesA Cloudflare API token with the Edit zone DNS permission for the domain's zone.
cURL
curl -X POST https://api.usend.et/domains/d91cd9bd-1176-453e-8fc1-35364d380206/auto-configure \
  -H "Authorization: Bearer us_123456789" \
  -H "Content-Type: application/json" \
  -d '{ "provider": "cloudflare", "api_token": "cf_token_value" }'
Response
{
  "object": "domain",
  "id": "d91cd9bd-1176-453e-8fc1-35364d380206",
  "provider": "cloudflare",
  "zone": "acme.com",
  "records": [
    { "name": "rs1._domainkey.acme.com", "type": "TXT", "value": "v=DKIM1; k=rsa; p=MIIB...", "action": "created" },
    { "name": "send-ses.acme.com", "type": "CNAME", "value": "rp-ses-us-east-1.usend.et", "action": "created" },
    { "name": "_dmarc.acme.com", "type": "TXT", "value": "v=DMARC1; p=none;", "action": "unchanged" }
  ]
}

action is created, updated, unchanged, skipped or conflict, with a message when there is something to explain. Fails with 422 when Cloudflare refuses the token, and 422 dns_provider_error (with Cloudflare's message) on other Cloudflare errors.

Delete a domain

DELETE /domains/{id}

cURL
curl -X DELETE https://api.usend.et/domains/d91cd9bd-1176-453e-8fc1-35364d380206 \
  -H "Authorization: Bearer us_123456789"
Response
{ "object": "domain", "id": "d91cd9bd-1176-453e-8fc1-35364d380206", "deleted": true }