This is the full developer documentation for builders.ac # Build on sending.ac > API reference and guides for the sending.ac Mailbox API and Provisioning API. Two APIs. One sends and reads mail from mailboxes you already own; the other creates mailboxes for your own customers. They take different keys, and mixing them up is the most common first failure — so every page here says which one it belongs to. ## Send and read mail [Section titled “Send and read mail”](#send-and-read-mail) Point an unmodified Microsoft Graph SDK at our base URL. Your client, your code, your error handling — you change two values and nothing else. [Mailbox API](/api/mailbox/)v1alpha1Unstable * Base URL `https://api.customers.ac/api/mailbox/v1alpha1` * Key `sk_live_…`Scope mailbox, live only. Sandbox keys are refused. [Guide](/guides/mailbox-api/) · [Reference](/api/mailbox/) · 4 operations ## Provision mailboxes [Section titled “Provision mailboxes”](#provision-mailboxes) Create users, senders and domains for your end customers. The platform handles Microsoft 365 tenant setup, DNS and mailbox creation, and every write returns an operation you poll. [Provisioning API](/api/provisioning/)v1Internal testing * Base URL `https://live-api.customers.ac/v1` * Key `sac_live_… / sac_test_…`Scoped per operation. Sandbox provisions nothing. [Guide](/guides/provisioning-flow/) · [Reference](/api/provisioning/) · 17 operations ## Not sure which key you have? [Section titled “Not sure which key you have?”](#not-sure-which-key-you-have) [Authentication](/guides/authentication/) puts both key formats side by side and explains why the wrong one returns `403` rather than `401`. ## For agents [Section titled “For agents”](#for-agents) The whole site is available as plain text, and both OpenAPI documents are served directly. | | | | ------------------------------------------------------ | -------------------------------------------- | | [`/llms.txt`](/llms.txt) | index | | [`/llms-full.txt`](/llms-full.txt) | everything, including the complete reference | | [`/llms-small.txt`](/llms-small.txt) | prose only, for small context windows | | [`/specs/mailbox.json`](/specs/mailbox.json) | Mailbox API, OpenAPI 3.1 | | [`/specs/provisioning.json`](/specs/provisioning.json) | Provisioning API, OpenAPI 3.1 | # Guides > Task-oriented guides for the sending.ac Mailbox API and Provisioning API. sending.ac exposes two APIs. They serve different jobs and use different keys. ## Mailbox API [Section titled “Mailbox API”](#mailbox-api) Send and read mail from mailboxes you already own, using an **unmodified Microsoft Graph SDK**. Point your existing Graph client at our base URL, authenticate with a sending.ac key, and the rest of your code is unchanged. * [Send and read mail](/guides/mailbox-api/) — setup, sending, reading, paging, errors * [Reference](/api/mailbox/) — every operation ## Provisioning API [Section titled “Provisioning API”](#provisioning-api) Create users, senders, domains and mailboxes on behalf of your own customers. The platform handles Microsoft 365 tenant setup, DNS and mailbox creation. * [Provision mailboxes](/guides/provisioning-flow/) — the object model and the async path * [Reference](/api/provisioning/) — every operation Still in internal testing; access is granted case by case. ## Both [Section titled “Both”](#both) * [Authentication](/guides/authentication/) — the two key types, and why the wrong one returns `403` rather than `401` The raw OpenAPI documents are served at [`/specs/mailbox.json`](/specs/mailbox.json) and [`/specs/provisioning.json`](/specs/provisioning.json). # Authentication > The two sending.ac key types, how they differ, and why one is refused where the other works. sending.ac has two APIs and two kinds of key. They are not interchangeable, and using the wrong one is the most common first failure — it returns `403`, not `401`, because the key itself is valid. ## The two key types [Section titled “The two key types”](#the-two-key-types) | | Mailbox API | Provisioning API | | ------------ | ----------------------------------------------- | ---------------------------------- | | Prefix | `sk_live_…` | `sac_live_…` / `sac_test_…` | | Scope | `mailbox` | scoped per operation | | Environments | **live only** | live and sandbox | | Issued from | Production Credentials in the customer portal | the sending.ac partner dashboard | | Base URL | `https://api.customers.ac/api/mailbox/v1alpha1` | `https://live-api.customers.ac/v1` | Both are sent the same way: ```text Authorization: Bearer ``` ## Mailbox API keys [Section titled “Mailbox API keys”](#mailbox-api-keys) [Mailbox API](/api/mailbox/)v1alpha1Unstable * Base URL `https://api.customers.ac/api/mailbox/v1alpha1` * Key `sk_live_…`Scope mailbox, live only. Sandbox keys are refused. A Mailbox key must be **scope `mailbox`** and **environment `live`**. Both are enforced: * a Provisioning key returns `403` / `ErrorAccessDenied` * a sandbox key returns `403` / `ErrorAccessDenied` Sandbox keys are refused by design rather than downgraded to a mock. Every call touches a real Microsoft 365 mailbox, and `sendMail` delivers real mail to real recipients, so there is nothing sandbox-like to offer. Errors on this API use [Microsoft’s OData error shape](/api/mailbox/operations/sendmail/), not a sending.ac envelope, so a Graph SDK deserialises them as ordinary `GraphError`s. ## Provisioning API keys [Section titled “Provisioning API keys”](#provisioning-api-keys) [Provisioning API](/api/provisioning/)v1Internal testing * Base URL `https://live-api.customers.ac/v1` * Key `sac_live_… / sac_test_…`Scoped per operation. Sandbox provisions nothing. Provisioning tokens are scoped per operation. A request that needs a scope your token does not carry returns `403 auth.insufficient_scope`. Live keys begin with `sac_live_`, sandbox keys with `sac_test_`. Unlike the Mailbox API, sandbox is meaningful here: no real infrastructure is provisioned and operations complete instantly, which makes it useful for exercising the async flow without waiting on M365. Internal testing — not generally available The Provisioning API is still in internal testing. Endpoints and payloads may change without notice, and access is granted case by case. Treat the reference as a preview rather than a contract, and talk to us before building against it. ## Rate limits [Section titled “Rate limits”](#rate-limits) | API | Limit | On exceeding | | ------------ | ----------------------------- | ------------------------------------------------------------------------------------------- | | Mailbox | 60 requests/minute per key | `429` with `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` | | Provisioning | 120 requests/minute per token | `429 rate.quota_exceeded` with `Retry-After` | ## Which one do I want? [Section titled “Which one do I want?”](#which-one-do-i-want) * Sending or reading mail from a mailbox that already exists → **Mailbox API**. * Creating users, senders, domains or mailboxes on behalf of your own customers → **Provisioning API**. Most integrations that do both hold one of each. # Send and read mail > Send and read mail from your sending.ac mailboxes with an unmodified Microsoft Graph SDK. The Mailbox API lets you send and read mail from the mailboxes you own on sending.ac. It speaks Microsoft Graph, so if you already have a Graph client you keep it — you change the base URL and the credential, and nothing else. [Mailbox API](/api/mailbox/)v1alpha1Unstable * Base URL `https://api.customers.ac/api/mailbox/v1alpha1` * Key `sk_live_…`Scope mailbox, live only. Sandbox keys are refused. ## Before you start [Section titled “Before you start”](#before-you-start) You need a **Mailbox** key in the **live** environment. Create one under Production Credentials, choosing the Mailbox scope. Sandbox keys are refused These calls send and read real mail from real mailboxes, so there is no sandbox behaviour to offer. A sandbox key — or a Provisioning key — gets `403`. ## Base URL and auth [Section titled “Base URL and auth”](#base-url-and-auth) Every request goes to: ```text https://api.customers.ac/api/mailbox/v1alpha1 ``` The Graph surface lives under `/azure/v1.0`. Authenticate with your key as a bearer token: ```text Authorization: Bearer sk_live_xxxxxxxx ``` Mind the /api prefix Dropping `/api` is the most common setup mistake and returns `404` for everything. ## Point your client at us [Section titled “Point your client at us”](#point-your-client-at-us) Most Graph SDKs only attach the bearer token to hosts they trust. Pointed at another base URL they send the request unauthenticated, and you get a `401` that looks like a bad key. Tell the SDK to trust our host: ```javascript import { Client } from '@microsoft/microsoft-graph-client'; const client = Client.init({ baseUrl: 'https://api.customers.ac/api/mailbox/v1alpha1/azure', defaultVersion: 'v1.0', authProvider: (done) => done(null, 'sk_live_xxxxxxxx'), // Required. Without this the SDK omits your key and every call returns 401. customHosts: new Set(['api.customers.ac']), }); ``` ```csharp var http = new HttpClient { BaseAddress = new Uri("https://api.customers.ac/api/mailbox/v1alpha1/azure/v1.0") }; // Allow the credential to be sent to our host, as customHosts does in the JS SDK. var graph = new GraphServiceClient(http, new StaticTokenProvider("sk_live_xxxxxxxx")); ``` HTTPS only Graph SDKs refuse to authenticate over plain `http://`, so you cannot point one at a non-TLS host for local testing. ## Send an email [Section titled “Send an email”](#send-an-email) `sendMail` takes Graph’s own payload and returns `202 Accepted` with an empty body once Microsoft accepts the message. Full request schema in [the reference](/api/mailbox/operations/sendmail/). ```bash curl -X POST \ https://api.customers.ac/api/mailbox/v1alpha1/azure/v1.0/users/alice@acme.com/sendMail \ -H "Authorization: Bearer sk_live_xxxxxxxx" \ -H "Content-Type: application/json" \ -d '{"message":{"subject":"Hi","body":{"contentType":"Text","content":"hello"}, "toRecipients":[{"emailAddress":{"address":"lead@example.com"}}]}}' ``` ```javascript await client.api('/users/alice@acme.com/sendMail').post({ message: { subject: 'Hi', body: { contentType: 'Text', content: 'hello' }, toRecipients: [{ emailAddress: { address: 'lead@example.com' } }], }, saveToSentItems: true, }); ``` Never retry a send automatically `202` means accepted for delivery, not delivered. If a send fails at the transport layer we return `502` and do **not** retry, because Microsoft may already have accepted and sent the message. Treat a `502` here as *unknown*, not *failed*, and only retry if sending twice is acceptable. ## Read mail [Section titled “Read mail”](#read-mail) List messages with the OData parameters you already use — `$select`, `$filter`, `$top`, `$orderby` — forwarded to Microsoft untouched. ```javascript const inbox = await client .api('/users/alice@acme.com/messages') .select('id,subject,from,receivedDateTime') .top(25) .get(); ``` ```bash curl -G \ https://api.customers.ac/api/mailbox/v1alpha1/azure/v1.0/users/alice@acme.com/messages \ -H "Authorization: Bearer sk_live_xxxxxxxx" \ --data-urlencode '$select=id,subject,from,receivedDateTime' \ --data-urlencode '$top=25' ``` Always send `$select`. The default projection is large, and message bodies dominate the response. Every supported parameter is listed under [List messages](/api/mailbox/operations/listmessages/). ## Paging [Section titled “Paging”](#paging) We rewrite `@odata.nextLink` to point back at us, so page iterators work unchanged and you never receive a raw `graph.microsoft.com` link that your key could not authenticate against. ```javascript import { PageIterator } from '@microsoft/microsoft-graph-client'; const first = await client.api('/users/alice@acme.com/messages').top(25).get(); await new PageIterator(client, first, (message) => { console.log(message.subject); return true; }).iterate(); ``` ## What you can call [Section titled “What you can call”](#what-you-can-call) The proxy runs a strict allow-list. These four routes are reachable; anything else returns `404` even if it exists in Graph. | Method | Path | | ------ | ------------------------------------------------------------------------ | | `POST` | [`/users/{email}/sendMail`](/api/mailbox/operations/sendmail/) | | `GET` | [`/users/{email}/messages`](/api/mailbox/operations/listmessages/) | | `GET` | [`/users/{email}/messages/{id}`](/api/mailbox/operations/getmessage/) | | `GET` | [`/users/{email}/mailFolders`](/api/mailbox/operations/listmailfolders/) | You can only address mailboxes belonging to your account. A mailbox that is not yours returns `404` rather than `403`, so the API never confirms which addresses exist. A supported path with the wrong method returns `405`. ## Errors [Section titled “Errors”](#errors) Errors on the Graph surface come back in **Microsoft’s own format**, including errors we raise ourselves, so your existing Graph error handling keeps working. ```json { "error": { "code": "ResourceNotFound", "message": "No such mailbox.", "innerError": { "request-id": "…", "date": "…" } } } ``` | Status | Meaning | | ------ | --------------------------------------------------------------------------------- | | `401` | Missing or invalid API key, or the key was revoked. | | `403` | Valid key, but not a live Mailbox key — a Provisioning or sandbox key lands here. | | `404` | Unknown mailbox or path, including a mailbox that is not yours. | | `405` | Supported path, unsupported method. | | `413` | Request body above 10 MB. | | `429` | Rate limit exceeded. See `Retry-After`. | | `502` | We could not reach Microsoft. Ambiguous for sends. | | `503` | Temporarily unavailable. Safe to retry with backoff. | ## Rate limits [Section titled “Rate limits”](#rate-limits) 60 requests per minute per API key. Going over returns `429` with `Retry-After` and `X-RateLimit-*` headers — wait the number of seconds given and try again. Microsoft’s own throttling is passed through with its headers intact, so your SDK’s built-in backoff keeps working. ## Not available yet [Section titled “Not available yet”](#not-available-yet) Two things are planned and appear in the API reference so you can see them coming, but there is nothing to call today: * **Events and webhooks** — a feed of delivery and engagement activity across your mailboxes, plus push delivery. Until it ships, poll `messages` for the mailboxes you care about. Shape preview under [Events](/api/mailbox/operations/tags/events/). * **Gmail** — reserved under a `/google/` prefix, which answers `501` so you can detect it deliberately. Only Microsoft 365 mailboxes work today. v1alpha1 is unstable Endpoints, payloads and error codes can change without notice and without a version bump. Do not build anything you cannot redeploy. ## Getting help [Section titled “Getting help”](#getting-help) When something goes wrong, quote the `x-correlation-id` response header — the same value appears as `request-id` inside our error bodies. It identifies the exact request, including Microsoft’s own id from `x-ms-request-id`, which is what we need to escalate on your behalf. # Provision mailboxes > How a user becomes a sender, a connected domain and working mailboxes on the Provisioning API. Internal testing — not generally available The Provisioning API is still in internal testing. Endpoints and payloads may change without notice, and access is granted case by case. Treat this guide and the reference as a preview rather than a contract, and talk to us before building against it. The Provisioning API lets integration partners white-label mailbox provisioning for their own end customers. You create senders and connect domains; the platform handles Microsoft 365 tenant setup, DNS configuration and mailbox creation. [Provisioning API](/api/provisioning/)v1Internal testing * Base URL `https://live-api.customers.ac/v1` * Key `sac_live_… / sac_test_…`Scoped per operation. Sandbox provisions nothing. ## The object model [Section titled “The object model”](#the-object-model) | Object | What it is | | ------------- | ------------------------------------------------------------------------ | | **User** | an end customer on your platform | | **Sender** | a logical grouping of domains and mailboxes belonging to a user | | **Domain** | a domain connected to the platform | | **Mailbox** | an individual email account with IMAP/SMTP credentials | | **Operation** | every write returns an `operation_id` you can poll or receive by webhook | ## Everything is asynchronous [Section titled “Everything is asynchronous”](#everything-is-asynchronous) A `POST` that triggers infrastructure changes returns immediately with `status: "pending"` and an `operation_id`. It has not happened yet. Poll [`GET /operations/{id}`](/api/provisioning/operations/getoperation/) to track progress, or take the webhook. This is the part most integrations get wrong: treating the `201` as completion. The mailbox does not exist until the operation says so. ## The path through [Section titled “The path through”](#the-path-through) 1. **Create a user** — [`POST /users`](/api/provisioning/operations/createuser/) — one per end customer on your platform. 2. **Create a sender** — [`POST /senders`](/api/provisioning/operations/createsender/) — the grouping that domains and mailboxes hang off. 3. **Connect a domain.** The platform assigns nameservers in response. 4. **Update the registrar** with those nameservers, then wait for propagation — **up to 48 hours**. Nothing you can do shortens this. 5. **M365 is provisioned automatically** once propagation completes. You do not call anything to trigger it. 6. **Read the mailboxes** — [`GET /senders/{id}/mailboxes`](/api/provisioning/operations/listmailboxes/) — and their [credentials](/api/provisioning/operations/getmailboxcredentials/) when you need IMAP/SMTP details. Step 4 is the long pole and it is outside the API. Design your onboarding so a customer can leave and come back rather than watching a spinner. ## Pagination [Section titled “Pagination”](#pagination) List endpoints are cursor-based. Pass `page[size]` (max 100, default 25) and `page[after]`, an opaque cursor taken from a previous response. ## Tearing down [Section titled “Tearing down”](#tearing-down) Deprovisioning is explicit and separate per level: * [`DELETE /senders/{id}`](/api/provisioning/operations/deprovisionsender/) * [`DELETE /domains/{id}`](/api/provisioning/operations/deprovisiondomain/) Both are writes, so both return an `operation_id` and complete asynchronously like everything else. ## Sandbox [Section titled “Sandbox”](#sandbox) Sandbox keys (`sac_test_…`) run against `https://sandbox-api.customers.ac/v1`, where no real infrastructure is provisioned and operations complete instantly. That makes it the right place to exercise the async polling flow without waiting on DNS propagation or M365. ## Webhooks [Section titled “Webhooks”](#webhooks) Not documented yet The spec says an operation result can be “received via webhook”, but does not describe how a subscription is registered or what the payload looks like. Rather than guess, this guide leaves it out. Poll [`GET /operations/{id}`](/api/provisioning/operations/getoperation/) and talk to us if you need push delivery. # Mailbox API ## Overview Source: https://docs.builders.ac/api/mailbox/ A drop-in Microsoft Graph proxy for mailboxes you provisioned through sending.ac. ## sending.ac Mailbox API v1alpha1 [Section titled “sending.ac Mailbox API v1alpha1”](#overview) The Mailbox API lets you send and read mail from mailboxes you own on sending.ac, using **an unmodified Microsoft Graph SDK**. Point your Graph client at this base URL and authenticate with a sending.ac API key. We handle the rest. ## Stability `v1alpha1` is explicitly **unstable**. Endpoints, payloads and error codes may change without notice and without a version bump. Do not build anything you cannot redeploy. ## Authentication Send your key as a bearer token: ``` Authorization: Bearer sk_live_xxxxxxxxxxxx ``` The key must be **scope `mailbox`** and **environment `live`**. Both are enforced: * a Provisioning key returns `403` / `ErrorAccessDenied` * a sandbox key returns `403` / `ErrorAccessDenied` Sandbox keys are refused by design rather than downgraded to a mock. Every call here touches a real Microsoft 365 mailbox and `sendMail` delivers real mail to real recipients, so there is nothing sandbox-like to offer. Mint a Mailbox key under **Production Credentials** in the customer portal. ## Using a Microsoft Graph SDK The `/azure` surface mirrors Graph’s own URL layout, so an official SDK works unchanged — but two settings are mandatory: ``` import { Client } from '@microsoft/microsoft-graph-client'; const client = Client.init({ baseUrl: 'https://api.customers.ac/api/mailbox/v1alpha1/azure', defaultVersion: 'v1.0', authProvider: (done) => done(null, 'sk_live_xxxxxxxxxxxx'), // Required: the SDK only attaches the Authorization header to hosts it trusts. // Without this your requests arrive unauthenticated and fail with 401. customHosts: new Set(['api.customers.ac']), }); await client.api('/users/sender@yourdomain.com/sendMail').post({ message, saveToSentItems: true }); ``` The SDK also refuses to authenticate over plain `http://`, so there is no way to point it at a non-TLS host for testing. ## Paging `@odata.nextLink` in responses is rewritten to point back at this API, so `PageIterator` and equivalent helpers follow pages through the proxy with the same API key. You never receive a raw `graph.microsoft.com` link. ## Error format Errors on `/azure` and `/google` use **Microsoft’s OData error shape**, not a sending.ac envelope, so Graph SDKs deserialise them as ordinary `GraphError`s: ``` { "error": { "code": "InvalidAuthenticationToken", "message": "The API key is invalid or has been revoked.", "innerError": { "request-id": "…", "date": "…" } } } ``` `innerError.request-id` is the correlation id for the request. Quote it in support requests. ## Rate limits 60 requests per minute per API key on the Graph surface. Exceeding it returns `429` with `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`. ## Retries `sendMail` is **never retried automatically** on a transport error, because the failure is ambiguous — Microsoft may already have accepted and delivered the message. Retry it yourself only if a duplicate send is acceptable. Read-only calls are safe to retry. sending.ac support * Information * OpenAPI version: `3.1.0` ## Operations [Section titled “Operations”](#operations) GET [/](/api/mailbox/operations/getserviceroot/) POST [/azure/v1.0/users/{email}/sendMail](/api/mailbox/operations/sendmail/) GET [/azure/v1.0/users/{email}/messages](/api/mailbox/operations/listmessages/) GET [/azure/v1.0/users/{email}/messages/{id}](/api/mailbox/operations/getmessage/) GET [/azure/v1.0/users/{email}/mailFolders](/api/mailbox/operations/listmailfolders/) GET [/events](/api/mailbox/operations/listeventsnotyetavailable/) POST [/events/subscriptions](/api/mailbox/operations/createeventsubscriptionnotyetavailable/) GET [/google/v1/{path}](/api/mailbox/operations/googleproxynotimplemented/) ## Authentication [Section titled “Authentication”](#authentication) ### BearerAuth [Section titled “BearerAuth”](#bearerauth) A sending.ac API key with scope `mailbox` and environment `live`. Issue one under **Production Credentials** in the customer portal. Provisioning keys and sandbox keys are rejected with `403`. **Security scheme type:** http ## Overview Source: https://docs.builders.ac/api/mailbox/operations/tags/events/ ## Events [Section titled “Events”](#overview) **Not yet available.** Delivery and engagement events are planned for a future `v1alpha` revision and are documented here only so you can see what is coming. There is no endpoint to call today — the paths below are not routed and will return `404`. Until this ships, read mail state with `GET /users/{email}/messages`. ## Operations [Section titled “Operations”](#operations) GET [/events](/api/mailbox/operations/listeventsnotyetavailable/) POST [/events/subscriptions](/api/mailbox/operations/createeventsubscriptionnotyetavailable/) ## Overview Source: https://docs.builders.ac/api/mailbox/operations/tags/google-workspace/ ## Google Workspace [Section titled “Google Workspace”](#overview) **Not yet available.** The route is reserved and answers `501` so client code can detect it deliberately rather than by guessing. Only Microsoft 365 mailboxes are supported. ## Operations [Section titled “Operations”](#operations) GET [/google/v1/{path}](/api/mailbox/operations/googleproxynotimplemented/) ## Overview Source: https://docs.builders.ac/api/mailbox/operations/tags/mail/ ## Mail [Section titled “Mail”](#overview) The Microsoft Graph surface. Only the operations listed here are reachable — the proxy runs a strict allow-list, so any other Graph path returns `404` even if it exists upstream. The `{email}` in each path must be a mailbox owned by the account the API key belongs to. A mailbox you do not own returns `404`, not `403`, so the API never reveals which addresses are sending.ac mailboxes. ## Operations [Section titled “Operations”](#operations) POST [/azure/v1.0/users/{email}/sendMail](/api/mailbox/operations/sendmail/) GET [/azure/v1.0/users/{email}/messages](/api/mailbox/operations/listmessages/) GET [/azure/v1.0/users/{email}/messages/{id}](/api/mailbox/operations/getmessage/) GET [/azure/v1.0/users/{email}/mailFolders](/api/mailbox/operations/listmailfolders/) ## Overview Source: https://docs.builders.ac/api/mailbox/operations/tags/service/ ## Service [Section titled “Service”](#overview) Service metadata. ## Operations [Section titled “Operations”](#operations) GET [/](/api/mailbox/operations/getserviceroot/) ## Create an event webhook subscription — NOT YET AVAILABLE Source: https://docs.builders.ac/api/mailbox/operations/createeventsubscriptionnotyetavailable/ Deprecated POST /events/subscriptions Select code sampleFetchcURL ``` const url = 'https://api.customers.ac/api/mailbox/v1alpha1/events/subscriptions';const options = {method: 'POST', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request POST \ --url https://api.customers.ac/api/mailbox/v1alpha1/events/subscriptions \ --header 'Authorization: Bearer ' ``` * Production. Note the /api prefix — omitting it returns 404. > **Not yet available.** This endpoint is not routed. Calling it today returns `404`. Planned: push delivery of the same events as `GET /events`, so you can react without polling. No request or response shape is committed yet. Do not implement against it. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/mailbox/#bearerauth)** ## Responses [Section titled “Responses”](#responses) ### 404 [Section titled “404”](#404) Not routed. This endpoint does not exist yet. Media typeapplication/json _sending.ac error_ The envelope used outside the provider-native surfaces. object **error** required object **code** required string **message** required string ##### Example ``` { "error": { "code": "service.unavailable" }} ``` ## Get a message Source: https://docs.builders.ac/api/mailbox/operations/getmessage/ GET /azure/v1.0/users/{email}/messages/{id} Select code sampleFetchcURL ``` const url = 'https://api.customers.ac/api/mailbox/v1alpha1/azure/v1.0/users/sender%40yourdomain.com/messages/example?%24select=id%2Csubject%2Cbody%2Cfrom%2CtoRecipients%2CreceivedDateTime';const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request GET \ --url 'https://api.customers.ac/api/mailbox/v1alpha1/azure/v1.0/users/sender%40yourdomain.com/messages/example?%24select=id%2Csubject%2Cbody%2Cfrom%2CtoRecipients%2CreceivedDateTime' \ --header 'Authorization: Bearer ' ``` * Production. Note the /api prefix — omitting it returns 404. Fetches a single message by id. Mirrors Graph’s [GET /users/{id}/messages/{message-id}](https://learn.microsoft.com/graph/api/message-get). Use the `id` returned by **List messages**. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/mailbox/#bearerauth)** ## Parameters [Section titled “Parameters”](#parameters) ### Path Parameters [Section titled “Path Parameters”](#path-parameters) **email** required string format: email The mailbox address, which must belong to the account owning the API key. A mailbox that exists but is not yours returns `404` rather than `403`, so this endpoint cannot be used to discover which addresses are sending.ac mailboxes. ##### Example ``` sender@yourdomain.com ``` **id** required string Graph message id. Opaque and forwarded byte-for-byte — do not decode or re-encode it, as ids routinely contain `=`, `+` and `/`. ### Query Parameters [Section titled “Query Parameters”](#query-parameters) **$select** string ##### Example ``` id,subject,body,from,toRecipients,receivedDateTime ``` ## Responses [Section titled “Responses”](#responses) ### 200 [Section titled “200”](#200) The message. Media typeapplication/json A Graph message. Only commonly used properties are listed; the full Graph resource is returned and accepted. object **id** Opaque message id. Forward it byte-for-byte — ids contain `=`, `+` and `/`. string **subject** string **body** object **contentType** string default: text Allowed values: text html **content** required string **bodyPreview** string **from** object **emailAddress** required object **name** string **address** required string format: email **toRecipients** Array object **emailAddress** required object **name** string **address** required string format: email **ccRecipients** Array object **emailAddress** required object **name** string **address** required string format: email **receivedDateTime** string format: date-time **sentDateTime** string format: date-time **isRead** boolean **hasAttachments** boolean **conversationId** string **internetMessageId** string ##### Example ``` { "body": { "contentType": "text" }, "from": { "emailAddress": { "name": "Jane Doe", "address": "jane@example.com" } }, "toRecipients": [ { "emailAddress": { "name": "Jane Doe", "address": "jane@example.com" } } ], "ccRecipients": [ { "emailAddress": { "name": "Jane Doe", "address": "jane@example.com" } } ]} ``` #### Headers [Section titled “Headers”](#headers) **x-ms-request-id** string Microsoft’s own request id for the upstream call. Quote this when raising an issue with Microsoft support. (Graph returns it as `request-id`; it is re-emitted under this name because `Request-ID` is already used for our own request identifier.) ### 401 [Section titled “401”](#401) Missing or invalid API key. Also returned when the key has been revoked. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "InvalidAuthenticationToken", "message": "The API key is invalid or has been revoked.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` ### 403 [Section titled “403”](#403) The key is valid but not usable here: it is a Provisioning key rather than a Mailbox key, it is a sandbox key, or it is not linked to a sending.ac account. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "ErrorAccessDenied", "message": "The Mailbox API requires a live API key; sandbox keys are not accepted because these calls send and read real mail.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` ### 404 [Section titled “404”](#404) Either the mailbox is not yours (or does not exist), or the Graph path is outside the allow-list. Both answer `404` so the API does not disclose which. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "ResourceNotFound", "message": "No such mailbox.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` ### 429 [Section titled “429”](#429) Rate limit exceeded — 60 requests per minute per API key. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "TooManyRequests", "message": "Too many requests. Retry after the number of seconds in Retry-After.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` #### Headers [Section titled “Headers”](#headers) **Retry-After** integer Seconds to wait before retrying. **X-RateLimit-Limit** integer **X-RateLimit-Remaining** integer **X-RateLimit-Reset** integer Unix timestamp at which the window resets. ### 502 [Section titled “502”](#502) Microsoft Graph could not be reached, or its response was too large to relay. For `sendMail` this is **ambiguous**: the message may already have been accepted and sent. Do not retry automatically. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "UnknownError", "message": "Could not reach Microsoft Graph. The request may not have been processed; retry only if it is safe to repeat.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` ### 503 [Section titled “503”](#503) The Mailbox API is temporarily unavailable, or credentials could not be verified. Safe to retry with backoff. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "BadRequest" }} ``` ## Service root Source: https://docs.builders.ac/api/mailbox/operations/getserviceroot/ GET / Select code sampleFetchcURL ``` const url = 'https://api.customers.ac/api/mailbox/v1alpha1/';const options = {method: 'GET'}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request GET \ --url https://api.customers.ac/api/mailbox/v1alpha1/ ``` * Production. Note the /api prefix — omitting it returns 404. Returns service metadata. This is the only unauthenticated endpoint — useful as a reachability check before you debug credentials. ## Responses [Section titled “Responses”](#responses) ### 200 [Section titled “200”](#200) Service metadata. Media typeapplication/json object **service** string **version** string **status** string ##### Example ``` { "service": "mailbox-api", "version": "v1alpha1", "status": "alpha"} ``` ## Gmail proxy — NOT YET AVAILABLE Source: https://docs.builders.ac/api/mailbox/operations/googleproxynotimplemented/ Deprecated GET /google/v1/{path} Select code sampleFetchcURL ``` const url = 'https://api.customers.ac/api/mailbox/v1alpha1/google/v1/example';const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request GET \ --url https://api.customers.ac/api/mailbox/v1alpha1/google/v1/example \ --header 'Authorization: Bearer ' ``` * Production. Note the /api prefix — omitting it returns 404. > **Not yet available.** Reserved for a Gmail equivalent of the `/azure` surface. Unlike the Events paths, this one **is** routed and deliberately answers `501` so client code can distinguish “not supported yet” from “wrong URL”. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/mailbox/#bearerauth)** ## Parameters [Section titled “Parameters”](#parameters) ### Path Parameters [Section titled “Path Parameters”](#path-parameters) **path** required string ## Responses [Section titled “Responses”](#responses) ### 501 [Section titled “501”](#501) Google Workspace mailboxes are not available through the Mailbox API yet. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "BadRequest" }} ``` ## List mailbox events — NOT YET AVAILABLE Source: https://docs.builders.ac/api/mailbox/operations/listeventsnotyetavailable/ Deprecated GET /events Select code sampleFetchcURL ``` const url = 'https://api.customers.ac/api/mailbox/v1alpha1/events';const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request GET \ --url https://api.customers.ac/api/mailbox/v1alpha1/events \ --header 'Authorization: Bearer ' ``` * Production. Note the /api prefix — omitting it returns 404. > **Not yet available.** This endpoint is not routed. Calling it today returns `404`. Planned: a pollable feed of delivery and engagement events (sent, delivered, bounced, opened, replied) across the mailboxes you own, so you do not have to poll each mailbox’s messages to detect state changes. When it ships it will carry a tighter rate limit than the Graph surface — 10 requests per minute per key rather than 60 — because it is a substantially heavier query. No request or response shape is committed yet; treat everything about this operation as subject to change. Do not implement against it. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/mailbox/#bearerauth)** ## Responses [Section titled “Responses”](#responses) ### 404 [Section titled “404”](#404) Not routed. This endpoint does not exist yet. Media typeapplication/json _sending.ac error_ The envelope used outside the provider-native surfaces. object **error** required object **code** required string **message** required string ##### Example ``` { "error": { "code": "service.unavailable" }} ``` ## List mail folders Source: https://docs.builders.ac/api/mailbox/operations/listmailfolders/ GET /azure/v1.0/users/{email}/mailFolders Select code sampleFetchcURL ``` const url = 'https://api.customers.ac/api/mailbox/v1alpha1/azure/v1.0/users/sender%40yourdomain.com/mailFolders';const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request GET \ --url https://api.customers.ac/api/mailbox/v1alpha1/azure/v1.0/users/sender%40yourdomain.com/mailFolders \ --header 'Authorization: Bearer ' ``` * Production. Note the /api prefix — omitting it returns 404. Lists the mailbox’s folders. Mirrors Graph’s [GET /users/{id}/mailFolders](https://learn.microsoft.com/graph/api/user-list-mailfolders). Use this to discover folder ids and to read `totalItemCount` / `unreadItemCount` without pulling messages. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/mailbox/#bearerauth)** ## Parameters [Section titled “Parameters”](#parameters) ### Path Parameters [Section titled “Path Parameters”](#path-parameters) **email** required string format: email The mailbox address, which must belong to the account owning the API key. A mailbox that exists but is not yours returns `404` rather than `403`, so this endpoint cannot be used to discover which addresses are sending.ac mailboxes. ##### Example ``` sender@yourdomain.com ``` ## Responses [Section titled “Responses”](#responses) ### 200 [Section titled “200”](#200) A page of mail folders. Media typeapplication/json object **value** Array object **id** string **displayName** string **parentFolderId** string **childFolderCount** integer **unreadItemCount** integer **totalItemCount** integer **@odata.nextLink** string format: uri ##### Example ``` { "value": [ { "displayName": "Inbox" } ]} ``` #### Headers [Section titled “Headers”](#headers) **x-ms-request-id** string Microsoft’s own request id for the upstream call. Quote this when raising an issue with Microsoft support. (Graph returns it as `request-id`; it is re-emitted under this name because `Request-ID` is already used for our own request identifier.) ### 401 [Section titled “401”](#401) Missing or invalid API key. Also returned when the key has been revoked. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "InvalidAuthenticationToken", "message": "The API key is invalid or has been revoked.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` ### 403 [Section titled “403”](#403) The key is valid but not usable here: it is a Provisioning key rather than a Mailbox key, it is a sandbox key, or it is not linked to a sending.ac account. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "ErrorAccessDenied", "message": "The Mailbox API requires a live API key; sandbox keys are not accepted because these calls send and read real mail.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` ### 404 [Section titled “404”](#404) Either the mailbox is not yours (or does not exist), or the Graph path is outside the allow-list. Both answer `404` so the API does not disclose which. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "ResourceNotFound", "message": "No such mailbox.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` ### 429 [Section titled “429”](#429) Rate limit exceeded — 60 requests per minute per API key. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "TooManyRequests", "message": "Too many requests. Retry after the number of seconds in Retry-After.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` #### Headers [Section titled “Headers”](#headers) **Retry-After** integer Seconds to wait before retrying. **X-RateLimit-Limit** integer **X-RateLimit-Remaining** integer **X-RateLimit-Reset** integer Unix timestamp at which the window resets. ### 502 [Section titled “502”](#502) Microsoft Graph could not be reached, or its response was too large to relay. For `sendMail` this is **ambiguous**: the message may already have been accepted and sent. Do not retry automatically. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "UnknownError", "message": "Could not reach Microsoft Graph. The request may not have been processed; retry only if it is safe to repeat.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` ### 503 [Section titled “503”](#503) The Mailbox API is temporarily unavailable, or credentials could not be verified. Safe to retry with backoff. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "BadRequest" }} ``` ## List messages Source: https://docs.builders.ac/api/mailbox/operations/listmessages/ GET /azure/v1.0/users/{email}/messages Select code sampleFetchcURL ``` const url = 'https://api.customers.ac/api/mailbox/v1alpha1/azure/v1.0/users/sender%40yourdomain.com/messages?%24select=id%2Csubject%2Cfrom%2CreceivedDateTime%2CisRead&%24filter=receivedDateTime%20ge%202026-07-01T00%3A00%3A00Z&%24top=25&%24orderby=receivedDateTime%20desc';const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request GET \ --url 'https://api.customers.ac/api/mailbox/v1alpha1/azure/v1.0/users/sender%40yourdomain.com/messages?%24select=id%2Csubject%2Cfrom%2CreceivedDateTime%2CisRead&%24filter=receivedDateTime%20ge%202026-07-01T00%3A00%3A00Z&%24top=25&%24orderby=receivedDateTime%20desc' \ --header 'Authorization: Bearer ' ``` * Production. Note the /api prefix — omitting it returns 404. Lists messages in the mailbox. Mirrors Graph’s [GET /users/{id}/messages](https://learn.microsoft.com/graph/api/user-list-messages). OData query parameters are forwarded to Microsoft untouched, so `$select`, `$filter`, `$top`, `$orderby` and `$search` behave exactly as they do against Graph directly. `$search` additionally requires the `ConsistencyLevel: eventual` header, which is one of the headers the proxy forwards. `@odata.nextLink` in the response is rewritten to this API, so SDK page iterators work unchanged. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/mailbox/#bearerauth)** ## Parameters [Section titled “Parameters”](#parameters) ### Path Parameters [Section titled “Path Parameters”](#path-parameters) **email** required string format: email The mailbox address, which must belong to the account owning the API key. A mailbox that exists but is not yours returns `404` rather than `403`, so this endpoint cannot be used to discover which addresses are sending.ac mailboxes. ##### Example ``` sender@yourdomain.com ``` ### Query Parameters [Section titled “Query Parameters”](#query-parameters) **$select** string Comma-separated properties to return. Strongly recommended — the default projection is large. ##### Example ``` id,subject,from,receivedDateTime,isRead ``` **$filter** string OData filter expression. ##### Example ``` receivedDateTime ge 2026-07-01T00:00:00Z ``` **$top** integer \>= 1 <= 999 Page size. ##### Example ``` 25 ``` **$orderby** string ##### Example ``` receivedDateTime desc ``` ## Responses [Section titled “Responses”](#responses) ### 200 [Section titled “200”](#200) A page of messages. Media typeapplication/json object **value** Array A Graph message. Only commonly used properties are listed; the full Graph resource is returned and accepted. object **id** Opaque message id. Forward it byte-for-byte — ids contain `=`, `+` and `/`. string **subject** string **body** object **contentType** string default: text Allowed values: text html **content** required string **bodyPreview** string **from** object **emailAddress** required object **name** string **address** required string format: email **toRecipients** Array object **emailAddress** required object **name** string **address** required string format: email **ccRecipients** Array object **emailAddress** required object **name** string **address** required string format: email **receivedDateTime** string format: date-time **sentDateTime** string format: date-time **isRead** boolean **hasAttachments** boolean **conversationId** string **internetMessageId** string **@odata.nextLink** Link to the next page, rewritten to point at this API rather than graph.microsoft.com. Follow it with the same API key. string format: uri ##### Example ``` { "value": [ { "body": { "contentType": "text" }, "from": { "emailAddress": { "name": "Jane Doe", "address": "jane@example.com" } }, "toRecipients": [ { "emailAddress": { "name": "Jane Doe", "address": "jane@example.com" } } ], "ccRecipients": [ { "emailAddress": { "name": "Jane Doe", "address": "jane@example.com" } } ] } ]} ``` #### Headers [Section titled “Headers”](#headers) **x-ms-request-id** string Microsoft’s own request id for the upstream call. Quote this when raising an issue with Microsoft support. (Graph returns it as `request-id`; it is re-emitted under this name because `Request-ID` is already used for our own request identifier.) ### 400 [Section titled “400”](#400) Malformed request — for example an invalid OData query or a body Graph refused. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "BadRequest", "message": "The request is malformed or incorrect.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` ### 401 [Section titled “401”](#401) Missing or invalid API key. Also returned when the key has been revoked. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "InvalidAuthenticationToken", "message": "The API key is invalid or has been revoked.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` ### 403 [Section titled “403”](#403) The key is valid but not usable here: it is a Provisioning key rather than a Mailbox key, it is a sandbox key, or it is not linked to a sending.ac account. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "ErrorAccessDenied", "message": "The Mailbox API requires a live API key; sandbox keys are not accepted because these calls send and read real mail.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` ### 404 [Section titled “404”](#404) Either the mailbox is not yours (or does not exist), or the Graph path is outside the allow-list. Both answer `404` so the API does not disclose which. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "ResourceNotFound", "message": "No such mailbox.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` ### 429 [Section titled “429”](#429) Rate limit exceeded — 60 requests per minute per API key. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "TooManyRequests", "message": "Too many requests. Retry after the number of seconds in Retry-After.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` #### Headers [Section titled “Headers”](#headers) **Retry-After** integer Seconds to wait before retrying. **X-RateLimit-Limit** integer **X-RateLimit-Remaining** integer **X-RateLimit-Reset** integer Unix timestamp at which the window resets. ### 502 [Section titled “502”](#502) Microsoft Graph could not be reached, or its response was too large to relay. For `sendMail` this is **ambiguous**: the message may already have been accepted and sent. Do not retry automatically. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "UnknownError", "message": "Could not reach Microsoft Graph. The request may not have been processed; retry only if it is safe to repeat.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` ### 503 [Section titled “503”](#503) The Mailbox API is temporarily unavailable, or credentials could not be verified. Safe to retry with backoff. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "BadRequest" }} ``` ## Send mail Source: https://docs.builders.ac/api/mailbox/operations/sendmail/ POST /azure/v1.0/users/{email}/sendMail Select code sampleFetchcURL ``` const url = 'https://api.customers.ac/api/mailbox/v1alpha1/azure/v1.0/users/sender%40yourdomain.com/sendMail';const options = { method: 'POST', headers: {Authorization: 'Bearer ', 'Content-Type': 'application/json'}, body: '{"message":{"subject":"Following up","body":{"contentType":"html","content":"

Hi — following up on my last note.

"},"toRecipients":[{"emailAddress":{"address":"prospect@example.com"}}]},"saveToSentItems":true}'}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request POST \ --url https://api.customers.ac/api/mailbox/v1alpha1/azure/v1.0/users/sender%40yourdomain.com/sendMail \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "message": { "subject": "Following up", "body": { "contentType": "html", "content": "

Hi — following up on my last note.

" }, "toRecipients": [ { "emailAddress": { "address": "prospect@example.com" } } ] }, "saveToSentItems": true }' ``` * Production. Note the /api prefix — omitting it returns 404. Sends a message as the mailbox in the path. Mirrors Graph’s [POST /users/{id}/sendMail](https://learn.microsoft.com/graph/api/user-sendmail). Returns `202 Accepted` with an empty body once Microsoft has accepted the message — that is acceptance for delivery, not proof of delivery. **This operation is not retried for you.** If the forward to Graph fails at the transport layer, the request may still have been accepted and sent upstream, so the proxy surfaces `502` rather than risking a duplicate send. Treat a `502` here as _unknown_, not _failed_, and only retry if sending twice is acceptable. Bodies larger than 10 MB are rejected with `413` before any call to Microsoft. Graph itself rejects payloads over roughly 4 MB, so attachments should stay well below that. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/mailbox/#bearerauth)** ## Parameters [Section titled “Parameters”](#parameters) ### Path Parameters [Section titled “Path Parameters”](#path-parameters) **email** required string format: email The mailbox address, which must belong to the account owning the API key. A mailbox that exists but is not yours returns `404` rather than `403`, so this endpoint cannot be used to discover which addresses are sending.ac mailboxes. ##### Example ``` sender@yourdomain.com ``` ## Request Bodyrequired [Section titled “Request Bodyrequired”](#request-body) Media typeapplication/json Graph’s `sendMail` payload, passed through unchanged. object **message** required A Graph message. Only commonly used properties are listed; the full Graph resource is returned and accepted. object **id** Opaque message id. Forward it byte-for-byte — ids contain `=`, `+` and `/`. string **subject** string **body** object **contentType** string default: text Allowed values: text html **content** required string **bodyPreview** string **from** object **emailAddress** required object **name** string **address** required string format: email **toRecipients** Array object **emailAddress** required object **name** string **address** required string format: email **ccRecipients** Array object **emailAddress** required object **name** string **address** required string format: email **receivedDateTime** string format: date-time **sentDateTime** string format: date-time **isRead** boolean **hasAttachments** boolean **conversationId** string **internetMessageId** string **saveToSentItems** Whether to keep a copy in Sent Items. boolean default: true ## Responses [Section titled “Responses”](#responses) ### 202 [Section titled “202”](#202) Accepted by Microsoft for delivery. Empty body. #### Headers [Section titled “Headers”](#headers) **x-ms-request-id** string Microsoft’s own request id for the upstream call. Quote this when raising an issue with Microsoft support. (Graph returns it as `request-id`; it is re-emitted under this name because `Request-ID` is already used for our own request identifier.) ### 400 [Section titled “400”](#400) Malformed request — for example an invalid OData query or a body Graph refused. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "BadRequest", "message": "The request is malformed or incorrect.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` ### 401 [Section titled “401”](#401) Missing or invalid API key. Also returned when the key has been revoked. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "InvalidAuthenticationToken", "message": "The API key is invalid or has been revoked.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` ### 403 [Section titled “403”](#403) The key is valid but not usable here: it is a Provisioning key rather than a Mailbox key, it is a sandbox key, or it is not linked to a sending.ac account. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "ErrorAccessDenied", "message": "The Mailbox API requires a live API key; sandbox keys are not accepted because these calls send and read real mail.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` ### 404 [Section titled “404”](#404) Either the mailbox is not yours (or does not exist), or the Graph path is outside the allow-list. Both answer `404` so the API does not disclose which. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "ResourceNotFound", "message": "No such mailbox.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` ### 413 [Section titled “413”](#413) Request body above 10 MB. Rejected before any call to Microsoft. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "BadRequest" }} ``` ### 429 [Section titled “429”](#429) Rate limit exceeded — 60 requests per minute per API key. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "TooManyRequests", "message": "Too many requests. Retry after the number of seconds in Retry-After.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` #### Headers [Section titled “Headers”](#headers) **Retry-After** integer Seconds to wait before retrying. **X-RateLimit-Limit** integer **X-RateLimit-Remaining** integer **X-RateLimit-Reset** integer Unix timestamp at which the window resets. ### 502 [Section titled “502”](#502) Microsoft Graph could not be reached, or its response was too large to relay. For `sendMail` this is **ambiguous**: the message may already have been accepted and sent. Do not retry automatically. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "UnknownError", "message": "Could not reach Microsoft Graph. The request may not have been processed; retry only if it is safe to repeat.", "innerError": { "request-id": "a26397a7-04e1-4c8f", "date": "2026-07-31T08:24:57+00:00" } }} ``` ### 503 [Section titled “503”](#503) The Mailbox API is temporarily unavailable, or credentials could not be verified. Safe to retry with backoff. Media typeapplication/json _OData error_ Microsoft’s error shape, used on the `/azure` and `/google` surfaces so Graph SDKs deserialise failures as ordinary errors. object **error** required object **code** required Microsoft’s error code for the status. string Allowed values: BadRequest InvalidAuthenticationToken ErrorAccessDenied ResourceNotFound RequestNotSupported RequestEntityTooLarge TooManyRequests UnknownError NotImplemented ServiceUnavailable Timeout **message** required string **innerError** object **request-id** Correlation id for this request. Quote it in support requests. string **date** string format: date-time ##### Example ``` { "error": { "code": "BadRequest" }} ``` # Provisioning API ## Overview Source: https://docs.builders.ac/api/provisioning/ Provision and manage cold email infrastructure for your customers. ## sending.ac Partner API 1.0.0 [Section titled “sending.ac Partner API 1.0.0”](#overview) > **Internal testing — not generally available.**The Provisioning API is still in internal testing. Endpoints and payloads may change without notice, and access is granted case by case. Treat this reference as a preview rather than a contract, and talk to us before building against it. The sending.ac Partner API lets integration partners white-label mailbox provisioning for their end customers. You create senders, connect domains, and the platform handles Microsoft 365 tenant setup, DNS configuration, and mailbox creation automatically. ## Core concepts * **User** — an end customer on your platform. * **Sender** — a logical grouping of domains and mailboxes belonging to a user. * **Domain** — a domain connected to the platform. After you connect a domain, the platform assigns nameservers. Update the registrar, wait for propagation (up to 48 h), and the platform provisions M365 automatically. * **Mailbox** — an individual email account with IMAP/SMTP credentials. * **Operation** — every write request returns an `operation_id` you can poll or receive via webhook. ## Authentication All requests require a Bearer token in the `Authorization` header: ``` Authorization: Bearer sac_live_xxxxx ``` Tokens are scoped. A request that requires a scope your token does not have will return `403 auth.insufficient_scope`. ## Pagination List endpoints use cursor-based pagination. Pass `page[size]` (max 100, default 25) and `page[after]` (an opaque cursor from a previous response). ## Async provisioning All provisioning is asynchronous. A `POST` that triggers infrastructure changes returns immediately with `status: "pending"` and an `operation_id`. Poll `GET /v1/operations/{id}` to track progress. ## Rate limits The API enforces 120 requests per minute per token. Exceeding this returns `429 rate.quota_exceeded` with a `Retry-After` header. sending.ac Partner Support * * [partners@sending.ac](mailto:partners@sending.ac) Information * [Terms of Service](https://sending.ac/legal/terms) * License: [Proprietary](https://sending.ac/legal/api-license) * OpenAPI version: `3.1.0` ## Operations [Section titled “Operations”](#operations) GET [/users](/api/provisioning/operations/listusers/) POST [/users](/api/provisioning/operations/createuser/) GET [/users/{user\_id}](/api/provisioning/operations/getuser/) PATCH [/users/{user\_id}](/api/provisioning/operations/updateuser/) GET [/senders](/api/provisioning/operations/listsenders/) POST [/senders](/api/provisioning/operations/createsender/) GET [/senders/{sender\_id}](/api/provisioning/operations/getsender/) DELETE [/senders/{sender\_id}](/api/provisioning/operations/deprovisionsender/) PATCH [/senders/{sender\_id}](/api/provisioning/operations/updatesender/) GET [/senders/{sender\_id}/domains](/api/provisioning/operations/listdomains/) GET [/domains/{domain\_id}](/api/provisioning/operations/getdomain/) DELETE [/domains/{domain\_id}](/api/provisioning/operations/deprovisiondomain/) GET [/senders/{sender\_id}/mailboxes](/api/provisioning/operations/listmailboxes/) GET [/mailboxes/{mailbox\_id}](/api/provisioning/operations/getmailbox/) GET [/mailboxes/{mailbox\_id}/credentials](/api/provisioning/operations/getmailboxcredentials/) GET [/operations](/api/provisioning/operations/listoperations/) GET [/operations/{operation\_id}](/api/provisioning/operations/getoperation/) ## Authentication [Section titled “Authentication”](#authentication) ### BearerAuth [Section titled “BearerAuth”](#bearerauth) API key issued from the sending.ac partner dashboard. Live keys begin with `sac_live_`, sandbox keys with `sac_test_`. **Security scheme type:** http **Bearer format:** sac\_live\_xxxxx or sac\_test\_xxxxx ## Overview Source: https://docs.builders.ac/api/provisioning/operations/tags/domains/ ## Domains [Section titled “Domains”](#overview) Domains are specified when a sender is created and cannot be added afterwards. After creation, poll this endpoint or listen for webhooks to track nameserver assignments and provisioning status. ## Operations [Section titled “Operations”](#operations) GET [/senders/{sender\_id}/domains](/api/provisioning/operations/listdomains/) GET [/domains/{domain\_id}](/api/provisioning/operations/getdomain/) DELETE [/domains/{domain\_id}](/api/provisioning/operations/deprovisiondomain/) ## Overview Source: https://docs.builders.ac/api/provisioning/operations/tags/mailboxes/ ## Mailboxes [Section titled “Mailboxes”](#overview) List mailboxes and retrieve IMAP/SMTP credentials. ## Operations [Section titled “Operations”](#operations) GET [/senders/{sender\_id}/mailboxes](/api/provisioning/operations/listmailboxes/) GET [/mailboxes/{mailbox\_id}](/api/provisioning/operations/getmailbox/) GET [/mailboxes/{mailbox\_id}/credentials](/api/provisioning/operations/getmailboxcredentials/) ## Overview Source: https://docs.builders.ac/api/provisioning/operations/tags/operations/ ## Operations [Section titled “Operations”](#overview) Track the progress of asynchronous provisioning workflows. ## Operations [Section titled “Operations”](#operations) GET [/operations](/api/provisioning/operations/listoperations/) GET [/operations/{operation\_id}](/api/provisioning/operations/getoperation/) ## Overview Source: https://docs.builders.ac/api/provisioning/operations/tags/senders/ ## Senders [Section titled “Senders”](#overview) Group domains and mailboxes under a logical sender identity. ## Operations [Section titled “Operations”](#operations) GET [/senders](/api/provisioning/operations/listsenders/) POST [/senders](/api/provisioning/operations/createsender/) GET [/senders/{sender\_id}](/api/provisioning/operations/getsender/) DELETE [/senders/{sender\_id}](/api/provisioning/operations/deprovisionsender/) PATCH [/senders/{sender\_id}](/api/provisioning/operations/updatesender/) ## Overview Source: https://docs.builders.ac/api/provisioning/operations/tags/users/ ## Users [Section titled “Users”](#overview) Manage end customers on your platform. ## Operations [Section titled “Operations”](#operations) GET [/users](/api/provisioning/operations/listusers/) POST [/users](/api/provisioning/operations/createuser/) GET [/users/{user\_id}](/api/provisioning/operations/getuser/) PATCH [/users/{user\_id}](/api/provisioning/operations/updateuser/) ## Create a sender Source: https://docs.builders.ac/api/provisioning/operations/createsender/ POST /senders Select code sampleFetchcURL ``` const url = 'https://live-api.customers.ac/v1/senders';const options = { method: 'POST', headers: {Authorization: 'Bearer ', 'Content-Type': 'application/json'}, body: '{"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"}]}'}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request POST \ --url https://live-api.customers.ac/v1/senders \ --header 'Authorization: Bearer ' \ --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" } ] }' ``` * Production * Sandbox — no real infrastructure is provisioned; operations complete instantly. 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. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/provisioning/#bearerauth)** senders:write ## Request Bodyrequired [Section titled “Request Bodyrequired”](#request-body) 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 \>= 1 items <= 50 items **personas** Persona templates for generating mailboxes. You can also add these later. Array 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" } ]} ``` ## Responses [Section titled “Responses”](#responses) ### 201 [Section titled “201”](#201) 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 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"} ``` ### 400 [Section titled “400”](#400) 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 | 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." } ] }} ``` ### 401 [Section titled “401”](#401) 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 | 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 Select examplemissing\_keyinvalid\_key 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" }} ``` Invalid API key ``` { "error": { "code": "auth.invalid_key", "message": "The API key provided is invalid or has been revoked.", "doc_url": "https://docs.sending.ac/errors/auth-invalid-key" }} ``` ### 403 [Section titled “403”](#403) 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 | 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" }} ``` ### 429 [Section titled “429”](#429) 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 | 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" }} ``` #### Headers [Section titled “Headers”](#headers) **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. ## Create a user Source: https://docs.builders.ac/api/provisioning/operations/createuser/ POST /users Select code sampleFetchcURL ``` const url = 'https://live-api.customers.ac/v1/users';const options = { method: 'POST', headers: {Authorization: 'Bearer ', 'Content-Type': 'application/json'}, body: '{"email":"jane@acme.com","company":"Acme Corp","name":"Jane Doe","external_id":"cust_8hTk2mN"}'}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request POST \ --url https://live-api.customers.ac/v1/users \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "email": "jane@acme.com", "company": "Acme Corp", "name": "Jane Doe", "external_id": "cust_8hTk2mN" }' ``` * Production * Sandbox — no real infrastructure is provisioned; operations complete instantly. Creates a new end customer. The `external_id` field is optional and can be used to store your platform’s internal identifier for this customer. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/provisioning/#bearerauth)** users:write ## Request Bodyrequired [Section titled “Request Bodyrequired”](#request-body) Media typeapplication/json object **email** required The user’s email address. Must be unique across your partner account. string format: email **name** The user’s full name. string **company** The user’s company or organization name. string **external\_id** An optional identifier from your system. string <= 255 characters ##### Example ``` { "email": "jane@acme.com", "company": "Acme Corp", "name": "Jane Doe", "external_id": "cust_8hTk2mN"} ``` ## Responses [Section titled “Responses”](#responses) ### 201 [Section titled “201”](#201) User created. Media typeapplication/json object **data** required object **id** required Unique identifier for the user. string format: uuid **email** required The user’s email address. Must be unique across your partner account. string format: email **name** The user’s full name. string | null **company** The user’s company or organization name. string | null **external\_id** An optional identifier from your system. Useful for correlating sending.ac users with your own customer records. string | null **senders\_count** Number of senders belonging to this user. integer **created\_at** required When the user was created. string format: date-time **updated\_at** required When the user was last updated. string format: date-time ##### Example ``` { "data": { "id": "usr_a1b2c3d4-e5f6-7890-abcd-ef1234567890", "email": "jane@acme.com", "name": "Jane Doe", "company": "Acme Corp", "external_id": "cust_8hTk2mN", "senders_count": 2, "created_at": "2026-03-20T09:00:00Z", "updated_at": "2026-03-20T09:00:00Z" }} ``` ### 400 [Section titled “400”](#400) 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 | 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." } ] }} ``` ### 401 [Section titled “401”](#401) 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 | 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 Select examplemissing\_keyinvalid\_key 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" }} ``` Invalid API key ``` { "error": { "code": "auth.invalid_key", "message": "The API key provided is invalid or has been revoked.", "doc_url": "https://docs.sending.ac/errors/auth-invalid-key" }} ``` ### 403 [Section titled “403”](#403) 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 | 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" }} ``` ### 409 [Section titled “409”](#409) The resource already exists. 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 | 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": "resource.already_exists", "message": "A user with email jane@acme.com already exists.", "doc_url": "https://docs.sending.ac/errors/resource-already-exists" }} ``` ### 429 [Section titled “429”](#429) 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 | 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" }} ``` #### Headers [Section titled “Headers”](#headers) **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. ## Deprovision a domain Source: https://docs.builders.ac/api/provisioning/operations/deprovisiondomain/ DELETE /domains/{domain\_id} Select code sampleFetchcURL ``` const url = 'https://live-api.customers.ac/v1/domains/dom_d4e5f6a7-b8c9-0123-def4-567890123456';const options = {method: 'DELETE', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request DELETE \ --url https://live-api.customers.ac/v1/domains/dom_d4e5f6a7-b8c9-0123-def4-567890123456 \ --header 'Authorization: Bearer ' ``` * Production * Sandbox — no real infrastructure is provisioned; operations complete instantly. Begins deprovisioning a single domain and its mailboxes. The domain transitions to `deprovisioning` and eventually `deprovisioned`. This does not affect other domains on the same sender. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/provisioning/#bearerauth)** domains:write ## Parameters [Section titled “Parameters”](#parameters) ### Path Parameters [Section titled “Path Parameters”](#path-parameters) **domain\_id** required string format: uuid ##### Example ``` dom_d4e5f6a7-b8c9-0123-def4-567890123456 ``` The unique identifier of the domain. ## Responses [Section titled “Responses”](#responses) ### 202 [Section titled “202”](#202) Deprovisioning started. Media typeapplication/json object **data** required object **id** required Unique identifier for the domain. string format: uuid **sender\_id** required The sender this domain belongs to. string format: uuid **domain** required The fully qualified domain name. string **status** required The current lifecycle status of a domain. string Allowed values: pending\_nameservers awaiting\_propagation connecting active failed deprovisioning deprovisioned **nameservers** The nameservers assigned to this domain by the platform. **Configure these at your domain registrar to proceed with provisioning.** This field is null until nameservers have been assigned (usually within a few minutes of sender creation). Poll `GET /v1/senders/{id}/domains` to check. Array nullable **health** DNS health check results. `null` until the domain reaches `active` status. object **spf** SPF record status. string Allowed values: pass fail missing **dkim** DKIM record status. string Allowed values: pass fail missing **mx** MX record status. string Allowed values: pass fail missing **last\_checked\_at** When the last health check was performed. string | null format: date-time **mailboxes\_count** Number of mailboxes on this domain. integer **created\_at** required string format: date-time **updated\_at** required string format: date-time **operation\_id** required string format: uuid ##### Example ``` { "data": { "id": "dom_d4e5f6a7-b8c9-0123-def4-567890123456", "sender_id": "snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890", "domain": "outbound.acme.com", "status": "pending_nameservers", "nameservers": [ "ns1.sending.ac", "ns2.sending.ac" ], "health": { "spf": "pass", "dkim": "pass", "mx": "pass", "last_checked_at": "2026-03-24T08:00:00Z" }, "mailboxes_count": 3, "created_at": "2026-03-20T09:05:00Z", "updated_at": "2026-03-21T14:30:00Z" }, "operation_id": "op_e5f6a7b8-c9d0-1234-ef56-789012345678"} ``` ### 401 [Section titled “401”](#401) 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 | 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 Select examplemissing\_keyinvalid\_key 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" }} ``` Invalid API key ``` { "error": { "code": "auth.invalid_key", "message": "The API key provided is invalid or has been revoked.", "doc_url": "https://docs.sending.ac/errors/auth-invalid-key" }} ``` ### 403 [Section titled “403”](#403) 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 | 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" }} ``` ### 404 [Section titled “404”](#404) The requested resource does not exist. 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 | 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": "resource.not_found", "message": "No sender found with ID snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890.", "doc_url": "https://docs.sending.ac/errors/resource-not-found" }} ``` ### 429 [Section titled “429”](#429) 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 | 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" }} ``` #### Headers [Section titled “Headers”](#headers) **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. ## Deprovision a sender Source: https://docs.builders.ac/api/provisioning/operations/deprovisionsender/ DELETE /senders/{sender\_id} Select code sampleFetchcURL ``` const url = 'https://live-api.customers.ac/v1/senders/snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890';const options = {method: 'DELETE', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request DELETE \ --url https://live-api.customers.ac/v1/senders/snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890 \ --header 'Authorization: Bearer ' ``` * Production * Sandbox — no real infrastructure is provisioned; operations complete instantly. Begins deprovisioning a sender and all of its domains and mailboxes. This is irreversible. The sender transitions to `deprovisioning` and eventually `deprovisioned`. Returns an `operation_id` to track progress. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/provisioning/#bearerauth)** senders:write ## Parameters [Section titled “Parameters”](#parameters) ### Path Parameters [Section titled “Path Parameters”](#path-parameters) **sender\_id** required string format: uuid ##### Example ``` snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890 ``` The unique identifier of the sender. ## Responses [Section titled “Responses”](#responses) ### 202 [Section titled “202”](#202) Deprovisioning started. 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 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 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_b2c3d4e5-f6a7-8901-bcde-f23456789012"} ``` ### 401 [Section titled “401”](#401) 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 | 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 Select examplemissing\_keyinvalid\_key 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" }} ``` Invalid API key ``` { "error": { "code": "auth.invalid_key", "message": "The API key provided is invalid or has been revoked.", "doc_url": "https://docs.sending.ac/errors/auth-invalid-key" }} ``` ### 403 [Section titled “403”](#403) 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 | 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" }} ``` ### 404 [Section titled “404”](#404) The requested resource does not exist. 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 | 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": "resource.not_found", "message": "No sender found with ID snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890.", "doc_url": "https://docs.sending.ac/errors/resource-not-found" }} ``` ### 429 [Section titled “429”](#429) 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 | 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" }} ``` #### Headers [Section titled “Headers”](#headers) **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. ## Retrieve a domain Source: https://docs.builders.ac/api/provisioning/operations/getdomain/ GET /domains/{domain\_id} Select code sampleFetchcURL ``` const url = 'https://live-api.customers.ac/v1/domains/dom_d4e5f6a7-b8c9-0123-def4-567890123456';const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request GET \ --url https://live-api.customers.ac/v1/domains/dom_d4e5f6a7-b8c9-0123-def4-567890123456 \ --header 'Authorization: Bearer ' ``` * Production * Sandbox — no real infrastructure is provisioned; operations complete instantly. Returns a single domain by ID, including its nameserver assignments, health records, and current status. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/provisioning/#bearerauth)** domains:read ## Parameters [Section titled “Parameters”](#parameters) ### Path Parameters [Section titled “Path Parameters”](#path-parameters) **domain\_id** required string format: uuid ##### Example ``` dom_d4e5f6a7-b8c9-0123-def4-567890123456 ``` The unique identifier of the domain. ## Responses [Section titled “Responses”](#responses) ### 200 [Section titled “200”](#200) The requested domain. Media typeapplication/json object **data** required object **id** required Unique identifier for the domain. string format: uuid **sender\_id** required The sender this domain belongs to. string format: uuid **domain** required The fully qualified domain name. string **status** required The current lifecycle status of a domain. string Allowed values: pending\_nameservers awaiting\_propagation connecting active failed deprovisioning deprovisioned **nameservers** The nameservers assigned to this domain by the platform. **Configure these at your domain registrar to proceed with provisioning.** This field is null until nameservers have been assigned (usually within a few minutes of sender creation). Poll `GET /v1/senders/{id}/domains` to check. Array nullable **health** DNS health check results. `null` until the domain reaches `active` status. object **spf** SPF record status. string Allowed values: pass fail missing **dkim** DKIM record status. string Allowed values: pass fail missing **mx** MX record status. string Allowed values: pass fail missing **last\_checked\_at** When the last health check was performed. string | null format: date-time **mailboxes\_count** Number of mailboxes on this domain. integer **created\_at** required string format: date-time **updated\_at** required string format: date-time ##### Example ``` { "data": { "id": "dom_d4e5f6a7-b8c9-0123-def4-567890123456", "sender_id": "snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890", "domain": "outbound.acme.com", "status": "pending_nameservers", "nameservers": [ "ns1.sending.ac", "ns2.sending.ac" ], "health": { "spf": "pass", "dkim": "pass", "mx": "pass", "last_checked_at": "2026-03-24T08:00:00Z" }, "mailboxes_count": 3, "created_at": "2026-03-20T09:05:00Z", "updated_at": "2026-03-21T14:30:00Z" }} ``` ### 401 [Section titled “401”](#401) 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 | 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 Select examplemissing\_keyinvalid\_key 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" }} ``` Invalid API key ``` { "error": { "code": "auth.invalid_key", "message": "The API key provided is invalid or has been revoked.", "doc_url": "https://docs.sending.ac/errors/auth-invalid-key" }} ``` ### 403 [Section titled “403”](#403) 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 | 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" }} ``` ### 404 [Section titled “404”](#404) The requested resource does not exist. 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 | 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": "resource.not_found", "message": "No sender found with ID snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890.", "doc_url": "https://docs.sending.ac/errors/resource-not-found" }} ``` ### 429 [Section titled “429”](#429) 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 | 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" }} ``` #### Headers [Section titled “Headers”](#headers) **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. ## Retrieve a mailbox Source: https://docs.builders.ac/api/provisioning/operations/getmailbox/ GET /mailboxes/{mailbox\_id} Select code sampleFetchcURL ``` const url = 'https://live-api.customers.ac/v1/mailboxes/mbx_f6a7b8c9-d0e1-2345-f678-901234567890';const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request GET \ --url https://live-api.customers.ac/v1/mailboxes/mbx_f6a7b8c9-d0e1-2345-f678-901234567890 \ --header 'Authorization: Bearer ' ``` * Production * Sandbox — no real infrastructure is provisioned; operations complete instantly. Returns a single mailbox by ID. Credentials are not included — use the dedicated credentials endpoint. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/provisioning/#bearerauth)** mailboxes:read ## Parameters [Section titled “Parameters”](#parameters) ### Path Parameters [Section titled “Path Parameters”](#path-parameters) **mailbox\_id** required string format: uuid ##### Example ``` mbx_f6a7b8c9-d0e1-2345-f678-901234567890 ``` The unique identifier of the mailbox. ## Responses [Section titled “Responses”](#responses) ### 200 [Section titled “200”](#200) The requested mailbox. Media typeapplication/json object **data** required object **id** required Unique identifier for the mailbox. string format: uuid **domain\_id** required The domain this mailbox belongs to. string format: uuid **sender\_id** required The sender this mailbox belongs to (denormalized for convenience). string format: uuid **email** required The full email address of this mailbox. string format: email **display\_name** The display name configured on this mailbox. string | null **status** required The current lifecycle status of a mailbox. string Allowed values: pending provisioning active suspended deprovisioned **credentials** IMAP and SMTP credentials. Only included when `?include=credentials` is passed. Omitted by default for security. object **mailbox\_id** required string format: uuid **email** required string format: email **imap** required object **host** required IMAP server hostname. string **port** required IMAP server port. integer **username** required IMAP login username (typically the email address). string **password** required IMAP login password. string **encryption** required Connection encryption method. string Allowed values: SSL/TLS STARTTLS none **smtp** required object **host** required SMTP server hostname. string **port** required SMTP server port. integer **username** required SMTP login username (typically the email address). string **password** required SMTP login password. string **encryption** required Connection encryption method. string Allowed values: SSL/TLS STARTTLS none **created\_at** required string format: date-time **updated\_at** required string format: date-time ##### Example ``` { "data": { "id": "mbx_f6a7b8c9-d0e1-2345-f678-901234567890", "domain_id": "dom_d4e5f6a7-b8c9-0123-def4-567890123456", "sender_id": "snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890", "email": "jane@outbound.acme.com", "display_name": "Jane Doe", "status": "pending", "credentials": { "mailbox_id": "mbx_f6a7b8c9-d0e1-2345-f678-901234567890", "email": "jane@outbound.acme.com", "imap": { "host": "outlook.office365.com", "port": 993, "username": "jane@outbound.acme.com", "password": "xK9#mP2$vL5nQ8wR", "encryption": "SSL/TLS" }, "smtp": { "host": "smtp.office365.com", "port": 587, "username": "jane@outbound.acme.com", "password": "xK9#mP2$vL5nQ8wR", "encryption": "SSL/TLS" } }, "created_at": "2026-03-21T14:30:00Z", "updated_at": "2026-03-21T14:35:00Z" }} ``` ### 401 [Section titled “401”](#401) 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 | 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 Select examplemissing\_keyinvalid\_key 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" }} ``` Invalid API key ``` { "error": { "code": "auth.invalid_key", "message": "The API key provided is invalid or has been revoked.", "doc_url": "https://docs.sending.ac/errors/auth-invalid-key" }} ``` ### 403 [Section titled “403”](#403) 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 | 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" }} ``` ### 404 [Section titled “404”](#404) The requested resource does not exist. 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 | 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": "resource.not_found", "message": "No sender found with ID snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890.", "doc_url": "https://docs.sending.ac/errors/resource-not-found" }} ``` ### 429 [Section titled “429”](#429) 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 | 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" }} ``` #### Headers [Section titled “Headers”](#headers) **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. ## Retrieve mailbox credentials Source: https://docs.builders.ac/api/provisioning/operations/getmailboxcredentials/ GET /mailboxes/{mailbox\_id}/credentials Select code sampleFetchcURL ``` const url = 'https://live-api.customers.ac/v1/mailboxes/mbx_f6a7b8c9-d0e1-2345-f678-901234567890/credentials';const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request GET \ --url https://live-api.customers.ac/v1/mailboxes/mbx_f6a7b8c9-d0e1-2345-f678-901234567890/credentials \ --header 'Authorization: Bearer ' ``` * Production * Sandbox — no real infrastructure is provisioned; operations complete instantly. Returns the IMAP and SMTP credentials for a single mailbox. This endpoint is logged separately for audit purposes. Credentials are only available when the mailbox status is `active`. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/provisioning/#bearerauth)** mailboxes:read ## Parameters [Section titled “Parameters”](#parameters) ### Path Parameters [Section titled “Path Parameters”](#path-parameters) **mailbox\_id** required string format: uuid ##### Example ``` mbx_f6a7b8c9-d0e1-2345-f678-901234567890 ``` The unique identifier of the mailbox. ## Responses [Section titled “Responses”](#responses) ### 200 [Section titled “200”](#200) The mailbox credentials. Media typeapplication/json object **data** required IMAP and SMTP connection details for a mailbox. object **mailbox\_id** required string format: uuid **email** required string format: email **imap** required object **host** required IMAP server hostname. string **port** required IMAP server port. integer **username** required IMAP login username (typically the email address). string **password** required IMAP login password. string **encryption** required Connection encryption method. string Allowed values: SSL/TLS STARTTLS none **smtp** required object **host** required SMTP server hostname. string **port** required SMTP server port. integer **username** required SMTP login username (typically the email address). string **password** required SMTP login password. string **encryption** required Connection encryption method. string Allowed values: SSL/TLS STARTTLS none ##### Example ``` { "data": { "mailbox_id": "mbx_f6a7b8c9-d0e1-2345-f678-901234567890", "email": "jane@outbound.acme.com", "imap": { "host": "outlook.office365.com", "port": 993, "username": "jane@outbound.acme.com", "password": "xK9#mP2$vL5nQ8wR", "encryption": "SSL/TLS" }, "smtp": { "host": "smtp.office365.com", "port": 587, "username": "jane@outbound.acme.com", "password": "xK9#mP2$vL5nQ8wR", "encryption": "STARTTLS" } }} ``` ### 401 [Section titled “401”](#401) 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 | 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 Select examplemissing\_keyinvalid\_key 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" }} ``` Invalid API key ``` { "error": { "code": "auth.invalid_key", "message": "The API key provided is invalid or has been revoked.", "doc_url": "https://docs.sending.ac/errors/auth-invalid-key" }} ``` ### 403 [Section titled “403”](#403) 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 | 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" }} ``` ### 404 [Section titled “404”](#404) The requested resource does not exist. 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 | 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": "resource.not_found", "message": "No sender found with ID snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890.", "doc_url": "https://docs.sending.ac/errors/resource-not-found" }} ``` ### 422 [Section titled “422”](#422) Credentials not yet available. The mailbox must be in `active` status. 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 | 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": "resource.not_ready", "message": "Credentials are not available until the mailbox is active. Current status: provisioning.", "doc_url": "https://docs.sending.ac/errors/resource-not-ready" }} ``` ### 429 [Section titled “429”](#429) 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 | 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" }} ``` #### Headers [Section titled “Headers”](#headers) **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. ## Retrieve an operation Source: https://docs.builders.ac/api/provisioning/operations/getoperation/ GET /operations/{operation\_id} Select code sampleFetchcURL ``` const url = 'https://live-api.customers.ac/v1/operations/op_f47ac10b-58cc-4372-a567-0e02b2c3d479';const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request GET \ --url https://live-api.customers.ac/v1/operations/op_f47ac10b-58cc-4372-a567-0e02b2c3d479 \ --header 'Authorization: Bearer ' ``` * Production * Sandbox — no real infrastructure is provisioned; operations complete instantly. Returns a single operation by ID, including its individual steps and their statuses. Poll this endpoint to track the progress of an asynchronous provisioning workflow. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/provisioning/#bearerauth)** senders:read ## Parameters [Section titled “Parameters”](#parameters) ### Path Parameters [Section titled “Path Parameters”](#path-parameters) **operation\_id** required string format: uuid ##### Example ``` op_f47ac10b-58cc-4372-a567-0e02b2c3d479 ``` The unique identifier of the operation. ## Responses [Section titled “Responses”](#responses) ### 200 [Section titled “200”](#200) The requested operation. Media typeapplication/json object **data** required object **id** required Unique identifier for the operation. string format: uuid **type** required The type of async operation. string Allowed values: provision\_sender connect\_domain deprovision\_sender deprovision\_domain **status** required The current status of an operation. string Allowed values: pending in\_progress completed failed cancelled **sender\_id** The sender associated with this operation, if applicable. string | null format: uuid **domain\_id** The domain associated with this operation, if applicable. string | null format: uuid **steps** Ordered list of steps within the operation. Array object **name** required Machine-readable step identifier. string **status** required The current status of this step. string Allowed values: pending in\_progress completed failed skipped **started\_at** When this step started. `null` if not yet started. string | null format: date-time **completed\_at** When this step completed. `null` if not yet completed. string | null format: date-time **message** A human-readable explanation of the step’s current state. string | null **created\_at** required string format: date-time **updated\_at** required string format: date-time ##### Example ``` { "data": { "id": "op_f47ac10b-58cc-4372-a567-0e02b2c3d479", "type": "provision_sender", "status": "in_progress", "sender_id": "snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890", "created_at": "2026-03-24T10:00:00Z", "updated_at": "2026-03-24T10:15:00Z", "steps": [ { "name": "assign_nameservers", "status": "completed", "started_at": "2026-03-24T10:00:01Z", "completed_at": "2026-03-24T10:00:03Z", "message": "Nameservers ns1.sending.ac and ns2.sending.ac assigned to outbound.acme.com." }, { "name": "detect_propagation", "status": "in_progress", "started_at": "2026-03-24T10:00:03Z", "completed_at": null, "message": "Waiting for DNS propagation. Last check: 2026-03-24T10:15:00Z." }, { "name": "provision_m365", "status": "pending", "started_at": null, "completed_at": null, "message": null }, { "name": "create_mailboxes", "status": "pending", "started_at": null, "completed_at": null, "message": null } ] }} ``` ### 401 [Section titled “401”](#401) 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 | 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 Select examplemissing\_keyinvalid\_key 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" }} ``` Invalid API key ``` { "error": { "code": "auth.invalid_key", "message": "The API key provided is invalid or has been revoked.", "doc_url": "https://docs.sending.ac/errors/auth-invalid-key" }} ``` ### 403 [Section titled “403”](#403) 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 | 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" }} ``` ### 404 [Section titled “404”](#404) The requested resource does not exist. 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 | 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": "resource.not_found", "message": "No sender found with ID snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890.", "doc_url": "https://docs.sending.ac/errors/resource-not-found" }} ``` ### 429 [Section titled “429”](#429) 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 | 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" }} ``` #### Headers [Section titled “Headers”](#headers) **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. ## Retrieve a sender Source: https://docs.builders.ac/api/provisioning/operations/getsender/ GET /senders/{sender\_id} Select code sampleFetchcURL ``` const url = 'https://live-api.customers.ac/v1/senders/snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890';const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request GET \ --url https://live-api.customers.ac/v1/senders/snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890 \ --header 'Authorization: Bearer ' ``` * Production * Sandbox — no real infrastructure is provisioned; operations complete instantly. Returns a single sender by ID. To see domain details including nameserver assignments, call `GET /v1/senders/{id}/domains`. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/provisioning/#bearerauth)** senders:read ## Parameters [Section titled “Parameters”](#parameters) ### Path Parameters [Section titled “Path Parameters”](#path-parameters) **sender\_id** required string format: uuid ##### Example ``` snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890 ``` The unique identifier of the sender. ## Responses [Section titled “Responses”](#responses) ### 200 [Section titled “200”](#200) The requested sender. 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 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 ##### 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" }} ``` ### 401 [Section titled “401”](#401) 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 | 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 Select examplemissing\_keyinvalid\_key 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" }} ``` Invalid API key ``` { "error": { "code": "auth.invalid_key", "message": "The API key provided is invalid or has been revoked.", "doc_url": "https://docs.sending.ac/errors/auth-invalid-key" }} ``` ### 403 [Section titled “403”](#403) 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 | 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" }} ``` ### 404 [Section titled “404”](#404) The requested resource does not exist. 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 | 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": "resource.not_found", "message": "No sender found with ID snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890.", "doc_url": "https://docs.sending.ac/errors/resource-not-found" }} ``` ### 429 [Section titled “429”](#429) 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 | 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" }} ``` #### Headers [Section titled “Headers”](#headers) **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. ## Retrieve a user Source: https://docs.builders.ac/api/provisioning/operations/getuser/ GET /users/{user\_id} Select code sampleFetchcURL ``` const url = 'https://live-api.customers.ac/v1/users/usr_a1b2c3d4-e5f6-7890-abcd-ef1234567890';const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request GET \ --url https://live-api.customers.ac/v1/users/usr_a1b2c3d4-e5f6-7890-abcd-ef1234567890 \ --header 'Authorization: Bearer ' ``` * Production * Sandbox — no real infrastructure is provisioned; operations complete instantly. Returns a single user by ID. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/provisioning/#bearerauth)** users:read ## Parameters [Section titled “Parameters”](#parameters) ### Path Parameters [Section titled “Path Parameters”](#path-parameters) **user\_id** required string format: uuid ##### Example ``` usr_a1b2c3d4-e5f6-7890-abcd-ef1234567890 ``` The unique identifier of the user. ## Responses [Section titled “Responses”](#responses) ### 200 [Section titled “200”](#200) The requested user. Media typeapplication/json object **data** required object **id** required Unique identifier for the user. string format: uuid **email** required The user’s email address. Must be unique across your partner account. string format: email **name** The user’s full name. string | null **company** The user’s company or organization name. string | null **external\_id** An optional identifier from your system. Useful for correlating sending.ac users with your own customer records. string | null **senders\_count** Number of senders belonging to this user. integer **created\_at** required When the user was created. string format: date-time **updated\_at** required When the user was last updated. string format: date-time ##### Example ``` { "data": { "id": "usr_a1b2c3d4-e5f6-7890-abcd-ef1234567890", "email": "jane@acme.com", "name": "Jane Doe", "company": "Acme Corp", "external_id": "cust_8hTk2mN", "senders_count": 2, "created_at": "2026-03-20T09:00:00Z", "updated_at": "2026-03-20T09:00:00Z" }} ``` ### 401 [Section titled “401”](#401) 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 | 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 Select examplemissing\_keyinvalid\_key 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" }} ``` Invalid API key ``` { "error": { "code": "auth.invalid_key", "message": "The API key provided is invalid or has been revoked.", "doc_url": "https://docs.sending.ac/errors/auth-invalid-key" }} ``` ### 403 [Section titled “403”](#403) 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 | 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" }} ``` ### 404 [Section titled “404”](#404) The requested resource does not exist. 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 | 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": "resource.not_found", "message": "No sender found with ID snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890.", "doc_url": "https://docs.sending.ac/errors/resource-not-found" }} ``` ### 429 [Section titled “429”](#429) 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 | 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" }} ``` #### Headers [Section titled “Headers”](#headers) **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. ## List domains for a sender Source: https://docs.builders.ac/api/provisioning/operations/listdomains/ GET /senders/{sender\_id}/domains Select code sampleFetchcURL ``` const url = 'https://live-api.customers.ac/v1/senders/snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890/domains?page%5Bsize%5D=25&filter%5Bstatus%5D=pending_nameservers';const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request GET \ --url 'https://live-api.customers.ac/v1/senders/snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890/domains?page%5Bsize%5D=25&filter%5Bstatus%5D=pending_nameservers' \ --header 'Authorization: Bearer ' ``` * Production * Sandbox — no real infrastructure is provisioned; operations complete instantly. Returns all domains belonging to a sender, including their assigned nameservers and current provisioning status. Call this endpoint after creating a sender to retrieve the nameserver values you must configure at your domain registrar. Each domain proceeds independently through the provisioning lifecycle. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/provisioning/#bearerauth)** domains:read ## Parameters [Section titled “Parameters”](#parameters) ### Path Parameters [Section titled “Path Parameters”](#path-parameters) **sender\_id** required string format: uuid ##### Example ``` snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890 ``` The unique identifier of the sender. ### Query Parameters [Section titled “Query Parameters”](#query-parameters) **page\[size\]** integer default: 25 \>= 1 <= 100 Maximum number of records to return. Default: 25, maximum: 100. **page\[after\]** string Opaque cursor returned by a previous list response. Pass this to fetch the next page. **filter\[status\]** The current lifecycle status of a domain. string Allowed values: pending\_nameservers awaiting\_propagation connecting active failed deprovisioning deprovisioned Return only domains with this status. ## Responses [Section titled “Responses”](#responses) ### 200 [Section titled “200”](#200) A paginated list of domains. Media typeapplication/json object **data** required Array object **id** required Unique identifier for the domain. string format: uuid **sender\_id** required The sender this domain belongs to. string format: uuid **domain** required The fully qualified domain name. string **status** required The current lifecycle status of a domain. string Allowed values: pending\_nameservers awaiting\_propagation connecting active failed deprovisioning deprovisioned **nameservers** The nameservers assigned to this domain by the platform. **Configure these at your domain registrar to proceed with provisioning.** This field is null until nameservers have been assigned (usually within a few minutes of sender creation). Poll `GET /v1/senders/{id}/domains` to check. Array nullable **health** DNS health check results. `null` until the domain reaches `active` status. object **spf** SPF record status. string Allowed values: pass fail missing **dkim** DKIM record status. string Allowed values: pass fail missing **mx** MX record status. string Allowed values: pass fail missing **last\_checked\_at** When the last health check was performed. string | null format: date-time **mailboxes\_count** Number of mailboxes on this domain. integer **created\_at** required string format: date-time **updated\_at** required string format: date-time **pagination** required Cursor-based pagination metadata. object **has\_more** required `true` if there are more records after this page. boolean **next\_cursor** Pass this value as `page[after]` to fetch the next page. `null` when there are no more records. string | null ##### Example ``` { "data": [ { "id": "dom_d4e5f6a7-b8c9-0123-def4-567890123456", "sender_id": "snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890", "domain": "outbound.acme.com", "status": "pending_nameservers", "nameservers": [ "ns1.sending.ac", "ns2.sending.ac" ], "health": { "spf": "pass", "dkim": "pass", "mx": "pass", "last_checked_at": "2026-03-24T08:00:00Z" }, "mailboxes_count": 3, "created_at": "2026-03-20T09:05:00Z", "updated_at": "2026-03-21T14:30:00Z" } ], "pagination": { "next_cursor": "eyJpZCI6InVzcl96OXk4eDd3NiJ9" }} ``` ### 401 [Section titled “401”](#401) 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 | 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 Select examplemissing\_keyinvalid\_key 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" }} ``` Invalid API key ``` { "error": { "code": "auth.invalid_key", "message": "The API key provided is invalid or has been revoked.", "doc_url": "https://docs.sending.ac/errors/auth-invalid-key" }} ``` ### 403 [Section titled “403”](#403) 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 | 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" }} ``` ### 404 [Section titled “404”](#404) The requested resource does not exist. 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 | 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": "resource.not_found", "message": "No sender found with ID snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890.", "doc_url": "https://docs.sending.ac/errors/resource-not-found" }} ``` ### 429 [Section titled “429”](#429) 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 | 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" }} ``` #### Headers [Section titled “Headers”](#headers) **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. ## List mailboxes for a sender Source: https://docs.builders.ac/api/provisioning/operations/listmailboxes/ GET /senders/{sender\_id}/mailboxes Select code sampleFetchcURL ``` const url = 'https://live-api.customers.ac/v1/senders/snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890/mailboxes?page%5Bsize%5D=25&filter%5Bstatus%5D=pending&include=credentials';const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request GET \ --url 'https://live-api.customers.ac/v1/senders/snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890/mailboxes?page%5Bsize%5D=25&filter%5Bstatus%5D=pending&include=credentials' \ --header 'Authorization: Bearer ' ``` * Production * Sandbox — no real infrastructure is provisioned; operations complete instantly. Returns all mailboxes belonging to a sender. By default, credentials are **not** included. Pass `include=credentials` to include IMAP and SMTP credentials in the response. > **Security note:** Only request credentials when you need them. Credential responses are logged separately for audit purposes. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/provisioning/#bearerauth)** mailboxes:read ## Parameters [Section titled “Parameters”](#parameters) ### Path Parameters [Section titled “Path Parameters”](#path-parameters) **sender\_id** required string format: uuid ##### Example ``` snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890 ``` The unique identifier of the sender. ### Query Parameters [Section titled “Query Parameters”](#query-parameters) **page\[size\]** integer default: 25 \>= 1 <= 100 Maximum number of records to return. Default: 25, maximum: 100. **page\[after\]** string Opaque cursor returned by a previous list response. Pass this to fetch the next page. **filter\[status\]** The current lifecycle status of a mailbox. string Allowed values: pending provisioning active suspended deprovisioned Return only mailboxes with this status. **filter\[domain\_id\]** string format: uuid Return only mailboxes on this domain. **include** string Allowed values: credentials Comma-separated list of related resources to include. Supported values: `credentials`. ## Responses [Section titled “Responses”](#responses) ### 200 [Section titled “200”](#200) A paginated list of mailboxes. Media typeapplication/json object **data** required Array object **id** required Unique identifier for the mailbox. string format: uuid **domain\_id** required The domain this mailbox belongs to. string format: uuid **sender\_id** required The sender this mailbox belongs to (denormalized for convenience). string format: uuid **email** required The full email address of this mailbox. string format: email **display\_name** The display name configured on this mailbox. string | null **status** required The current lifecycle status of a mailbox. string Allowed values: pending provisioning active suspended deprovisioned **credentials** IMAP and SMTP credentials. Only included when `?include=credentials` is passed. Omitted by default for security. object **mailbox\_id** required string format: uuid **email** required string format: email **imap** required object **host** required IMAP server hostname. string **port** required IMAP server port. integer **username** required IMAP login username (typically the email address). string **password** required IMAP login password. string **encryption** required Connection encryption method. string Allowed values: SSL/TLS STARTTLS none **smtp** required object **host** required SMTP server hostname. string **port** required SMTP server port. integer **username** required SMTP login username (typically the email address). string **password** required SMTP login password. string **encryption** required Connection encryption method. string Allowed values: SSL/TLS STARTTLS none **created\_at** required string format: date-time **updated\_at** required string format: date-time **pagination** required Cursor-based pagination metadata. object **has\_more** required `true` if there are more records after this page. boolean **next\_cursor** Pass this value as `page[after]` to fetch the next page. `null` when there are no more records. string | null ##### Example ``` { "data": [ { "id": "mbx_f6a7b8c9-d0e1-2345-f678-901234567890", "domain_id": "dom_d4e5f6a7-b8c9-0123-def4-567890123456", "sender_id": "snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890", "email": "jane@outbound.acme.com", "display_name": "Jane Doe", "status": "pending", "credentials": { "mailbox_id": "mbx_f6a7b8c9-d0e1-2345-f678-901234567890", "email": "jane@outbound.acme.com", "imap": { "host": "outlook.office365.com", "port": 993, "username": "jane@outbound.acme.com", "password": "xK9#mP2$vL5nQ8wR", "encryption": "SSL/TLS" }, "smtp": { "host": "smtp.office365.com", "port": 587, "username": "jane@outbound.acme.com", "password": "xK9#mP2$vL5nQ8wR", "encryption": "SSL/TLS" } }, "created_at": "2026-03-21T14:30:00Z", "updated_at": "2026-03-21T14:35:00Z" } ], "pagination": { "next_cursor": "eyJpZCI6InVzcl96OXk4eDd3NiJ9" }} ``` ### 401 [Section titled “401”](#401) 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 | 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 Select examplemissing\_keyinvalid\_key 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" }} ``` Invalid API key ``` { "error": { "code": "auth.invalid_key", "message": "The API key provided is invalid or has been revoked.", "doc_url": "https://docs.sending.ac/errors/auth-invalid-key" }} ``` ### 403 [Section titled “403”](#403) 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 | 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" }} ``` ### 404 [Section titled “404”](#404) The requested resource does not exist. 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 | 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": "resource.not_found", "message": "No sender found with ID snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890.", "doc_url": "https://docs.sending.ac/errors/resource-not-found" }} ``` ### 429 [Section titled “429”](#429) 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 | 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" }} ``` #### Headers [Section titled “Headers”](#headers) **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. ## List operations Source: https://docs.builders.ac/api/provisioning/operations/listoperations/ GET /operations Select code sampleFetchcURL ``` const url = 'https://live-api.customers.ac/v1/operations?page%5Bsize%5D=25&filter%5Btype%5D=provision_sender&filter%5Bstatus%5D=pending';const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request GET \ --url 'https://live-api.customers.ac/v1/operations?page%5Bsize%5D=25&filter%5Btype%5D=provision_sender&filter%5Bstatus%5D=pending' \ --header 'Authorization: Bearer ' ``` * Production * Sandbox — no real infrastructure is provisioned; operations complete instantly. Returns a paginated list of operations. Use filters to narrow results by type or status. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/provisioning/#bearerauth)** senders:read ## Parameters [Section titled “Parameters”](#parameters) ### Query Parameters [Section titled “Query Parameters”](#query-parameters) **page\[size\]** integer default: 25 \>= 1 <= 100 Maximum number of records to return. Default: 25, maximum: 100. **page\[after\]** string Opaque cursor returned by a previous list response. Pass this to fetch the next page. **filter\[type\]** The type of async operation. string Allowed values: provision\_sender connect\_domain deprovision\_sender deprovision\_domain Return only operations of this type. **filter\[status\]** The current status of an operation. string Allowed values: pending in\_progress completed failed cancelled Return only operations with this status. **filter\[sender\_id\]** string format: uuid Return only operations for this sender. ## Responses [Section titled “Responses”](#responses) ### 200 [Section titled “200”](#200) A paginated list of operations. Media typeapplication/json object **data** required Array object **id** required Unique identifier for the operation. string format: uuid **type** required The type of async operation. string Allowed values: provision\_sender connect\_domain deprovision\_sender deprovision\_domain **status** required The current status of an operation. string Allowed values: pending in\_progress completed failed cancelled **sender\_id** The sender associated with this operation, if applicable. string | null format: uuid **domain\_id** The domain associated with this operation, if applicable. string | null format: uuid **steps** Ordered list of steps within the operation. Array object **name** required Machine-readable step identifier. string **status** required The current status of this step. string Allowed values: pending in\_progress completed failed skipped **started\_at** When this step started. `null` if not yet started. string | null format: date-time **completed\_at** When this step completed. `null` if not yet completed. string | null format: date-time **message** A human-readable explanation of the step’s current state. string | null **created\_at** required string format: date-time **updated\_at** required string format: date-time **pagination** required Cursor-based pagination metadata. object **has\_more** required `true` if there are more records after this page. boolean **next\_cursor** Pass this value as `page[after]` to fetch the next page. `null` when there are no more records. string | null ##### Example ``` { "data": [ { "id": "op_f47ac10b-58cc-4372-a567-0e02b2c3d479", "type": "provision_sender", "status": "pending", "sender_id": "snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890", "domain_id": "dom_d4e5f6a7-b8c9-0123-def4-567890123456", "steps": [ { "name": "detect_propagation", "status": "pending", "message": "Waiting for DNS propagation. Last check: 2026-03-24T10:15:00Z." } ], "created_at": "2026-03-24T10:00:00Z", "updated_at": "2026-03-24T10:15:00Z" } ], "pagination": { "next_cursor": "eyJpZCI6InVzcl96OXk4eDd3NiJ9" }} ``` ### 401 [Section titled “401”](#401) 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 | 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 Select examplemissing\_keyinvalid\_key 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" }} ``` Invalid API key ``` { "error": { "code": "auth.invalid_key", "message": "The API key provided is invalid or has been revoked.", "doc_url": "https://docs.sending.ac/errors/auth-invalid-key" }} ``` ### 403 [Section titled “403”](#403) 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 | 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" }} ``` ### 429 [Section titled “429”](#429) 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 | 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" }} ``` #### Headers [Section titled “Headers”](#headers) **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. ## List senders Source: https://docs.builders.ac/api/provisioning/operations/listsenders/ GET /senders Select code sampleFetchcURL ``` const url = 'https://live-api.customers.ac/v1/senders?page%5Bsize%5D=25&filter%5Bstatus%5D=pending';const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request GET \ --url 'https://live-api.customers.ac/v1/senders?page%5Bsize%5D=25&filter%5Bstatus%5D=pending' \ --header 'Authorization: Bearer ' ``` * Production * Sandbox — no real infrastructure is provisioned; operations complete instantly. Returns a paginated list of senders. You can filter by user or status. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/provisioning/#bearerauth)** senders:read ## Parameters [Section titled “Parameters”](#parameters) ### Query Parameters [Section titled “Query Parameters”](#query-parameters) **page\[size\]** integer default: 25 \>= 1 <= 100 Maximum number of records to return. Default: 25, maximum: 100. **page\[after\]** string Opaque cursor returned by a previous list response. Pass this to fetch the next page. **filter\[user\_id\]** string format: uuid Return only senders belonging to this user. **filter\[status\]** The current lifecycle status of a sender. string Allowed values: pending provisioning active deprovisioning deprovisioned Return only senders with this status. ## Responses [Section titled “Responses”](#responses) ### 200 [Section titled “200”](#200) A paginated list of senders. Media typeapplication/json object **data** required Array 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 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 **pagination** required Cursor-based pagination metadata. object **has\_more** required `true` if there are more records after this page. boolean **next\_cursor** Pass this value as `page[after]` to fetch the next page. `null` when there are no more records. string | null ##### 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" } ], "pagination": { "next_cursor": "eyJpZCI6InVzcl96OXk4eDd3NiJ9" }} ``` ### 401 [Section titled “401”](#401) 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 | 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 Select examplemissing\_keyinvalid\_key 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" }} ``` Invalid API key ``` { "error": { "code": "auth.invalid_key", "message": "The API key provided is invalid or has been revoked.", "doc_url": "https://docs.sending.ac/errors/auth-invalid-key" }} ``` ### 403 [Section titled “403”](#403) 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 | 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" }} ``` ### 429 [Section titled “429”](#429) 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 | 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" }} ``` #### Headers [Section titled “Headers”](#headers) **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. ## List users Source: https://docs.builders.ac/api/provisioning/operations/listusers/ GET /users Select code sampleFetchcURL ``` const url = 'https://live-api.customers.ac/v1/users?page%5Bsize%5D=25';const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request GET \ --url 'https://live-api.customers.ac/v1/users?page%5Bsize%5D=25' \ --header 'Authorization: Bearer ' ``` * Production * Sandbox — no real infrastructure is provisioned; operations complete instantly. Returns a paginated list of users belonging to your partner account. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/provisioning/#bearerauth)** users:read ## Parameters [Section titled “Parameters”](#parameters) ### Query Parameters [Section titled “Query Parameters”](#query-parameters) **page\[size\]** integer default: 25 \>= 1 <= 100 Maximum number of records to return. Default: 25, maximum: 100. **page\[after\]** string Opaque cursor returned by a previous list response. Pass this to fetch the next page. **filter\[email\]** string format: email Filter by exact email address. ## Responses [Section titled “Responses”](#responses) ### 200 [Section titled “200”](#200) A paginated list of users. Media typeapplication/json object **data** required Array object **id** required Unique identifier for the user. string format: uuid **email** required The user’s email address. Must be unique across your partner account. string format: email **name** The user’s full name. string | null **company** The user’s company or organization name. string | null **external\_id** An optional identifier from your system. Useful for correlating sending.ac users with your own customer records. string | null **senders\_count** Number of senders belonging to this user. integer **created\_at** required When the user was created. string format: date-time **updated\_at** required When the user was last updated. string format: date-time **pagination** required Cursor-based pagination metadata. object **has\_more** required `true` if there are more records after this page. boolean **next\_cursor** Pass this value as `page[after]` to fetch the next page. `null` when there are no more records. string | null ##### Example ``` { "data": [ { "id": "usr_a1b2c3d4-e5f6-7890-abcd-ef1234567890", "email": "jane@acme.com", "name": "Jane Doe", "company": "Acme Corp", "external_id": "cust_8hTk2mN", "senders_count": 2, "created_at": "2026-03-20T09:00:00Z", "updated_at": "2026-03-20T09:00:00Z" } ], "pagination": { "next_cursor": "eyJpZCI6InVzcl96OXk4eDd3NiJ9" }} ``` ### 401 [Section titled “401”](#401) 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 | 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 Select examplemissing\_keyinvalid\_key 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" }} ``` Invalid API key ``` { "error": { "code": "auth.invalid_key", "message": "The API key provided is invalid or has been revoked.", "doc_url": "https://docs.sending.ac/errors/auth-invalid-key" }} ``` ### 403 [Section titled “403”](#403) 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 | 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" }} ``` ### 429 [Section titled “429”](#429) 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 | 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" }} ``` #### Headers [Section titled “Headers”](#headers) **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. ## Update a sender Source: https://docs.builders.ac/api/provisioning/operations/updatesender/ PATCH /senders/{sender\_id} Select code sampleFetchcURL ``` const url = 'https://live-api.customers.ac/v1/senders/snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890';const options = { method: 'PATCH', headers: {Authorization: 'Bearer ', 'Content-Type': 'application/json'}, body: '{"name":"Acme Outbound Q2"}'}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request PATCH \ --url https://live-api.customers.ac/v1/senders/snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890 \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "name": "Acme Outbound Q2" }' ``` * Production * Sandbox — no real infrastructure is provisioned; operations complete instantly. Updates mutable fields on a sender (name, personas). You cannot change the user or status directly. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/provisioning/#bearerauth)** senders:write ## Parameters [Section titled “Parameters”](#parameters) ### Path Parameters [Section titled “Path Parameters”](#path-parameters) **sender\_id** required string format: uuid ##### Example ``` snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890 ``` The unique identifier of the sender. ## Request Bodyrequired [Section titled “Request Bodyrequired”](#request-body) Media typeapplication/json object \>= 1 properties **name** A human-readable name for this sender. string <= 255 characters **personas** Replace all personas. This does not affect already-provisioned mailboxes. Array 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 ``` { "name": "Acme Outbound Q2"} ``` ## Responses [Section titled “Responses”](#responses) ### 200 [Section titled “200”](#200) Sender updated. 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 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 ##### 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" }} ``` ### 400 [Section titled “400”](#400) 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 | 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." } ] }} ``` ### 401 [Section titled “401”](#401) 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 | 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 Select examplemissing\_keyinvalid\_key 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" }} ``` Invalid API key ``` { "error": { "code": "auth.invalid_key", "message": "The API key provided is invalid or has been revoked.", "doc_url": "https://docs.sending.ac/errors/auth-invalid-key" }} ``` ### 403 [Section titled “403”](#403) 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 | 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" }} ``` ### 404 [Section titled “404”](#404) The requested resource does not exist. 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 | 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": "resource.not_found", "message": "No sender found with ID snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890.", "doc_url": "https://docs.sending.ac/errors/resource-not-found" }} ``` ### 429 [Section titled “429”](#429) 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 | 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" }} ``` #### Headers [Section titled “Headers”](#headers) **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. ## Update a user Source: https://docs.builders.ac/api/provisioning/operations/updateuser/ PATCH /users/{user\_id} Select code sampleFetchcURL ``` const url = 'https://live-api.customers.ac/v1/users/usr_a1b2c3d4-e5f6-7890-abcd-ef1234567890';const options = { method: 'PATCH', headers: {Authorization: 'Bearer ', 'Content-Type': 'application/json'}, body: '{"company":"Acme International"}'}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);} ``` ``` curl --request PATCH \ --url https://live-api.customers.ac/v1/users/usr_a1b2c3d4-e5f6-7890-abcd-ef1234567890 \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data '{ "company": "Acme International" }' ``` * Production * Sandbox — no real infrastructure is provisioned; operations complete instantly. Updates one or more fields on a user. Only the fields you include in the request body are changed. ## Authorizations [Section titled “Authorizations”](#authorizations) * **[BearerAuth](/api/provisioning/#bearerauth)** users:write ## Parameters [Section titled “Parameters”](#parameters) ### Path Parameters [Section titled “Path Parameters”](#path-parameters) **user\_id** required string format: uuid ##### Example ``` usr_a1b2c3d4-e5f6-7890-abcd-ef1234567890 ``` The unique identifier of the user. ## Request Bodyrequired [Section titled “Request Bodyrequired”](#request-body) Media typeapplication/json object \>= 1 properties **name** The user’s full name. string **company** The user’s company or organization name. string **external\_id** An optional identifier from your system. Pass `null` to clear. string | null <= 255 characters ##### Example ``` { "company": "Acme International"} ``` ## Responses [Section titled “Responses”](#responses) ### 200 [Section titled “200”](#200) User updated. Media typeapplication/json object **data** required object **id** required Unique identifier for the user. string format: uuid **email** required The user’s email address. Must be unique across your partner account. string format: email **name** The user’s full name. string | null **company** The user’s company or organization name. string | null **external\_id** An optional identifier from your system. Useful for correlating sending.ac users with your own customer records. string | null **senders\_count** Number of senders belonging to this user. integer **created\_at** required When the user was created. string format: date-time **updated\_at** required When the user was last updated. string format: date-time ##### Example ``` { "data": { "id": "usr_a1b2c3d4-e5f6-7890-abcd-ef1234567890", "email": "jane@acme.com", "name": "Jane Doe", "company": "Acme Corp", "external_id": "cust_8hTk2mN", "senders_count": 2, "created_at": "2026-03-20T09:00:00Z", "updated_at": "2026-03-20T09:00:00Z" }} ``` ### 400 [Section titled “400”](#400) 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 | 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." } ] }} ``` ### 401 [Section titled “401”](#401) 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 | 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 Select examplemissing\_keyinvalid\_key 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" }} ``` Invalid API key ``` { "error": { "code": "auth.invalid_key", "message": "The API key provided is invalid or has been revoked.", "doc_url": "https://docs.sending.ac/errors/auth-invalid-key" }} ``` ### 403 [Section titled “403”](#403) 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 | 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" }} ``` ### 404 [Section titled “404”](#404) The requested resource does not exist. 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 | 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": "resource.not_found", "message": "No sender found with ID snd_a1b2c3d4-e5f6-7890-abcd-ef1234567890.", "doc_url": "https://docs.sending.ac/errors/resource-not-found" }} ``` ### 429 [Section titled “429”](#429) 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 | 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" }} ``` #### Headers [Section titled “Headers”](#headers) **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.