API Reference

Bulk send

Draft a campaign to a whole segment. This endpoint does not send — it hands the draft to a human, who approves or discards it in the app. It is the one endpoint built for software that writes marketing email, and the approval step is why we are comfortable offering it.

Overview

MethodPathDescription
POST/api/v1/send/bulkDraft a campaign to a segment and hold it for approval.

Requires the email:send_bulk scope. A transactional email:send key is rejected here with 403 insufficient_scope, on purpose: a key that sends receipts should not be able to mail your whole list. The scope is never granted to an OAuth-connected agent and never inherited by default — see Scopes.

Nothing sends without a human

A successful call returns pending_approval. At that moment no recipient has been queued and no email has been sent. The workspace owner sees the draft in the app with the segment, the recipient count, a rendered preview and the deliverability verdict, and chooses to send, edit or cancel it.

The approval cannot come from the API. Approving is a signed-in action in the dashboard, so the software that drafted the campaign cannot approve its own work — and if nobody ever approves it, nothing is ever sent. Editing the draft in the app invalidates the earlier approval, so what goes out is always what someone actually looked at.

There is no dry run for bulk. On approval this sends real email to every subscribed contact in the segment. The sandbox covers transactional sends only — a ps_test_ key can draft a bulk send, and approving it delivers for real. To rehearse content, send yourself a normal transactional message first.

Draft a bulk send

POST/api/v1/send/bulk

Request body

FieldTypeRequiredDescription
segment_idstring (uuid)requiredAn existing audience segment in your workspace. Create one with POST /segments, or build it in the app. An unknown or foreign id returns 404.
subjectstringrequiredSubject line. The approver sees this before deciding.
htmlstringrequiredHTML body. The campaign footer and one-click unsubscribe are added automatically — you don't supply them.

Response

FieldTypeDescription
status"pending_approval"Always this value. It is the only outcome this endpoint has.
approval_idstring (uuid)The held campaign's id. It appears in the workspace owner's approvals queue.
recipient_countnumberSubscribed, non-suppressed contacts the segment resolved to at draft time. The reviewed set is frozen here, so approving sends to exactly these people.
deliverabilityobject | nullThe content verdict shown to the approver, in the same shape as the deliverability check. null when the check was unavailable — which does not block the draft.
"color:#79c0ff">curl "color:#ff7b72">-X POST https://pristinesend.com/api/v1/send/bulk \
  "color:#ff7b72">-H "Authorization: Bearer ps_live_YOUR_API_KEY" \
  "color:#ff7b72">-H "Content">-Type: application/json" \
  "color:#ff7b72">-d "color:#a5d6ff">'{
    "segment_id": "3f1c9a1b-2d4e-4f60-8182-930412345678",
    "subject": "Spring update",
    "html": "<p>Here is what shipped this month.</p>"
  }'

The campaign uses your workspace default sender, and suppression, the footer and one-click unsubscribe are applied at send time — the same path a campaign built in the app takes.

Following the outcome

There is no callback when someone approves. Poll GET /events or GET /emails — once the campaign is approved its sends appear there like any other, with delivery and engagement events following. A draft nobody approves simply produces nothing, which is the intended behaviour rather than a failure to handle.

Errors

StatuscodeWhen
400missing_fieldsegment_id, subject or html absent.
400invalid_fieldA field is present but the wrong type, segment_id is not a UUID, or the segment currently resolves to no subscribed recipients (param: segment_id).
401unauthorizedMissing or invalid API key.
403insufficient_scopeThe key lacks email:send_bulk.
403account_not_approvedThe workspace is not approved for sending yet.
404not_foundNo such segment in this workspace. A segment belonging to another workspace returns 404 too — never a hint that it exists.
429rate_limitedPer-key rate limit exceeded.

See Error codes for the envelope and the full list.