Domains
Add, verify, configure and delete sending domains.
See Verify a domain for a guide.
The domain object
{
"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;" }
]
}| Field | Description |
|---|---|
status | not_started, pending, verified, temporary_failure or failed. See domain status. |
custom_return_path | The return-path label. |
dns_verified_at | When the required DNS records first verified. |
verified_at | When the domain first became verified. |
records | The 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_provider | Only on GET /domains/{id}: cloudflare when the domain's DNS is on Cloudflare, otherwise empty. |
Create a domain
POST /domains
| Name | Type | Required | Description |
|---|---|---|---|
name | string | Yes | The domain, for example acme.com or mail.acme.com. |
custom_return_path | string | No | Return-path label. Default send. One DNS label, up to 59 characters. |
curl -X POST https://api.usend.et/domains \
-H "Authorization: Bearer us_123456789" \
-H "Content-Type: application/json" \
-d '{ "name": "acme.com" }'const { data, error } = await usend.domains.create({ name: 'acme.com' });domain = usend.domains.create({"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}
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The domain ID (path). |
curl https://api.usend.et/domains/d91cd9bd-1176-453e-8fc1-35364d380206 \
-H "Authorization: Bearer us_123456789"const { data, error } = await usend.domains.get('d91cd9bd-1176-453e-8fc1-35364d380206');domain = usend.domains.get("d91cd9bd-1176-453e-8fc1-35364d380206")Returns the domain object, including dns_provider.
List domains
GET /domains
curl https://api.usend.et/domains \
-H "Authorization: Bearer us_123456789"const { data, error } = await usend.domains.list();domains = usend.domains.list(){
"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}
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The domain ID (path). |
open_tracking | boolean | No | Track opens. See Tracking. |
click_tracking | boolean | No | Track clicks. |
receiving_enabled | boolean | No | Receive email for this domain. See Receiving. |
custom_return_path | string | No | New return-path label. Changing it sets the domain back to pending until the new record verifies. |
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 -X POST https://api.usend.et/domains/d91cd9bd-1176-453e-8fc1-35364d380206/verify \
-H "Authorization: Bearer us_123456789"const { data, error } = await usend.domains.verify('d91cd9bd-1176-453e-8fc1-35364d380206');usend.domains.verify("d91cd9bd-1176-453e-8fc1-35364d380206"){ "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.
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The domain ID (path). |
provider | string | No | cloudflare (the only supported provider). |
api_token | string | Yes | A Cloudflare API token with the Edit zone DNS permission for the domain's zone. |
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" }'{
"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 -X DELETE https://api.usend.et/domains/d91cd9bd-1176-453e-8fc1-35364d380206 \
-H "Authorization: Bearer us_123456789"const { data, error } = await usend.domains.remove('d91cd9bd-1176-453e-8fc1-35364d380206');usend.domains.remove("d91cd9bd-1176-453e-8fc1-35364d380206"){ "object": "domain", "id": "d91cd9bd-1176-453e-8fc1-35364d380206", "deleted": true }