Skip to content

Provisioning API

Create a sender

POST
/senders
curl --request POST \
--url https://live-api.customers.ac/v1/senders \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "user_id": "usr_a1b2c3d4-e5f6-7890-abcd-ef1234567890", "name": "Acme Outbound Q1", "domains": [ "outbound.acme.com", "cold.acme.com", "sales.acme.com" ], "personas": [ { "first_name": "Jane", "last_name": "Doe", "title": "Head of Partnerships" } ] }'

Creates a new sender with all its domains. Domains must be specified at creation time and cannot be added afterwards. The platform immediately begins processing each domain: assigning nameservers (asynchronous — usually within a few minutes), then waiting for DNS propagation (up to 48 hours per domain), then provisioning mailboxes automatically.

After creation, call GET /v1/senders/{id}/domains to retrieve the nameserver values assigned to each domain.

Media typeapplication/json
object
user_id
required

The user this sender belongs to.

string format: uuid
name
required

A human-readable name for this sender.

string
<= 255 characters
domains
required

The domains to connect to this sender. All domains must be specified at creation time. Minimum 1, maximum 50.

Array<string>
>= 1 items <= 50 items
personas

Persona templates for generating mailboxes. You can also add these later.

Array<object>

A persona template. One mailbox is created per persona per domain (e.g., 3 personas x 3 domains = 9 mailboxes).

object
first_name
required

First name used in the mailbox address.

string
last_name
required

Last name used in the mailbox address.

string
title

Job title, used for display name in the mailbox.

string | null
Example
{
"user_id": "usr_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Acme Outbound Q1",
"domains": [
"outbound.acme.com",
"cold.acme.com",
"sales.acme.com"
],
"personas": [
{
"first_name": "Jane",
"last_name": "Doe",
"title": "Head of Partnerships"
}
]
}

Sender created. Domain nameserver assignment has begun. Call GET /v1/senders/{id}/domains to check nameserver assignments and update your registrar.

Media typeapplication/json
object
data
required
object
id
required

Unique identifier for the sender.

string format: uuid
user_id
required

The user this sender belongs to.

string format: uuid
name
required

A human-readable name for this sender, chosen by the partner.

string
status
required

The current lifecycle status of a sender.

string
Allowed values: pending provisioning active deprovisioning deprovisioned
personas

Templates used to generate mailbox usernames on each domain.

Array<object>

A persona template. One mailbox is created per persona per domain (e.g., 3 personas x 3 domains = 9 mailboxes).

object
first_name
required

First name used in the mailbox address.

string
last_name
required

Last name used in the mailbox address.

string
title

Job title, used for display name in the mailbox.

string | null
domains_count

Number of domains connected to this sender.

integer
mailboxes_count

Total number of mailboxes across all domains.

integer
created_at
required
string format: date-time
updated_at
required
string format: date-time
operation_id
required

The ID of the provisioning operation. Poll GET /v1/operations/{id} to track progress.

string format: uuid
Example
{
"data": {
"id": "snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"user_id": "usr_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Acme Outbound Q1",
"status": "pending",
"personas": [
{
"first_name": "Jane",
"last_name": "Doe",
"title": "Head of Partnerships"
}
],
"domains_count": 3,
"mailboxes_count": 9,
"created_at": "2026-03-20T09:00:00Z",
"updated_at": "2026-03-20T12:30:00Z"
},
"operation_id": "op_f47ac10b-58cc-4372-a567-0e02b2c3d479"
}

The request body failed validation.

Media typeapplication/json
object
error
required
object
code
required

A machine-readable error code.

string
Allowed values: auth.missing_key auth.invalid_key auth.insufficient_scope rate.quota_exceeded validation.required_field validation.invalid_value resource.not_found resource.already_exists resource.not_ready server.error
message
required

A human-readable explanation of the error.

string
doc_url

A link to the documentation page for this error code.

string format: uri
details

For validation errors, a list of individual field-level problems.

Array<object> | null
object
field
required

The field that caused the error, in dot notation.

string
code

A machine-readable code for this specific validation issue.

string
message
required

A human-readable explanation.

string
Example
{
"error": {
"code": "validation.required_field",
"message": "The request body is missing required fields.",
"doc_url": "https://docs.sending.ac/errors/validation-required-field",
"details": [
{
"field": "email",
"code": "validation.required_field",
"message": "This field is required."
}
]
}
}

Authentication failed. The API key is missing or invalid.

Media typeapplication/json
object
error
required
object
code
required

A machine-readable error code.

string
Allowed values: auth.missing_key auth.invalid_key auth.insufficient_scope rate.quota_exceeded validation.required_field validation.invalid_value resource.not_found resource.already_exists resource.not_ready server.error
message
required

A human-readable explanation of the error.

string
doc_url

A link to the documentation page for this error code.

string format: uri
details

For validation errors, a list of individual field-level problems.

Array<object> | null
object
field
required

The field that caused the error, in dot notation.

string
code

A machine-readable code for this specific validation issue.

string
message
required

A human-readable explanation.

string
Examples

No API key provided

{
"error": {
"code": "auth.missing_key",
"message": "No API key was provided. Include your key in the Authorization header: Bearer sac_live_xxxxx.",
"doc_url": "https://docs.sending.ac/errors/auth-missing-key"
}
}

The API key does not have the required scope for this operation.

Media typeapplication/json
object
error
required
object
code
required

A machine-readable error code.

string
Allowed values: auth.missing_key auth.invalid_key auth.insufficient_scope rate.quota_exceeded validation.required_field validation.invalid_value resource.not_found resource.already_exists resource.not_ready server.error
message
required

A human-readable explanation of the error.

string
doc_url

A link to the documentation page for this error code.

string format: uri
details

For validation errors, a list of individual field-level problems.

Array<object> | null
object
field
required

The field that caused the error, in dot notation.

string
code

A machine-readable code for this specific validation issue.

string
message
required

A human-readable explanation.

string
Example
{
"error": {
"code": "auth.insufficient_scope",
"message": "Your API key does not have the 'senders:write' scope required for this operation.",
"doc_url": "https://docs.sending.ac/errors/auth-insufficient-scope"
}
}

You have exceeded the rate limit. Wait and retry.

Media typeapplication/json
object
error
required
object
code
required

A machine-readable error code.

string
Allowed values: auth.missing_key auth.invalid_key auth.insufficient_scope rate.quota_exceeded validation.required_field validation.invalid_value resource.not_found resource.already_exists resource.not_ready server.error
message
required

A human-readable explanation of the error.

string
doc_url

A link to the documentation page for this error code.

string format: uri
details

For validation errors, a list of individual field-level problems.

Array<object> | null
object
field
required

The field that caused the error, in dot notation.

string
code

A machine-readable code for this specific validation issue.

string
message
required

A human-readable explanation.

string
Example
{
"error": {
"code": "rate.quota_exceeded",
"message": "Rate limit exceeded. You may make 120 requests per minute. Retry after 30 seconds.",
"doc_url": "https://docs.sending.ac/errors/rate-quota-exceeded"
}
}
Retry-After
integer
Example
30

Number of seconds to wait before retrying.

X-RateLimit-Limit
integer
Example
120

The maximum number of requests allowed per minute.

X-RateLimit-Remaining
integer
Example
0

The number of requests remaining in the current window.

X-RateLimit-Reset
integer
Example
1711267260

Unix timestamp when the rate limit window resets.