Skip to content
Cowliss is in beta: features and pricing may change.

Sending domains

An organization cannot send without a verified domain. Each name is claimed on its own (acme.com and mail.acme.com are separate claims), and a domain belongs to the organization whose own verification record resolved last, so publishing that record takes a name another organization holds. The dnsRecords array specifies what 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. DNS is re-checked on a schedule and nothing pushes an event when it is, so status refreshes are pull-only.

List sending domains

Auth: 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
}
],
"challengeToken": "string",
"challengeVerifiedAt": "2026-01-15T09:30:00.000Z",
"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,
"warnings": [
{
"code": "string",
"message": "string",
"suggestion": "string"
}
]
}
}
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” | “blocked” 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” | “blocked” yes
data[].dnsRecords[].recommended boolean no
data[].challengeToken string yes
data[].challengeVerifiedAt string (date-time) | null yes
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
meta.warnings object[] no
meta.warnings[] object no
meta.warnings[].code string yes
meta.warnings[].message string yes
meta.warnings[].suggestion string no

Errors follow the shared envelope and code table.

Fetch one sending domain

Auth: 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
}
],
"challengeToken": "string",
"challengeVerifiedAt": "2026-01-15T09:30:00.000Z",
"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,
"warnings": [
{
"code": "string",
"message": "string",
"suggestion": "string"
}
]
}
}
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” | “blocked” 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” | “blocked” yes
data.dnsRecords[].recommended boolean no
data.challengeToken string yes
data.challengeVerifiedAt string (date-time) | null yes
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
meta.warnings object[] no
meta.warnings[] object no
meta.warnings[].code string yes
meta.warnings[].message string yes
meta.warnings[].suggestion string no

Errors follow the shared envelope and code table.

Add a sending domain

Auth: 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
}
],
"challengeToken": "string",
"challengeVerifiedAt": "2026-01-15T09:30:00.000Z",
"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,
"warnings": [
{
"code": "string",
"message": "string",
"suggestion": "string"
}
]
}
}
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” | “blocked” 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” | “blocked” yes
data.dnsRecords[].recommended boolean no
data.challengeToken string yes
data.challengeVerifiedAt string (date-time) | null yes
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
meta.warnings object[] no
meta.warnings[] object no
meta.warnings[].code string yes
meta.warnings[].message string yes
meta.warnings[].suggestion string no

Errors follow the shared envelope and code table.

Where the DNS provider can publish the records

The Domain Connect link for this domain’s DNS provider, which shows the admin the records and asks them to confirm. url is null when the provider does not support it.

Auth: Session token.

Response 200

{
"data": {
"url": "https://example.com/hooks/cowliss",
"provider": "string"
},
"meta": {
"requestId": "string",
"nextCursor": "string",
"hasMore": true,
"warnings": [
{
"code": "string",
"message": "string",
"suggestion": "string"
}
]
}
}
Field Type Required Constraints
data object yes
data.url string (uri) | null yes
data.provider string | null yes
meta object no
meta.requestId string no
meta.nextCursor string | null no
meta.hasMore boolean no
meta.warnings object[] no
meta.warnings[] object no
meta.warnings[].code string yes
meta.warnings[].message string yes
meta.warnings[].suggestion string no

Errors follow the shared envelope and code table.

Re-check DNS now

Auth: 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
}
],
"challengeToken": "string",
"challengeVerifiedAt": "2026-01-15T09:30:00.000Z",
"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,
"warnings": [
{
"code": "string",
"message": "string",
"suggestion": "string"
}
]
}
}
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” | “blocked” 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” | “blocked” yes
data.dnsRecords[].recommended boolean no
data.challengeToken string yes
data.challengeVerifiedAt string (date-time) | null yes
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
meta.warnings object[] no
meta.warnings[] object no
meta.warnings[].code string yes
meta.warnings[].message string yes
meta.warnings[].suggestion string no

Errors follow the shared envelope and code table.

Toggle click tracking

Enabling click tracking requires a verified domain, while disabling is always allowed. Tracking covers every email sent from the domain, including transactional email.

Auth: 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
}
],
"challengeToken": "string",
"challengeVerifiedAt": "2026-01-15T09:30:00.000Z",
"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,
"warnings": [
{
"code": "string",
"message": "string",
"suggestion": "string"
}
]
}
}
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” | “blocked” 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” | “blocked” yes
data.dnsRecords[].recommended boolean no
data.challengeToken string yes
data.challengeVerifiedAt string (date-time) | null yes
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
meta.warnings object[] no
meta.warnings[] object no
meta.warnings[].code string yes
meta.warnings[].message string yes
meta.warnings[].suggestion string no

Errors follow the shared envelope and code table.

Give up a sending domain

Sending from this domain stops immediately, and the domain becomes available for any organization to claim.

Auth: Session token.

Response 200

{
"data": {
"deleted": true
},
"meta": {
"requestId": "string",
"nextCursor": "string",
"hasMore": true,
"warnings": [
{
"code": "string",
"message": "string",
"suggestion": "string"
}
]
}
}
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
meta.warnings object[] no
meta.warnings[] object no
meta.warnings[].code string yes
meta.warnings[].message string yes
meta.warnings[].suggestion string no

Errors follow the shared envelope and code table.