SendRaven

Docs

Campaigns

Audiences, a preview you should always run, and a send that cannot be recalled.

A campaign mails an audience, or a segment of it, from a marketing identity. The order is: build the audience, create the campaign as a draft, preview it, then send.

Audiences and contacts

POST /v1/audiences with a name creates a list. POST /v1/audiences/{id}/contacts accepts either one contact — email, first_name, last_name — or an array of up to 5,000 of them. Importing a list one call at a time is how a migration takes a week, so use the array. A contact exists once per workspace and can be on any number of audiences; adding an address that already exists joins it to this list rather than creating a second copy.

GET /v1/contacts?email= finds an address across every audience. DELETE /v1/audiences/{id}/contacts/{contactId} takes someone off one list; DELETE /v1/contacts/{id} removes them from the workspace. Both keep the person's suppression and topic preferences — those belong to the person, and discarding them would mean a re-import mails someone who opted out.

curl -X POST https://api.example.com/v1/audiences/$AUDIENCE_ID/contacts \
  -H "Authorization: Bearer $API_KEY" \
  -d '[
    {"email": "ana@example.com", "first_name": "Ana"},
    {"email": "ben@example.com", "first_name": "Ben"}
  ]'

Creating a campaign

POST /v1/broadcasts takes audience_id, identity_id, name, subject and html. Narrow the audience with a saved segment_id, or an inline segment of opened_within_days, clicked_within_days and exclude_unengaged_days; a saved segment wins when both are given. Pass topic_key so recipients can opt out of this kind of mail rather than everything you send.

The identity must be a marketing one — GET /v1/domains lists each with its risk_class. A campaign is created as a draft and can be edited with PATCH /v1/broadcasts/{id} while it is still one — once scheduled or sent it answers 409 invalid_state.

{
  "audience_id": "…",
  "identity_id": "…",
  "name": "September update",
  "subject": "What's new this month",
  "html": "<p>…</p>",
  "topic_key": "newsletter",
  "segment": { "exclude_unengaged_days": 180 }
}

Preview first

GET /v1/broadcasts/{id}/preview returns recipient_count — the number who will actually receive it, after suppressed addresses and topic opt-outs are removed — beside resolved_count and suppressed_count, a sample of addresses, and can_send. The gap between resolved and receiving is exactly the people who opted out, which is the number worth seeing before a send.

can_send is the reputation gate. Once a workspace has sent a thousand messages in the last fourteen days, a bounce rate above 4% or a complaint rate above 0.08% over that window refuses the campaign, and blocked_reason says which and what to do about it. The gate sits in the send path rather than on a dashboard because its whole point is to refuse the send that would tip the account over.

Preview is a separate call on purpose: nobody should discover the size of a 200k campaign by starting it.

Sending

POST /v1/broadcasts/{id}/send with an empty body starts it now and returns 202 with status: "sending". With scheduled_at — an ISO 8601 timestamp, not the relative phrases POST /v1/emails accepts — it returns 202 with status: "scheduled". The fan-out runs in the background, because a large send takes far longer than any HTTP timeout; poll GET /v1/broadcasts/{id} for progress and GET /v1/broadcasts/{id}/recipients for what happened to each message.

Once started it cannot be recalled. The reputation gate runs again at send time, and a claim on the row means two callers cannot both start the same campaign. DELETE /v1/broadcasts/{id} removes a draft or a scheduled campaign before it starts, and answers 409 in_flight for one mid-send.

Refused whole, not sent partly

Campaigns go out on the marketing identity

Every message in a campaign is sent as marketing, on the news. subdomain with its own reputation, and a campaign pointed at a transactional identity fails rather than sending. That separation is what stops a campaign's complaint rate from affecting password reset delivery. Marketing mail also carries the one-click unsubscribe headers and a footer with your postal address — a workspace without one set is refused with no_postal_address.

Next: Automations