REST API

Base URL https://api.reviewbump.co. All responses are JSON.

Create a campaign

POST/v1/campaigns

Validates, enqueues, and starts sending. Returns immediately with 202; sending continues in the background.

Body

  • organizationId (string, required) — the org whose review link is sent.
  • recipients(string[], required) — phone numbers in any common format; invalid & duplicate numbers are dropped.
  • name (string, optional) — a label for your own reference.
  • idempotencyKey (string, optional) — a token you choose. A repeat create with the same key returns the original campaign instead of texting everyone again, so a retry is always safe.
Request
curl -X POST https://api.reviewbump.co/v1/campaigns \
  -H "Authorization: Bearer rb_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{"organizationId":"org_123","recipients":["+17325550142","7325550188"],"idempotencyKey":"june-regulars-1"}'
202 Accepted
{ "campaignId": "cmp_abc123", "accepted": 2, "skipped": 0, "reused": false }

accepted is the number of valid, de-duplicated recipients queued; skipped is how many were dropped. If you request more than your remaining quota the call returns 402 with a remaining field. When an idempotencyKey matches an earlier campaign the response is 200 with reused: true and nothing new is sent.

Preview a campaign (dry run)

POST/v1/campaigns/preview

Same body as create (minus idempotencyKey), but it sends nothing and spends no quota. Use it to check a list before committing: how many numbers are valid, what the message says, and whether it fits your remaining quota.

200 OK
{
  "organizationId": "org_123",
  "organizationName": "Bella's Cafe",
  "message": "Bella's Cafe here. Got a few seconds to leave us a quick review?\nhttps://reviewbump.co/r/bellas-cafe\n",
  "totalProvided": 3,
  "accepted": 2,            // valid, de-duplicated
  "skipped": 1,             // invalid or duplicate
  "plan": "PRO",
  "monthlyLimit": 1000,
  "remaining": 863,
  "withinQuota": true,      // would 'accepted' fit right now?
  "sample": ["+17325550142", "+17325550188"]
}

Get a campaign

GET/v1/campaigns/{id}

Live status and counts — poll this to track progress.

200 OK
{
  "id": "cmp_abc123",
  "name": "June regulars",
  "status": "SENDING",          // SENDING | SENT | PARTIAL | FAILED
  "organizationId": "org_123",
  "totalRecipients": 250,
  "sent": 120,
  "failed": 3,
  "underway": 127,
  "createdAt": "2026-06-15T18:00:00.000Z"
}

List campaigns

GET/v1/campaigns?page=1&status=sent

Paginated (page, pageSize up to 100). Optional status filter: sending, sent, partial, failed. Returns { items, page, pageSize, total, pageCount }.

List recipients

GET/v1/campaigns/{id}/recipients?status=failed

Per-number delivery status. Optional status: sent, failed, underway. Each item is { id, phone, status, error }.

Cancel a campaign

POST/v1/campaigns/{id}/cancel

Marks all not-yet-sent recipients failed, refunds their quota, and finalizes the campaign. Already-sent texts are unaffected.

List organizations

GET/v1/organizations

Your organizations and their review links, so you know what to pass as organizationId.

200 OK
{ "items": [ { "id": "org_123", "name": "Bella's Cafe", "reviewLink": "https://reviewbump.co/r/bellas-cafe" } ] }

Get usage

GET/v1/usage

Your plan and remaining monthly text quota.

200 OK
{ "plan": "PRO", "monthlyLimit": 1000, "used": 137, "remaining": 863, "active": true }