Skip to content

Sending domains

Orgs verify their own sending domains; Cowliss registers the identity in AWS SES and mirrors the status SES reports. Claims are exact-string and global: a parent or child of a claimed domain conflicts (409). The dnsRecords array on the DTO is the copy-paste table your DNS must carry (three DKIM CNAMEs, the MX return path and its SPF TXT, plus a recommended DMARC TXT), each with its own status. SES re-checks DNS on its own schedule and emits no domain events, so status refreshes are pull-only. Orgs without a verified domain send from the zero-config shared fallback domain. All mutations require org:admin.

List sending domains

Auth: Clerk session token.

Query parameters

{
"cursor": "string",
"limit": 50,
"q": "string"
}
Field Type Required Constraints
cursor string no
limit integer no default 50; 1 ≤ x ≤ 100
q string no length 0–200

Response 200

{
"data": [
{
"id": "string",
"orgId": "string",
"domain": "string",
"region": "string",
"status": "not_started",
"dkimStatus": "string",
"spfStatus": "string",
"clickTracking": true,
"dnsRecords": [
{
"type": "CNAME",
"name": "string",
"value": "string",
"ttl": "string",
"priority": "string",
"status": "not_started",
"recommended": true
}
],
"lastCheckedAt": "2026-01-15T09:30:00.000Z",
"createdAt": "2026-01-15T09:30:00.000Z",
"updatedAt": "2026-01-15T09:30:00.000Z"
}
],
"meta": {
"requestId": "string",
"nextCursor": "string",
"hasMore": true
}
}
Field Type Required Constraints
data object[] yes
data[] object yes
data[].id string yes
data[].orgId string yes
data[].domain string yes
data[].region string yes
data[].status “not_started” | “pending” | “success” | “failed” | “temporary_failure” yes
data[].dkimStatus string | null yes
data[].spfStatus string | null yes
data[].clickTracking boolean yes
data[].dnsRecords object[] yes
data[].dnsRecords[] object yes
data[].dnsRecords[].type “CNAME” | “MX” | “TXT” yes
data[].dnsRecords[].name string yes
data[].dnsRecords[].value string yes
data[].dnsRecords[].ttl string yes
data[].dnsRecords[].priority string | null no
data[].dnsRecords[].status “not_started” | “pending” | “success” | “failed” | “temporary_failure” yes
data[].dnsRecords[].recommended boolean no
data[].lastCheckedAt string (date-time) | null yes
data[].createdAt string (date-time) yes
data[].updatedAt string (date-time) yes
meta object no
meta.requestId string no
meta.nextCursor string | null no
meta.hasMore boolean no

Errors follow the shared envelope and code table.

Fetch one sending domain

Auth: Clerk session token.

Response 200

{
"data": {
"id": "string",
"orgId": "string",
"domain": "string",
"region": "string",
"status": "not_started",
"dkimStatus": "string",
"spfStatus": "string",
"clickTracking": true,
"dnsRecords": [
{
"type": "CNAME",
"name": "string",
"value": "string",
"ttl": "string",
"priority": "string",
"status": "not_started",
"recommended": true
}
],
"lastCheckedAt": "2026-01-15T09:30:00.000Z",
"createdAt": "2026-01-15T09:30:00.000Z",
"updatedAt": "2026-01-15T09:30:00.000Z"
},
"meta": {
"requestId": "string",
"nextCursor": "string",
"hasMore": true
}
}
Field Type Required Constraints
data object yes
data.id string yes
data.orgId string yes
data.domain string yes
data.region string yes
data.status “not_started” | “pending” | “success” | “failed” | “temporary_failure” yes
data.dkimStatus string | null yes
data.spfStatus string | null yes
data.clickTracking boolean yes
data.dnsRecords object[] yes
data.dnsRecords[] object yes
data.dnsRecords[].type “CNAME” | “MX” | “TXT” yes
data.dnsRecords[].name string yes
data.dnsRecords[].value string yes
data.dnsRecords[].ttl string yes
data.dnsRecords[].priority string | null no
data.dnsRecords[].status “not_started” | “pending” | “success” | “failed” | “temporary_failure” yes
data.dnsRecords[].recommended boolean no
data.lastCheckedAt string (date-time) | null yes
data.createdAt string (date-time) yes
data.updatedAt string (date-time) yes
meta object no
meta.requestId string no
meta.nextCursor string | null no
meta.hasMore boolean no

Errors follow the shared envelope and code table.

Claim a sending domain

Auth: Clerk session token.

Request body

{
"data": {
"domain": "string"
}
}
Field Type Required Constraints
data object yes
data.domain string yes length 0–253

Response 201

{
"data": {
"id": "string",
"orgId": "string",
"domain": "string",
"region": "string",
"status": "not_started",
"dkimStatus": "string",
"spfStatus": "string",
"clickTracking": true,
"dnsRecords": [
{
"type": "CNAME",
"name": "string",
"value": "string",
"ttl": "string",
"priority": "string",
"status": "not_started",
"recommended": true
}
],
"lastCheckedAt": "2026-01-15T09:30:00.000Z",
"createdAt": "2026-01-15T09:30:00.000Z",
"updatedAt": "2026-01-15T09:30:00.000Z"
},
"meta": {
"requestId": "string",
"nextCursor": "string",
"hasMore": true
}
}
Field Type Required Constraints
data object yes
data.id string yes
data.orgId string yes
data.domain string yes
data.region string yes
data.status “not_started” | “pending” | “success” | “failed” | “temporary_failure” yes
data.dkimStatus string | null yes
data.spfStatus string | null yes
data.clickTracking boolean yes
data.dnsRecords object[] yes
data.dnsRecords[] object yes
data.dnsRecords[].type “CNAME” | “MX” | “TXT” yes
data.dnsRecords[].name string yes
data.dnsRecords[].value string yes
data.dnsRecords[].ttl string yes
data.dnsRecords[].priority string | null no
data.dnsRecords[].status “not_started” | “pending” | “success” | “failed” | “temporary_failure” yes
data.dnsRecords[].recommended boolean no
data.lastCheckedAt string (date-time) | null yes
data.createdAt string (date-time) yes
data.updatedAt string (date-time) yes
meta object no
meta.requestId string no
meta.nextCursor string | null no
meta.hasMore boolean no

Errors follow the shared envelope and code table.

Re-check DNS now

Auth: Clerk session token.

Response 200

{
"data": {
"id": "string",
"orgId": "string",
"domain": "string",
"region": "string",
"status": "not_started",
"dkimStatus": "string",
"spfStatus": "string",
"clickTracking": true,
"dnsRecords": [
{
"type": "CNAME",
"name": "string",
"value": "string",
"ttl": "string",
"priority": "string",
"status": "not_started",
"recommended": true
}
],
"lastCheckedAt": "2026-01-15T09:30:00.000Z",
"createdAt": "2026-01-15T09:30:00.000Z",
"updatedAt": "2026-01-15T09:30:00.000Z"
},
"meta": {
"requestId": "string",
"nextCursor": "string",
"hasMore": true
}
}
Field Type Required Constraints
data object yes
data.id string yes
data.orgId string yes
data.domain string yes
data.region string yes
data.status “not_started” | “pending” | “success” | “failed” | “temporary_failure” yes
data.dkimStatus string | null yes
data.spfStatus string | null yes
data.clickTracking boolean yes
data.dnsRecords object[] yes
data.dnsRecords[] object yes
data.dnsRecords[].type “CNAME” | “MX” | “TXT” yes
data.dnsRecords[].name string yes
data.dnsRecords[].value string yes
data.dnsRecords[].ttl string yes
data.dnsRecords[].priority string | null no
data.dnsRecords[].status “not_started” | “pending” | “success” | “failed” | “temporary_failure” yes
data.dnsRecords[].recommended boolean no
data.lastCheckedAt string (date-time) | null yes
data.createdAt string (date-time) yes
data.updatedAt string (date-time) yes
meta object no
meta.requestId string no
meta.nextCursor string | null no
meta.hasMore boolean no

Errors follow the shared envelope and code table.

Toggle click tracking

Auth: Clerk session token.

Request body

{
"data": {
"clickTracking": true
}
}
Field Type Required Constraints
data object yes
data.clickTracking boolean yes

Response 200

{
"data": {
"id": "string",
"orgId": "string",
"domain": "string",
"region": "string",
"status": "not_started",
"dkimStatus": "string",
"spfStatus": "string",
"clickTracking": true,
"dnsRecords": [
{
"type": "CNAME",
"name": "string",
"value": "string",
"ttl": "string",
"priority": "string",
"status": "not_started",
"recommended": true
}
],
"lastCheckedAt": "2026-01-15T09:30:00.000Z",
"createdAt": "2026-01-15T09:30:00.000Z",
"updatedAt": "2026-01-15T09:30:00.000Z"
},
"meta": {
"requestId": "string",
"nextCursor": "string",
"hasMore": true
}
}
Field Type Required Constraints
data object yes
data.id string yes
data.orgId string yes
data.domain string yes
data.region string yes
data.status “not_started” | “pending” | “success” | “failed” | “temporary_failure” yes
data.dkimStatus string | null yes
data.spfStatus string | null yes
data.clickTracking boolean yes
data.dnsRecords object[] yes
data.dnsRecords[] object yes
data.dnsRecords[].type “CNAME” | “MX” | “TXT” yes
data.dnsRecords[].name string yes
data.dnsRecords[].value string yes
data.dnsRecords[].ttl string yes
data.dnsRecords[].priority string | null no
data.dnsRecords[].status “not_started” | “pending” | “success” | “failed” | “temporary_failure” yes
data.dnsRecords[].recommended boolean no
data.lastCheckedAt string (date-time) | null yes
data.createdAt string (date-time) yes
data.updatedAt string (date-time) yes
meta object no
meta.requestId string no
meta.nextCursor string | null no
meta.hasMore boolean no

Errors follow the shared envelope and code table.

Release a domain claim

Auth: Clerk session token.

Response 200

{
"data": {
"deleted": true
},
"meta": {
"requestId": "string",
"nextCursor": "string",
"hasMore": true
}
}
Field Type Required Constraints
data object yes
data.deleted true yes
meta object no
meta.requestId string no
meta.nextCursor string | null no
meta.hasMore boolean no

Errors follow the shared envelope and code table.