Campaign orchestration
This capability is granted by an API key scoped to the `` product (product face). See the product reference below.
Outbound multi-channel campaign engine — define a campaign over an audience (a channel + a message template + a pacing/rate-limit + a schedule window), add contacts, and start it. An owner-elected pacer (single-owner Postgres advisory-lock election + FOR UPDATE SKIP LOCKED contact claim) selects due contacts respecting a per-minute rate budget derived from the persisted dispatch history (correct across ticks/restarts/failover) and dispatches each by POSTing the campaign's dispatch_endpoint (a channel capability) — it never sends bytes itself. Own logical Postgres store (I4). Dispatch/callback service tokens are resolved server-side (Infisical), never stored per-campaign or logged.
- Group: Comms & workflow
- Contract:
contracts/campaign-orchestration/v1/openapi.yaml - Public base:
https://api.vagarylabs.com(the consolidated API gateway — one host, per-brand siblingapi.<zone>) - Auth: a product API key (
vgk_…) issued from the console —Authorization: Bearer vgk_… - Product face (customer-keyed):
https://api.vagarylabs.com/product/v1/campaigns
Endpoints
| Method | Path | Summary |
|---|---|---|
POST | /v1/campaigns | Define (upsert) a campaign |
GET | /v1/campaigns | List the caller's org campaigns |
GET | /v1/campaigns/{campaign_id} | Get one campaign |
PATCH | /v1/campaigns/{campaign_id} | Update pacing / schedule / template / retry (not status) |
POST | /v1/campaigns/{campaign_id}/start | Start (or, for a future start_at, schedule) dispatching |
POST | /v1/campaigns/{campaign_id}/pause | Pause dispatching |
POST | /v1/campaigns/{campaign_id}/contacts | Add audience contacts (bulk, idempotent on contact_id) |
GET | /v1/campaigns/{campaign_id}/stats | Live campaign stats (contacts by status + dispatch counts + trailing-minute rate) |
POST | /internal/campaigns/{campaign_id}/activate | Scheduler callback — flip a scheduled campaign to running |
POST | /internal/campaigns/{campaign_id}/pace | Run exactly ONE pacing pass for a campaign. Cadence lives in the scheduler, not here; the budget cap holds regardless of call frequency because budget is derived from persisted dispatch history. |
GET | /health | liveness |
GET | /metrics | Prometheus |
Schemas
Pacing
dispatch-rate governance. rate is the channel-agnostic default; progressive/predictive/power are the restored voice pacing family generalized to available_capacity.
| Field | Type | Description |
|---|---|---|
rate_limit_per_minute | integer | hard per-minute dispatch ceiling (always enforced) |
mode | string | |
lines_per_capacity | number | |
power_lines_per_capacity | number | |
max_failure_rate | number |
ScheduleWindow
| Field | Type | Description |
|---|---|---|
start_hour | integer | |
end_hour | integer | |
days | array | 0=Mon … 6=Sun |
timezone | string | IANA tz (e.g. America/New_York); default UTC |
Schedule
| Field | Type | Description |
|---|---|---|
start_at | string | future start → durable delayed-start via the scheduler capability |
end_at | string | |
window | object |
CampaignRequest
| Field | Type | Description |
|---|---|---|
organization_id | string | product-tier tenant (I6) |
campaign_id | string | |
name | string | |
channel | string | |
dispatch_endpoint | string | http(s) URL of the channel capability that SENDS each contact |
message_template | object | |
pacing | object | |
schedule | object | |
max_attempts | integer | |
retry_delay_seconds | integer |
CampaignPatch
| Field | Type | Description |
|---|---|---|
name | string | |
message_template | object | |
pacing | object | |
schedule | object | |
max_attempts | integer | |
retry_delay_seconds | integer | |
dispatch_endpoint | string |
Campaign
| Field | Type | Description |
|---|---|---|
organization_id | string | |
campaign_id | string | |
name | string | |
channel | string | |
dispatch_endpoint | string | |
message_template | object | |
pacing | object | |
schedule | object | |
max_attempts | integer | |
retry_delay_seconds | integer | |
status | string | |
created_at | string | |
updated_at | string |
Contact
| Field | Type | Description |
|---|---|---|
contact_id | string | |
address | string | channel address — phone / email / webhook target |
custom_fields | object |
ContactsRequest
| Field | Type | Description |
|---|---|---|
contacts | array |
Generated by scripts/gen-capability-docs.py from contracts/campaign-orchestration/v1/openapi.yaml — the contract IS the source of truth; edit the contract, not this page.