The API, in full, before you buy anything.
A plain HTTP API over JSON. No SDK to install, no partner programme, no sales call to unlock the docs: everything the application does, it does through the endpoints below, and you can read them now to decide whether the thing fits your systems.
Authentication
Keys are created in Settings → API, scoped to one workspace, and shown once. Send one as a bearer token over TLS 1.2 or better; there is no other authentication scheme and no key in a query string.
curl https://api.coppermailer.com/v1/mailboxes \
-H "Authorization: Bearer cm_live_7f3a9c2e41b8d05e"
https://api.coppermailer.com/v1
Content type application/json
Key prefix cm_live_ and cm_test_
Endpoints
| Endpoint | What it does | Credits |
|---|---|---|
| GET/mailboxes | The mailboxes connected to this workspace, with their connection state. | Free |
| GET/messages | Inbound messages, filtered by mailbox, status, intent, language or date. | Free |
| GET/messages/{id} | One inbound message, with its detected intent, language and sentiment. | Free |
| POST/messages/{id}/draft | Generate a reply to that message from your knowledge sources. Returns the draft with its citations. | 1 |
| POST/messages/{id}/reply | Send an approved draft. The recipient is the sender of message {id}. | Free |
| GET/drafts/{id} | Retrieve a draft, its citations and its approval history. | Free |
| POST/drafts/{id}/reject | Reject a draft with a reason. The reason trains your voice profile. | Free |
| GET/knowledge/sources | Knowledge sources, with page counts and last index time. | Free |
| POST/knowledge/sources | Add a help-centre URL, an uploaded file or a pasted macro set. | Free |
| POST/knowledge/reindex | Re-read the sources. First 500 pages free on every licence, then 5 per 100 pages. | 5 / 100 pp |
| DELETE/knowledge/sources/{id} | Remove a source and everything indexed from it. | Free |
| GET/rules | The routing and auto-send rules built in Circuit Builder. | Free |
| POST/rules | Create a rule: match on intent, language, sentiment or sender domain. | Free |
| GET/usage | The credit ledger, line by line: what was generated, when, and what it cost. | Free |
| GET/audit | Administrative and data-access events, 12 months, paginated. | Free |
Requires the API & webhooks unlock. The interface uses these same endpoints, so anything the application can do, your own code can do.
There is no send endpoint, and there is nowhere to put a recipient. Look down the list again: the only call that puts mail on the wire is POST /messages/{id}/reply, and it takes a draft, not an address. The recipient is read from the message being answered. There is no to field to populate, no contact object, no list, no segment, no campaign and no schedule anywhere in the API, because none of those things exist in the product. This is what we mean when we say CopperMailer answers mail rather than sends it: it is a property of the software, not a policy you have to trust us on.
Generating a reply
POST /v1/messages/msg_4nZ7pB/draft
{
"tone": "workspace_default",
"max_words": 220
}
200 OK
{
"id": "drf_8Qk2mRt5",
"message_id": "msg_4nZ7pB",
"mailbox": "support@yourcompany.com",
"language": "en",
"intent": "order_status",
"status": "awaiting_approval",
"credits_charged": 1,
"body": "Hello Anna, order 41982 was dispatched on 12 August and is...",
"citations": [
{
"source_id": "src_helpcentre",
"title": "Delivery times",
"url": "https://help.yourcompany.com/delivery",
"confidence": 0.94
},
{
"source_id": "src_shopify",
"title": "Order 41982",
"confidence": 0.99
}
],
"created_at": "2026-08-20T09:14:22Z"
}
Sending it, once a human has said yes
POST /v1/messages/msg_4nZ7pB/reply
{
"draft_id": "drf_8Qk2mRt5",
"approved_by": "usr_kJ92la"
}
200 OK
{
"status": "sent",
"to": "anna.kowalska@example.com",
"in_reply_to": "msg_4nZ7pB",
"sent_at": "2026-08-20T09:15:03Z",
"credits_charged": 0
}
to comes back in the response because we tell you where it went. It is not accepted in the request: send one and the call fails with 422 unexpected_field.
Webhooks
Register up to five endpoints. Every delivery carries a CM-Signature header, HMAC-SHA256 over the raw body with your endpoint secret, and is retried five times over six hours until you answer with a 2xx inside ten seconds.
| Event | Fires when |
|---|---|
message.received | Mail lands in a connected mailbox and has been classified. |
draft.created | A reply has been generated and is waiting in the queue. |
draft.rejected | Someone rejected a draft, with the reason they gave. |
reply.sent | A reply left the mailbox, whether approved by a person or by a rule. |
reply.failed | Delivery failed: bad credentials, a bounce, or the provider refused it. |
credits.low | The remaining credits crossed a threshold you set yourself. |
credits.exhausted | Generation has paused. Inbound mail is still received, classified and routed. |
knowledge.reindexed | A source finished indexing, with the page count that was charged. |
Errors and rate limits
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | Malformed JSON, or a parameter outside its permitted range. |
| 401 | invalid_key | Missing, revoked or mistyped API key. |
| 402 | insufficient_credits | No credits left. Nothing is charged, nothing is queued and no card is touched: buy credits and repeat the call. |
| 403 | feature_locked | The API & webhooks unlock is not on this workspace. |
| 404 | not_found | No such object in this workspace. Identifiers never cross workspaces. |
| 409 | already_answered | That message has already been replied to. |
| 422 | unexpected_field | A field the endpoint does not accept, such as a recipient on a reply. |
| 429 | rate_limited | Slow down. Retry-After tells you by how long. |
| 503 | model_unavailable | Our model provider is failing. No credit is charged for a generation that did not happen. |
Limits
| API requests | 120 per minute per workspace, of which 20 may be generations. CM-RateLimit-Remaining on every response. |
|---|---|
| Inbound message size | 25 MB including attachments |
| Attachment reading | 20 pages per message: PDF, images, spreadsheets |
| Reply length | 1,500 words at 1 credit; longer replies cost 2 |
| Languages | 31 detected and answered, with your terminology held consistent across all of them |
| Knowledge sources | 200 sources, 5,000 pages per workspace. First 500 pages indexed free. |
| API keys and webhooks | 10 keys and 5 webhook endpoints per workspace |
| Credits per order | 10 minimum, 20,000 maximum. Purchases stack; nothing expires. |
| Audit log | 12 months, exportable by administrators on every licence |
| Sessions | 30 days maximum, TLS 1.2 or better, HSTS enforced |
| Sandbox | Foundry workspaces get a sandbox; test replies there never consume credits and never reach a real recipient. |
The complete reference, with every field on every object, sits in your workspace under Settings → API. Breaking changes get a new version prefix and twelve months of overlap; we do not move things under you.