Resource
SMS Broadcasts
Headless equivalent of the agency Broadcasts dashboard. Create a broadcast against a CRM list (or a smart list), approve it, and send it now or on schedule.
Tenancy + agent
Broadcasts pin
org_id, client_id, AND agent_id. The agent must be an SMS agent owned by that client; cross-client agent ids return 422 unprocessable. Client-scoped keys auto- narrow client_id to their bound client.List broadcasts#
Paginated list
GET
/v1/sms-broadcastsQuery parameters
agent_iduuidNarrow to one SMS agent.
statusstringFilter —
draft, scheduled, pending_approval, approved, sending, completed, cancelled.limitintegerdefault: 50page_tokenstringCreate a broadcast#
Create a draft, scheduled, or recurring broadcast
POST
/v1/sms-broadcastsCreates the broadcast row and resolves the recipient list. Sends and approvals are separate endpoints.
•
•
•
schedule_mode picks the lifecycle:•
one_shot — created as draft; you call send-now when ready.•
scheduled — fires once at scheduled_at.•
recurring — fires on therecurrence_rule (RRULE syntax) inrecurrence_timezone.Body parameters
agent_iduuidRequired. SMS agent that owns the conversation.
client_iduuidRequired when using an agency key without X-Gary-Client-Id.
list_iduuidCRM list to send to. One of list_id or smart_list_slug is required.
smart_list_slugstringSmart list (e.g. inbound_no_book_30d). Resolved at send time.
namestringInternal label, ≤200 chars.
bodystringMessage body, ≤1600 chars. Use {{first_name}} / {{last_name}} placeholders.
media_urlsstring[]Up to 10 MMS attachment URLs.
schedule_modestringone_shot (default) | scheduled | recurring.
scheduled_atiso datetimeRequired when schedule_mode=scheduled.
recurrence_rulestringiCalendar RRULE; required when schedule_mode=recurring.
recurrence_timezonestringIANA tz, default UTC.
Request
curl -X POST \
https://agency.gary.club/api/public/v1/sms-broadcasts \
-H "Authorization: Bearer cl_live_EXAMPLE_AbCdEfGhIj0123456789" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "agent_3kf9ab",
"list_id": "list_EXAMPLE_aaaa",
"name": "Spring promo — leads who never booked",
"body": "Hey {{first_name}}, the spring tune-up special ends Friday. Reply Y to grab a slot.",
"schedule_mode": "scheduled",
"scheduled_at": "2026-04-29T15:00:00.000Z"
}'Response
{
"broadcast": {
"id": "bc_EXAMPLE_aaaa",
"client_id": "ccccccc-cccc-4ccc-cccc-cccccccccccc",
"agent_id": "agent_3kf9ab",
"list_id": "list_EXAMPLE_aaaa",
"name": "Spring promo — leads who never booked",
"body": "Hey {{first_name}}, the spring tune-up special ends Friday. Reply Y to grab a slot.",
"status": "scheduled",
"schedule_mode": "scheduled",
"scheduled_at": "2026-04-29T15:00:00.000Z",
"next_run_at": "2026-04-29T15:00:00.000Z",
"recipient_count": 0,
"delivered_count": 0,
"failed_count": 0,
"optout_count": 0,
"requires_approval": true,
"approved_at": null,
"estimated_credits": null,
"created_at": "2026-04-28T01:18:53.000Z"
}
}Read one#
Single broadcast with stats
GET
/v1/sms-broadcasts/{id}Path parameters
iduuidrequiredBroadcast id.
Update#
Update mutable fields (only while in draft / scheduled)
PATCH
/v1/sms-broadcasts/{id}Path parameters
iduuidrequiredApprove#
Approve a broadcast that needs sign-off
POST
/v1/sms-broadcasts/{id}/approveSome broadcasts (large recipient counts, high-cost projections, agency policy) land with
requires_approval=true. This endpoint flips them to approved so they can send.Path parameters
iduuidrequiredSend now#
Force-send a draft or scheduled broadcast immediately
POST
/v1/sms-broadcasts/{id}/send-nowPushes next_run_at to now and flips to sending state. The send worker picks it up on the next tick (within ~60s).
Path parameters
iduuidrequiredRecipients#
Per-recipient delivery state
GET
/v1/sms-broadcasts/{id}/recipientsPaginated. Includes message status (queued / sent / delivered / failed / opted_out), reply count, and last-event timestamp.
Path parameters
iduuidrequiredQuery parameters
limitintegerdefault: 50page_tokenstringstatusstringNarrow to one delivery state.
Webhooks for broadcasts#
broadcast.scheduled— created with a future run time.broadcast.send_started— first message left the queue.broadcast.send_completed— final recipient processed.broadcast.opt_out— a recipient replied STOP / unsubscribed.

