POST /api/v1/domains/{domainId}/verify
Asks the email provider to re-read the DNS and stores the answer. Admin role required.
This is the call to repeat after publishing your records — not GET /api/v1/domains, which returns
the last known state. Propagation takes up to 72 hours, usually minutes.
Authorization
| Role in the organization | This endpoint |
|---|---|
OWNER | Allowed |
ADMIN | Allowed |
MEMBER | Refused — 403 |
Path parameters
| Parameter | Type | Description |
|---|---|---|
domainId | string | Required. The domain to re-check |
Example
bash
curl -X POST -H "x-api-key: $AGENTMAIL_API_KEY" \
"https://www.agentsmail.io/api/v1/domains/$DOMAIN_ID/verify"Response
200 OK— the call succeeded.401 Unauthorized— missing or invalid key, or its owner left the organization.403 Forbidden— the key's owner is amemberof the organization, not anadmin.404 Not Found— no such resource, or it belongs to another organization. The API never confirms that an id exists to a caller who has no right to it.429 Too Many Requests— over 120 requests in a minute for this key.
Response fields
The domain after the check, same shape as reading it.Nothing is gained by publishing twice. Poll this endpoint until
verified is true; on a
provider outage it answers an error rather than a stale state, because verification is exactly
what was asked for.| Field | Type | Description |
|---|---|---|
success | boolean | Indicates if the operation was successful |
data.id | string | Identifier of the declared domain |
data.domain | string | The domain itself |
data.dkimStatus | string | PENDING, SUCCESS or FAILED — the signing keys |
data.mailFromStatus | string \ | null |
data.mailFromDomain | string \ | null |
data.verified | boolean | The only question that decides sending: DKIM SUCCESS and ownership proved |
data.ownershipProved | boolean | Which of the two gestures is still missing |
data.lastCheckedAt | string \ | null |
data.sesUnavailable | boolean | true means you are reading the last known state, not the current truth |
data.dnsRecords | array | The records to publish — {type, name, value, purpose} |
Example response
json
{
"success": true,
"data": {
"id": "4d19c0a2",
"domain": "mail.example.com",
"dkimStatus": "SUCCESS",
"mailFromStatus": "SUCCESS",
"mailFromDomain": "bounce.mail.example.com",
"verified": true,
"ownershipProved": true,
"lastCheckedAt": "2026-08-23T10:22:05.000Z",
"sesUnavailable": true,
"dnsRecords": [
{
"type": "CNAME",
"name": "abc123._domainkey.mail.example.com",
"value": "abc123.dkim.amazonses.com",
"purpose": "dkim"
}
]
}
}Agent recipe
Declaring a domain, publishing its records and verifying it is a loop an agent can run end to end. Propagation takes minutes to 72 hours, so back off rather than hammer.js
const {data: domain} = await (
await fetch(`${base}/domains`, {
method: 'POST',
headers: {...headers, 'content-type': 'application/json'},
body: JSON.stringify({domain: 'mail.example.com'}),
})
).json()
await publishToDns(domain.dnsRecords) // your registrar, your API
for (let wait = 30_000; wait < 3_600_000; wait *= 2) {
const {data} = await (
await fetch(`${base}/domains/${domain.id}/verify`, {method: 'POST', headers})
).json()
if (data.verified) break
if (!data.ownershipProved) console.log('DKIM is fine — the TXT challenge is what is missing')
await new Promise((resolve) => setTimeout(resolve, wait))
}