API reference
Domains API
Reference for creating, listing, retrieving, updating, verifying and deleting sending domains.
The domains API manages the sending domains of the project that owns your API key. Every endpoint needs a full_access key. For the concepts, see Add a domain and DNS records.
The domain object
{
"object": "domain",
"id": "jh7b2k4d9x1m5q8r3t6v0w2y",
"name": "mail.yourcompany.com",
"status": "verified",
"region": "us-east-1",
"created_at": "2026-11-14T10:30:00.000Z",
"open_tracking": false,
"click_tracking": true,
"records": [
{
"record": "DKIM",
"name": "<token>._domainkey.mail.yourcompany.com",
"type": "CNAME",
"ttl": "Auto",
"status": "verified",
"value": "<value from the API>"
}
]
}status is not_started, pending, verified, temporary_failure or failed. A record that has a priority, such as MX, also has a priority field. The list endpoint leaves out records.
Create a domain
Adds a domain and starts generating its DNS records. Returns 201.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | A valid domain name, 3 to 253 characters. Stored in lowercase. |
region | string | No | Leave out unless support told you otherwise. |
open_tracking | boolean | No | Default false. |
click_tracking | boolean | No | Default false. |
curl -X POST https://api.sooner.dev/domains \
-H "Authorization: Bearer $SOONER_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "mail.yourcompany.com", "click_tracking": true }'{
"object": "domain",
"id": "jh7b2k4d9x1m5q8r3t6v0w2y",
"name": "mail.yourcompany.com",
"status": "not_started",
"region": "us-east-1",
"created_at": "2026-11-14T10:30:00.000Z",
"open_tracking": false,
"click_tracking": true,
"records": []
}records is empty until the records are generated, usually within a few seconds. Fetch the domain again to read them.
Notable errors: validation_error for an invalid name, a domain already registered by you or by another team, or the Free plan's limit of 10 domains.
List domains
Returns every domain in the project, without records. The list is not paginated.
curl https://api.sooner.dev/domains \
-H "Authorization: Bearer $SOONER_API_KEY"{
"object": "list",
"data": [
{
"object": "domain",
"id": "jh7b2k4d9x1m5q8r3t6v0w2y",
"name": "mail.yourcompany.com",
"status": "verified",
"region": "us-east-1",
"created_at": "2026-11-14T10:30:00.000Z",
"open_tracking": false,
"click_tracking": true
}
]
}Retrieve a domain
Returns one domain with its records.
curl https://api.sooner.dev/domains/jh7b2k4d9x1m5q8r3t6v0w2y \
-H "Authorization: Bearer $SOONER_API_KEY"The response is the domain object above. Notable errors: not_found.
Update a domain
Turns open and click tracking on or off. See Open and click tracking.
| Field | Type | Required | Description |
|---|---|---|---|
open_tracking | boolean | No | Record opens. |
click_tracking | boolean | No | Record clicks. |
curl -X PATCH https://api.sooner.dev/domains/jh7b2k4d9x1m5q8r3t6v0w2y \
-H "Authorization: Bearer $SOONER_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "open_tracking": true }'{ "object": "domain", "id": "jh7b2k4d9x1m5q8r3t6v0w2y" }Verify a domain
Asks Sooner to check the DNS records now instead of waiting for the next automatic check. The result arrives afterward in the domain's status and in the domain.verified or domain.failed webhook.
curl -X POST https://api.sooner.dev/domains/jh7b2k4d9x1m5q8r3t6v0w2y/verify \
-H "Authorization: Bearer $SOONER_API_KEY"{ "object": "domain", "id": "jh7b2k4d9x1m5q8r3t6v0w2y" }Delete a domain
Removes a domain. You can no longer send from it.
curl -X DELETE https://api.sooner.dev/domains/jh7b2k4d9x1m5q8r3t6v0w2y \
-H "Authorization: Bearer $SOONER_API_KEY"{ "object": "domain", "id": "jh7b2k4d9x1m5q8r3t6v0w2y", "deleted": true }Notable errors: validation_error if scheduled emails from this domain still exist. Cancel them first. See Scheduling.
With the Node SDK
import { Resend } from "resend";
const resend = new Resend(process.env.SOONER_API_KEY, { baseUrl: "https://api.sooner.dev" });
const { data: domain } = await resend.domains.create({ name: "mail.yourcompany.com" });
await resend.domains.verify(domain!.id);
const { data: domains } = await resend.domains.list();