Reference
Sends
The primitive — every email Clement sends, whether one-off or campaign-driven, lands here. See the Send your first email guide for the typical flow.
List sends
/v1/sends curl -X GET "https://api.clement.so/v1/sends" \
-H "Authorization: Bearer $CLEMENT_API_KEY" Query parameters
-
limitinteger -
starting_afterstring -
ending_beforestring -
inbox_idstring -
statestring -
expandstring
Response200
OK
| Property | Type | Description |
|---|---|---|
object
required
| enum (1) | "list" |
data
required
| array<Send> | |
has_more
required
| boolean | |
next_cursor
required
| string | null | |
prev_cursor
required
| string | null |
Example response
{
"object": "list",
"data": [
{
"id": "snd_01HZ8X3J9K7P2QV6R5N4M3T2L4",
"object": "send",
"mode": "live",
"inbox_id": "inb_01HZ8X3J9K7P2QV6R5N4M3T2L1",
"to_email": "alice@example.com",
"subject": "Quick question about Acme's data stack",
"state": "sent",
"failure_reason": null,
"provider_message_id": "18f8a2b...",
"provider_thread_id": "18f8a2b...",
"rfc822_message_id": "<01HZ8X3J9K7P2QV6@mail.clement.so>",
"attempt_count": 1,
"scheduled_at": "2026-04-29T14:30:00Z",
"sent_at": "2026-04-29T14:30:02Z",
"created_at": "2026-04-29T14:30:00Z",
"campaign_id": null
}
],
"has_more": false,
"next_cursor": "string",
"prev_cursor": "string"
} Errors
-
400Invalid request -
401Authentication failed -
403Insufficient scope -
404Not found -
409Conflict -
422Validation failed -
429Rate limited
See Errors for the full envelope and per-code reference.
Send an email (single or fan-out across inboxes)
/v1/sends **The send primitive** (API-PLAN §6). Single recipient → returns the `Send`. Multi-recipient or `from_strategy` → returns a `BulkSendResult` with per-recipient outcomes.
curl -X POST "https://api.clement.so/v1/sends" \
-H "Authorization: Bearer $CLEMENT_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
--data '{
"to": "alice@example.com",
"subject": "Quick question about your stack",
"inbox_id": "inb_01HZ8X3J9K7P2QV6R5N4M3T2L1",
"from_strategy": {
"type": "single",
"inbox_id": "inb_01HZ8X3J9K7P2QV6R5N4M3T2L1",
"inbox_ids": [
"string"
]
},
"body_html": "<p>Hi {{first_name}}, would love to chat — does Tuesday work?</p>",
"body_text": "Hi {{first_name}}, would love to chat — does Tuesday work?",
"variables": {},
"thread_id": "thr_01HZ8X3J9K7P2QV6R5N4M3T2L6",
"in_reply_to_message_id": "in__01HZ8X3J9K7P2QV6R5N4M3T2L1",
"metadata": {},
"append_signature": false
}' Request body
| Property | Type | Description | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
inbox_id | string | Single-inbox shorthand. Equivalent to `from_strategy: { type: 'single', inbox_id }`. | ||||||||||||
from_strategy | SendFromStrategy | Show properties
| ||||||||||||
to
required
| object | |||||||||||||
subject
required
| string | |||||||||||||
body_html | string | |||||||||||||
body_text | string | |||||||||||||
variables | object | |||||||||||||
send_at | string (date-time) | null | RFC-3339 timestamp; null/omitted = enqueue immediately. | ||||||||||||
thread_id | string | Public thread id (`thr_…`). Setting this turns the send into a reply in that thread: it must be sent from the thread's inbox (`inbox_id` or a `single` from_strategy), and `In-Reply-To` defaults to the thread's latest message. | ||||||||||||
in_reply_to_message_id | string | RFC 822 Message-ID (`<…@…>`) to cite in `In-Reply-To`. With `thread_id`, overrides the default (the thread's latest message). | ||||||||||||
metadata | object | Customer-supplied dict echoed back on every event for this send. | ||||||||||||
append_signature | boolean | Append the sending inbox's signature (`signature_html` / `signature_text`) to the body parts you supply. Default false: ad-hoc sends go out exactly as written. |
Response201
Send(s) scheduled
Type: object.
Example response
{
"id": "snd_01HZ8X3J9K7P2QV6R5N4M3T2L4",
"object": "send",
"mode": "live",
"inbox_id": "inb_01HZ8X3J9K7P2QV6R5N4M3T2L1",
"to_email": "alice@example.com",
"subject": "Quick question about Acme's data stack",
"state": "sent",
"failure_reason": null,
"provider_message_id": "18f8a2b...",
"provider_thread_id": "18f8a2b...",
"rfc822_message_id": "<01HZ8X3J9K7P2QV6@mail.clement.so>",
"attempt_count": 1,
"scheduled_at": "2026-04-29T14:30:00Z",
"sent_at": "2026-04-29T14:30:02Z",
"created_at": "2026-04-29T14:30:00Z",
"campaign_id": null
} Errors
-
400Invalid request -
401Authentication failed -
403Insufficient scope -
404Not found -
409Conflict -
422Validation failed -
429Rate limited
See Errors for the full envelope and per-code reference.
Retrieve a send
/v1/sends/{id} curl -X GET "https://api.clement.so/v1/sends/obj_01HZ8X3J9K7P2QV6R5N4M3T2L1" \
-H "Authorization: Bearer $CLEMENT_API_KEY" Path parameters
-
idstring required
Query parameters
-
expandstring
Response200
OK
| Property | Type | Description | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
id
required
| string | ||||||||||||||||
object
required
| enum (1) | "send" | |||||||||||||||
mode
required
| enum (2) | "live""test" | |||||||||||||||
inbox_id
required
| string | ||||||||||||||||
inbox | SendExpandInbox | null | Present (possibly null if missing) when `?expand=inbox`. Show properties
| |||||||||||||||
to_email
required
| string (email) | ||||||||||||||||
subject
required
| string | ||||||||||||||||
state
required
| enum (4) | "scheduled""sending""sent""failed" | |||||||||||||||
failure_reason
required
| string | null | ||||||||||||||||
provider_message_id
required
| string | null | ||||||||||||||||
provider_thread_id
required
| string | null | ||||||||||||||||
rfc822_message_id
required
| string | null | ||||||||||||||||
attempt_count
required
| integer | ||||||||||||||||
scheduled_at
required
| string (date-time) | ||||||||||||||||
sent_at
required
| string (date-time) | null | ||||||||||||||||
created_at
required
| string (date-time) | ||||||||||||||||
campaign_id
required
| string | null |
Example response
{
"id": "snd_01HZ8X3J9K7P2QV6R5N4M3T2L4",
"object": "send",
"mode": "live",
"inbox_id": "inb_01HZ8X3J9K7P2QV6R5N4M3T2L1",
"to_email": "alice@example.com",
"subject": "Quick question about Acme's data stack",
"state": "sent",
"failure_reason": null,
"provider_message_id": "18f8a2b...",
"provider_thread_id": "18f8a2b...",
"rfc822_message_id": "<01HZ8X3J9K7P2QV6@mail.clement.so>",
"attempt_count": 1,
"scheduled_at": "2026-04-29T14:30:00Z",
"sent_at": "2026-04-29T14:30:02Z",
"created_at": "2026-04-29T14:30:00Z",
"campaign_id": null
} Errors
-
400Invalid request -
401Authentication failed -
403Insufficient scope -
404Not found -
409Conflict -
422Validation failed -
429Rate limited
See Errors for the full envelope and per-code reference.
Cancel a scheduled send
/v1/sends/{id}/cancel Only valid while the send is in state `scheduled`. Returns 409 once the worker has picked the job up (`sending` or beyond — the email may already be on its way to Gmail).
curl -X POST "https://api.clement.so/v1/sends/obj_01HZ8X3J9K7P2QV6R5N4M3T2L1/cancel" \
-H "Authorization: Bearer $CLEMENT_API_KEY" Path parameters
-
idstring required
Response200
Canceled
| Property | Type | Description | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
id
required
| string | ||||||||||||||||
object
required
| enum (1) | "send" | |||||||||||||||
mode
required
| enum (2) | "live""test" | |||||||||||||||
inbox_id
required
| string | ||||||||||||||||
inbox | SendExpandInbox | null | Present (possibly null if missing) when `?expand=inbox`. Show properties
| |||||||||||||||
to_email
required
| string (email) | ||||||||||||||||
subject
required
| string | ||||||||||||||||
state
required
| enum (4) | "scheduled""sending""sent""failed" | |||||||||||||||
failure_reason
required
| string | null | ||||||||||||||||
provider_message_id
required
| string | null | ||||||||||||||||
provider_thread_id
required
| string | null | ||||||||||||||||
rfc822_message_id
required
| string | null | ||||||||||||||||
attempt_count
required
| integer | ||||||||||||||||
scheduled_at
required
| string (date-time) | ||||||||||||||||
sent_at
required
| string (date-time) | null | ||||||||||||||||
created_at
required
| string (date-time) | ||||||||||||||||
campaign_id
required
| string | null |
Example response
{
"id": "snd_01HZ8X3J9K7P2QV6R5N4M3T2L4",
"object": "send",
"mode": "live",
"inbox_id": "inb_01HZ8X3J9K7P2QV6R5N4M3T2L1",
"to_email": "alice@example.com",
"subject": "Quick question about Acme's data stack",
"state": "sent",
"failure_reason": null,
"provider_message_id": "18f8a2b...",
"provider_thread_id": "18f8a2b...",
"rfc822_message_id": "<01HZ8X3J9K7P2QV6@mail.clement.so>",
"attempt_count": 1,
"scheduled_at": "2026-04-29T14:30:00Z",
"sent_at": "2026-04-29T14:30:02Z",
"created_at": "2026-04-29T14:30:00Z",
"campaign_id": null
} Errors
-
400Invalid request -
401Authentication failed -
403Insufficient scope -
404Not found -
409Conflict -
422Validation failed -
429Rate limited
See Errors for the full envelope and per-code reference.