Outbound Reminder Campaign

What you build: a campaign that dials (or texts) a list of recipients, plays a confirmation message, retries no-answers on a schedule, and reports how many succeeded. The outbound orchestrator does the pacing, retries, and per-recipient tracking for you.

recipients ─▶ POST /v1/campaigns ─▶ add targets ─▶ start
┌─────────────────────────────────── │ (paced dialing, retries)
▼ ▼
call/SMS each target webhooks: call.completed / message.delivered
│ │
▼ ▼
disposition per target ──────────────▶ your tally (succeeded / failed / no_answer)

Who it’s for: clinics reducing no-shows, lenders confirming repayments, schools and event organisers confirming attendance.

Prerequisites

  • An agent to run the conversation (for voice campaigns).
  • A webhook receiver for call.completed (voice) or message.delivered / message.failed (SMS).
  • ENABLE_OUTBOUND_VOICE / ENABLE_OUTBOUND_MESSAGES enabled on your workspace (they are, on managed accounts).

Step 1 — Create the campaign

Only channel is required. Channel-specific execution settings (caller-ID, call window, webhook) go in the free-form config block, which the orchestrator owns; retries go in retry_policy:

$curl -X POST https://api.voicebip.com/v1/campaigns \
> -H "Authorization: Bearer pk_xxx" -H "Content-Type: application/json" \
> -d @campaign.json
1{
2 "channel": "voice",
3 "agent_id": "agt_PAEZ_njcfm2kycpjs",
4 "config": {
5 "from_number": "+2341002223344",
6 "call_window": { "start": "09:00", "end": "18:00", "timezone": "Africa/Lagos" }
7 },
8 "retry_policy": { "max_attempts": 3, "backoff_seconds": 600, "backoff_multiplier": 4 }
9}
1{ "id": "camp_6r…", "channel": "voice", "status": "draft", "counters": { "total": 0 } }

The campaign starts in draft so you can add targets before any dialing happens.

Step 2 — Add recipients (targets)

Add targets in batches. Each target has a to_address and its own params — arbitrary per-recipient values the agent references (name, appointment time), so every call is personalised:

$curl -X POST https://api.voicebip.com/v1/campaigns/camp_6r…/targets \
> -H "Authorization: Bearer pk_xxx" -H "Content-Type: application/json" \
> -d '{
> "targets": [
> { "to_address": "+2348031234567", "params": { "name": "Ada", "time": "10am Thursday" } },
> { "to_address": "+2348082223344", "params": { "name": "Bode", "time": "2pm Thursday" } }
> ]
> }'
1{ "added": 2, "skipped_duplicate": 0, "rejected_invalid": 0 }

Reference the params in the agent’s system_prompt / greeting_text, e.g. “Hello {{name}}, this is a reminder about your appointment at {{time}}. Press 1 to confirm.”

Step 3 — Start it

$curl -X POST https://api.voicebip.com/v1/campaigns/camp_6r…/start \
> -H "Authorization: Bearer pk_xxx"
$# → { "id": "camp_6r…", "status": "running" }

The orchestrator now dials at its pacing, inside the call window, retrying failures per your retry_policy. Lifecycle controls:

ActionEndpoint
PausePOST /v1/campaigns/{id}/pause
ResumePOST /v1/campaigns/{id}/resume
CancelPOST /v1/campaigns/{id}/cancel
Retry only the failedPOST /v1/campaigns/{id}/retry-failed

Step 4 — Tally results from webhooks

Each finished call fires call.completed. There is no per-call “confirmed” flag — status is completed and the outcome you tally comes from the target’s disposition (voice: completed/failed/no_answer/busy) and, if you need intent, Voicebip’s AI resolution classification (resolved/unresolved). List targets to read their disposition:

$curl "https://api.voicebip.com/v1/campaigns/camp_6r…/targets?status=failed" \
> -H "Authorization: Bearer pk_xxx"
1{
2 "targets": [
3 { "id": "tgt_1a…", "to_address": "+2348082223344", "disposition": "no_answer", "attempt_count": 3 }
4 ]
5}

For SMS campaigns, watch message.delivered and message.failed; the SMS dispositions are sent/delivered/undeliv/opted_out.

Poll live counters any time:

$curl https://api.voicebip.com/v1/campaigns/camp_6r… \
> -H "Authorization: Bearer pk_xxx"
1{
2 "id": "camp_6r…",
3 "status": "running",
4 "counters": { "total": 2, "queued": 0, "dispatched": 1, "succeeded": 1, "failed": 0 }
5}

SMS variant

For a text-only reminder, set channel: "sms" and drop the agent — put the message body (with per-target params) in the campaign config. Everything else (targets, retries, lifecycle) is identical.

Test it (sandbox)

Run the whole campaign against pk_test_ with targets in the test range (+234800000xxxx) — the orchestrator paces and “dials” synthetically, ₦0 billing. Then simulate a completion:

$curl -X POST https://api.voicebip.com/v1/webhooks/test \
> -H "Authorization: Bearer pk_test_xxx" -H "Content-Type: application/json" \
> -d '{ "webhook_url": "https://you.example.com/webhooks", "event_type": "call.completed" }'

Troubleshooting

SymptomLikely cause
Campaign stuck in draftYou never called /start.
Nothing dialsOutside the call window, or workspace outbound flag off.
Targets rejected_invalid on addMalformed E.164 in to_address.
Variables not spokenThe agent prompt doesn’t reference {{name}} / {{time}}.

Next steps