Campaigns API
A campaign is a single broadcast push sent to a segment of your audience. The Campaigns API mirrors what the dashboard's campaign builder does — create, schedule, send, edit, delete, watch live progress, and export results.
All routes require authentication. Server-side callers should use x-api-key; dashboard sessions use JWT + x-org-id. See Authentication.
Campaign body shape
Every create and update request uses the same body shape:
{
"name": "Spring sale launch",
"projectId": "proj_01HX2...",
"content": {
"title": "Spring sale is live",
"body": "30% off everything until Sunday.",
"iconUrl": "https://cdn.example.com/icon-192.png",
"imageUrl": "https://cdn.example.com/hero.jpg",
"clickUrl": "https://example.com/sale",
"actions": [
{ "action": "shop", "title": "Shop now" }
]
},
"segment": {
"filters": { "country": ["US", "CA"], "tags": ["newsletter"] }
},
"schedule": {
"mode": "scheduled",
"sendAt": "2026-06-15T14:00:00.000Z",
"timezone": "America/New_York"
},
"utm": {
"source": "reachbell",
"medium": "push",
"campaign": "spring-sale"
}
}
schedule.modeis"immediate","scheduled", or"draft".segmentis either inline filters (above) or{ "savedSegmentId": "seg_..." }.utmis optional. If present, ReachBell appends the params tocontent.clickUrland to every action URL.
Create and send
POST /campaigns
Create a campaign. If schedule.mode is "immediate", ReachBell starts sending right away. "scheduled" queues it for sendAt. "draft" saves without dispatch.
curl -X POST https://api.reachbell.com/campaigns \
-H "x-api-key: rb_live_yourkey" \
-H "Content-Type: application/json" \
-d '{
"name": "Spring sale launch",
"projectId": "proj_01HX2...",
"content": {
"title": "Spring sale is live",
"body": "30% off everything until Sunday.",
"iconUrl": "https://cdn.example.com/icon-192.png",
"clickUrl": "https://example.com/sale"
},
"segment": { "filters": { "country": ["US"] } },
"schedule": { "mode": "immediate" },
"utm": { "source": "reachbell", "medium": "push", "campaign": "spring-sale" }
}'
Success:
{
"id": "cmp_01HX5...",
"name": "Spring sale launch",
"status": "sending",
"stats": { "queued": 14823, "sent": 0, "clicked": 0, "failed": 0 },
"createdAt": "2026-06-12T09:00:00.000Z"
}
List campaigns
GET /campaigns/project/:projectId
Paginated. Filters: status, from, to, q (name search).
curl "https://api.reachbell.com/campaigns/project/proj_01HX2...?status=sent&pageSize=20" \
-H "x-api-key: rb_live_yourkey"
Get campaign detail with stats
GET /campaigns/:id
Returns the campaign object including the full stats block: queued, sent, delivered, clicked, dismissed, failed, ctr, deliveryRate.
curl https://api.reachbell.com/campaigns/cmp_01HX5... \
-H "x-api-key: rb_live_yourkey"
Update a draft
PATCH /campaigns/:id
Only campaigns with status: "draft" can be edited. Once a campaign starts sending the API rejects the patch with 409 Conflict.
curl -X PATCH https://api.reachbell.com/campaigns/cmp_01HX5... \
-H "x-api-key: rb_live_yourkey" \
-H "Content-Type: application/json" \
-d '{ "content": { "title": "Spring sale — last chance" } }'
Delete
DELETE /campaigns/:id
Deletes a draft, scheduled, or cancelled campaign. Sent campaigns are archived rather than destroyed — the delete returns 409 and you should archive from the dashboard instead.
curl -X DELETE https://api.reachbell.com/campaigns/cmp_01HX5... \
-H "x-api-key: rb_live_yourkey"
Re-send
POST /campaigns/:id/send
Re-dispatch a sent or cancelled campaign. The campaign content and segment are reused; you can pass an override segment in the body.
curl -X POST https://api.reachbell.com/campaigns/cmp_01HX5.../send \
-H "x-api-key: rb_live_yourkey" \
-H "Content-Type: application/json" \
-d '{ "segment": { "filters": { "tags": ["did-not-open"] } } }'
Re-sends count as a fresh campaign in your stats. The original campaign's numbers are not mutated.
Live progress over SSE
GET /campaigns/:id/stream?token=<JWT>&orgId=<orgId>
Server-sent events stream of delivery progress. The dashboard uses this to power the live progress bar on the campaign detail page. Each event is a JSON object with the current stats snapshot.
curl "https://api.reachbell.com/campaigns/cmp_01HX5.../stream?token=eyJ...&orgId=org_01HX1..." \
-H "Accept: text/event-stream"
Sample event payload:
{
"queued": 14823,
"sent": 9211,
"clicked": 412,
"failed": 18,
"status": "sending"
}
The SSE endpoint is JWT-only (query params, since browsers can't set headers on
EventSource). API key callers should pollGET /campaigns/:idinstead.
Export results to CSV
GET /campaigns/export/project/:projectId.csv
Streams a CSV of every campaign on the project with stats columns. Useful for spreadsheet analysis or warehouse imports.
curl "https://api.reachbell.com/campaigns/export/project/proj_01HX2....csv?from=2026-01-01&to=2026-06-30" \
-H "x-api-key: rb_live_yourkey" \
-o campaigns.csv
What's next?
- Run an A/B test inside a campaign to find the highest-CTR variant.
- Build a reusable segment to target campaigns precisely.
- Attribute every click with UTM tracking.