# Clement API — full reference for agents Clement is the API-first cold-email platform. - Base URL: https://api.clement.so - Auth: `Authorization: Bearer cl_live_…` (or `cl_test_…` for sandbox). - IDs: type-prefixed ULIDs (`inb_…`, `cmp_…`, `snd_…`, `whk_…`). - Pagination: cursor (`limit`, `starting_after`, `ending_before`). - Idempotency: `Idempotency-Key` header **required** on /sends, /threads/{id}/replies, /contact_imports, /suppression_imports. - Errors: see Errors section. Every error envelope carries `code` and `doc_url`. - Confirmation: `?confirm=true` required on DELETE /inboxes/{id}, DELETE /api_keys/{id}, POST /api_keys/{id}/rotate, DELETE /audiences/{id} when non-empty. - OpenAPI spec: https://api.clement.so/openapi.json - MCP server (phase A8): https://mcp.clement.so ## Endpoints ### Meta Reference: https://clement.so/docs/reference/meta/ - `GET /v1/health` — Liveness probe ### Workspace Reference: https://clement.so/docs/reference/workspace/ - `GET /v1/workspace` — Retrieve the workspace bound to this key ### API keys Reference: https://clement.so/docs/reference/api-keys/ - `GET /v1/api_keys` — List API keys in the workspace - `POST /v1/api_keys` — Create an API key (secret returned once) - `DELETE /v1/api_keys/{id}` — Revoke an API key - `POST /v1/api_keys/{id}/rotate` — Rotate an API key (issues a new secret, revokes the old one) ### Inboxes Reference: https://clement.so/docs/reference/inboxes/ - `GET /v1/inboxes` — List inboxes in the workspace - `POST /v1/inboxes/google/connect_link` — Mint a one-time Gmail OAuth connect URL - `POST /v1/inboxes/sandbox` — Create a sandbox inbox (test mode only) - `POST /v1/inboxes/smtp` — Connect an SMTP/IMAP inbox - `GET /v1/inboxes/{id}` — Retrieve an inbox - `PATCH /v1/inboxes/{id}` — Update an inbox's settings - `DELETE /v1/inboxes/{id}` — Delete an inbox (sandbox only via API) ### Sends Reference: https://clement.so/docs/reference/sends/ - `GET /v1/sends` — List sends - `POST /v1/sends` — Send an email (single or fan-out across inboxes) *(Idempotency-Key required)* - `GET /v1/sends/{id}` — Retrieve a send - `POST /v1/sends/{id}/cancel` — Cancel a scheduled send ### Messages Reference: https://clement.so/docs/reference/messages/ - `GET /v1/messages` — List messages - `GET /v1/messages/{id}` — Retrieve a message - `GET /v1/messages/{id}/body` — Retrieve a message's body ### Threads Reference: https://clement.so/docs/reference/threads/ - `GET /v1/threads` — List threads - `GET /v1/threads/{id}` — Retrieve a thread (with messages embedded) - `POST /v1/threads/{id}/replies` — Reply in a thread (sugar over POST /v1/sends) *(Idempotency-Key required)* ### Contacts Reference: https://clement.so/docs/reference/contacts/ - `GET /v1/contact_imports` — List contact import jobs - `POST /v1/contact_imports` — Bulk-import contacts from a CSV *(Idempotency-Key required)* - `GET /v1/contact_imports/{id}` — Retrieve a contact import job - `GET /v1/contacts` — List contacts - `POST /v1/contacts` — Create a contact (idempotent on email) - `POST /v1/contacts/batch` — Create up to 1,000 contacts in one call - `GET /v1/contacts/{id}` — Retrieve a contact - `PATCH /v1/contacts/{id}` — Update a contact - `DELETE /v1/contacts/{id}` — Delete a contact - `POST /v1/contacts/{id}/lead_status` — Set a contact's lead status ### Audiences Reference: https://clement.so/docs/reference/audiences/ - `GET /v1/audiences` — List audiences - `POST /v1/audiences` — Create an audience - `GET /v1/audiences/{id}` — Retrieve an audience - `PATCH /v1/audiences/{id}` — Update an audience - `DELETE /v1/audiences/{id}` — Delete an audience - `POST /v1/audiences/{id}/contacts` — Attach contacts to an audience - `DELETE /v1/audiences/{id}/contacts/{contact_id}` — Detach one contact from an audience ### Sequences Reference: https://clement.so/docs/reference/sequences/ - `GET /v1/sequences` — List sequences - `POST /v1/sequences` — Create a sequence (optionally with initial steps) - `GET /v1/sequences/{id}` — Retrieve a sequence (with steps embedded) - `PATCH /v1/sequences/{id}` — Update sequence metadata - `DELETE /v1/sequences/{id}` — Delete a sequence - `POST /v1/sequences/{id}/steps` — Add a step to a sequence - `POST /v1/sequences/{id}/steps/reorder` — Reorder a sequence's steps - `PATCH /v1/sequences/{id}/steps/{step_id}` — Update a step - `DELETE /v1/sequences/{id}/steps/{step_id}` — Delete a step ### Campaigns Reference: https://clement.so/docs/reference/campaigns/ - `GET /v1/campaigns` — List campaigns - `POST /v1/campaigns` — Create a campaign (snapshots the source sequence's steps) - `GET /v1/campaigns/{id}` — Retrieve a campaign (with sequence steps embedded) - `PATCH /v1/campaigns/{id}` — Update a campaign - `DELETE /v1/campaigns/{id}` — Delete a campaign - `GET /v1/campaigns/{id}/contacts` — List contacts attached to this campaign with progress - `POST /v1/campaigns/{id}/contacts` — Attach contacts (or an audience) to a campaign - `POST /v1/campaigns/{id}/contacts/move` — Move or copy contacts to another campaign - `POST /v1/campaigns/{id}/contacts/remove` — Remove contacts from a campaign (bulk) - `DELETE /v1/campaigns/{id}/contacts/{contact_id}` — Remove a contact from a campaign - `POST /v1/campaigns/{id}/duplicate` — Duplicate a campaign - `POST /v1/campaigns/{id}/pause` — Pause a running campaign - `GET /v1/campaigns/{id}/preview` — Preview a campaign's emails for a lead - `POST /v1/campaigns/{id}/resume` — Resume a paused campaign - `POST /v1/campaigns/{id}/start` — Start a campaign (or preview with ?dry_run=true) - `GET /v1/campaigns/{id}/stats` — Campaign aggregate stats - `POST /v1/campaigns/{id}/steps` — Add a step to a campaign - `POST /v1/campaigns/{id}/steps/reorder` — Reorder a campaign's steps - `PATCH /v1/campaigns/{id}/steps/{step_id}` — Update a campaign step - `DELETE /v1/campaigns/{id}/steps/{step_id}` — Delete a campaign step - `POST /v1/campaigns/{id}/test_send` — Send a test email of one campaign step ### Suppressions Reference: https://clement.so/docs/reference/suppressions/ - `GET /v1/suppressions` — List suppressions - `POST /v1/suppressions` — Add an email to the suppression list - `POST /v1/suppressions/batch` — Add up to 1,000 suppressions in one call - `GET /v1/suppressions/{id}` — Retrieve a suppression - `DELETE /v1/suppressions/{id}` — Remove a suppression ### Events Reference: https://clement.so/docs/reference/events/ - `GET /v1/events` — List events - `GET /v1/events/{id}` — Retrieve an event ### Webhooks Reference: https://clement.so/docs/reference/webhooks/ - `GET /v1/webhooks` — List webhook endpoints - `POST /v1/webhooks` — Create a webhook endpoint (signing secret returned once) - `GET /v1/webhooks/{id}` — Retrieve a webhook endpoint - `PATCH /v1/webhooks/{id}` — Update a webhook endpoint - `DELETE /v1/webhooks/{id}` — Delete a webhook endpoint - `GET /v1/webhooks/{id}/deliveries` — List delivery attempts for this endpoint - `GET /v1/webhooks/{id}/deliveries/{delivery_id}` — Retrieve a single delivery attempt - `POST /v1/webhooks/{id}/deliveries/{delivery_id}/redeliver` — Replay a delivery (creates a new attempt with the same payload) - `POST /v1/webhooks/{id}/rotate` — Rotate the signing secret - `POST /v1/webhooks/{id}/test` — Send a synthetic test delivery to this endpoint ## Errors - `unauthenticated` (authentication_error, HTTP 401) — No valid bearer key or session cookie was found on the request. → https://clement.so/docs/errors/unauthenticated/ - `api_key_revoked` (conflict, HTTP 409) — The presented key was valid once, but has been revoked. → https://clement.so/docs/errors/api_key_revoked/ - `forbidden` (authorization_error, HTTP 403) — The key authenticated, but its scope tier doesn't permit this action. → https://clement.so/docs/errors/forbidden/ - `resource_not_found` (not_found, HTTP 404) — The resource doesn't exist or isn't visible to this workspace. → https://clement.so/docs/errors/resource_not_found/ - `invalid_request` (invalid_request_error, HTTP 400) — The request was rejected before validation — usually a missing or malformed field. → https://clement.so/docs/errors/invalid_request/ - `validation_failed` (unprocessable_entity, HTTP 422) — The body parsed as JSON but failed Zod schema validation. → https://clement.so/docs/errors/validation_failed/ - `idempotency_key_required` (invalid_request_error, HTTP 400) — A side-effect-bearing POST was missing the `Idempotency-Key` header. → https://clement.so/docs/errors/idempotency_key_required/ - `idempotency_key_in_use` (conflict, HTTP 409) — The `Idempotency-Key` was reused with a different request body. → https://clement.so/docs/errors/idempotency_key_in_use/ - `idempotency_request_in_progress` (conflict, HTTP 409) — Another request with this `Idempotency-Key` is still running. → https://clement.so/docs/errors/idempotency_request_in_progress/ - `idempotency_replay_unavailable` (conflict, HTTP 409) — The request already succeeded, but its response held a one-time secret. → https://clement.so/docs/errors/idempotency_replay_unavailable/ - `confirmation_required` (invalid_request_error, HTTP 400) — A high-blast-radius destructive op was called without `?confirm=true`. → https://clement.so/docs/errors/confirmation_required/ - `rate_limit_exceeded_key` (rate_limit_error, HTTP 429) — This API key exceeded its sustained or burst request rate. → https://clement.so/docs/errors/rate_limit_exceeded_key/ - `rate_limit_exceeded_workspace` (rate_limit_error, HTTP 429) — The workspace exceeded its aggregate request rate across all keys. → https://clement.so/docs/errors/rate_limit_exceeded_workspace/ - `subscription_required` (authorization_error, HTTP 402) — The workspace has no active plan. → https://clement.so/docs/errors/subscription_required/ - `quota_exceeded` (rate_limit_error, HTTP 429) — The workspace hit a plan-level quota (sends, contacts, webhooks). → https://clement.so/docs/errors/quota_exceeded/ - `invalid_state_transition` (conflict, HTTP 409) — The resource is in a state that doesn't permit the requested transition. → https://clement.so/docs/errors/invalid_state_transition/ - `inbox_connection_failed` (unprocessable_entity, HTTP 422) — Clement couldn't log in to the SMTP or IMAP server you supplied. → https://clement.so/docs/errors/inbox_connection_failed/ - `inbox_provider_conflict` (conflict, HTTP 409) — The address is already connected through another provider. → https://clement.so/docs/errors/inbox_provider_conflict/ - `invalid_email` (invalid_request_error, HTTP 400) — An email address didn't pass syntactic validation. → https://clement.so/docs/errors/invalid_email/ - `invalid_contact_id` (invalid_request_error, HTTP 400) — An ID in `contact_ids` didn't decode as a contact ID. → https://clement.so/docs/errors/invalid_contact_id/ - `duplicate_in_batch` (invalid_request_error, HTTP 400) — A batch payload contained duplicate entries (same email or same ID). → https://clement.so/docs/errors/duplicate_in_batch/ - `missing_email_column` (invalid_request_error, HTTP 400) — A CSV import didn't map any column to `email`. → https://clement.so/docs/errors/missing_email_column/ - `too_many_rows` (invalid_request_error, HTTP 400) — A bulk endpoint received more rows than its per-call cap. → https://clement.so/docs/errors/too_many_rows/ - `internal_error` (server_error, HTTP 500) — An unexpected error escaped a route handler. → https://clement.so/docs/errors/internal_error/ ## Webhook events - `inbox.connected` (Inbox) — An inbox finished OAuth or SMTP credential verification and is ready to send. - `inbox.disconnected` (Inbox) — An inbox was removed by the customer or revoked at the provider. - `inbox.token_expired` (Inbox) — OAuth refresh failed; the inbox needs reconnecting before sends resume. - `inbox.health_changed` (Inbox) — Health tier transitioned (good ↔ degraded ↔ paused). Fires on tier changes only, not on every score tick. - `contact.created` (Contact) — A new contact was created (single, batch, or CSV import). - `contact.updated` (Contact) — A contact's email, attributes, or global_status was modified. - `contact.deleted` (Contact) — A contact was hard-deleted. Historical sends keep their email snapshot. - `contact.unsubscribed` (Contact) — Global status flipped to `unsubscribed`. Carries the source: `campaign_id` or `manual`. - `contact.bounced` (Contact) — Global status flipped to `bounced` after a hard bounce. - `contact.lead_status_changed` (Contact) — A lead was classified in the unified inbox (e.g. `interested`, `meeting_booked`). Carries `lead_status` and `previous_lead_status`. - `send.scheduled` (Send) — Send row written; worker job enqueued. - `send.sending` (Send) — Worker has the lock; provider call is in flight. - `send.sent` (Send) — Provider accepted the message. - `send.failed` (Send) — Provider rejected the message or the worker timed out. - `send.canceled` (Send) — Customer canceled a `scheduled` send via `POST /v1/sends/{id}/cancel`. - `message.received` (Message) — Any inbound message landed in a connected inbox. - `message.replied` (Message) — An inbound message was classified as a real reply to one of our sends. - `message.bounced` (Message) — An inbound bounce report tied to one of our sends. Carries `bounce_type` (`hard`, `soft` or `unknown`), `bounce_status` (the DSN status code, e.g. `5.1.1`) and `bounce_diagnostic`. Hard bounces also suppress the address; soft bounces don't. - `message.autoresponse` (Message) — An inbound autoresponder (out-of-office, ticket-system ack). - `message.opened` (Message) *high-volume* — Tracking pixel hit. **High-volume.** Excluded from the recommended starter wildcard. - `message.clicked` (Message) *high-volume* — Tracked link clicked. Carries `url`. **High-volume.** - `campaign.started` (Campaign) — Campaign transitioned `draft → running`. - `campaign.paused` (Campaign) — Campaign transitioned `running → paused`. - `campaign.resumed` (Campaign) — Campaign transitioned `paused → running`, or `completed → running` because new contacts were attached. - `campaign.completed` (Campaign) — No contact is still active in the sequence (all finished, replied, bounced, unsubscribed or failed); campaign is `completed`. Attaching new contacts reopens it. - `campaign.contact.advanced` (Campaign) *high-volume* — A contact moved to the next sequence step. **High-volume.** - `import.completed` (Import) — A CSV / suppression import finished successfully. - `import.failed` (Import) — A CSV / suppression import failed with per-row errors. - `usage.threshold_reached` (Workspace) — 80% or 100% of a plan-level quota (sends, contacts, webhooks). - `webhook.delivery.failed` (Webhook) — An endpoint exhausted its retry schedule (the first attempt plus six retries after 1m → 5m → 30m → 2h → 8h → 24h) without ever 2xx-ing. Delivered to *other* endpoints of the same mode in the workspace — a failing endpoint can't notify itself. ## Guides - Quickstart — https://clement.so/docs/quickstart/ - Authentication — https://clement.so/docs/guides/authentication/ - Send your first email — https://clement.so/docs/guides/sends/ - Import contacts — https://clement.so/docs/guides/contacts/ - Run a campaign — https://clement.so/docs/guides/campaigns/ - Webhooks — https://clement.so/docs/guides/webhooks/ - Test mode — https://clement.so/docs/guides/test-mode/ - Agent integration — https://clement.so/docs/guides/agents/