Sends
Schedule a one-off message on an occurrence, edit, cancel or retry a planned send, with the send scope.
Everything on this page needs the send scope. A send goes out on your customer's WhatsApp number, so keep this scope for tools you trust. Reference: Messages.
Read the planned sends
GET /v1/events/{id}/jobs lists every planned send of an event (one per occurrence and sequence message, plus one-off messages), with filters status, occurrence_id, community_id, content_type, from, to, order, and cursor pagination. GET /v1/jobs/{id} reads one. GET /v1/jobs/{id}/deliveries lists the result per community.
A send has a status (scheduled, billing_paused, overdue, sent, partial, failed, canceled), flags editable, cancelable, retryable, retrying, a retry object (count, max, next_at), delivery counts (sent, failed, certain_failed, uncertain, total) and its content (source is template while it still follows the sequence message, snapshot once frozen). error_message, on sends and deliveries, is always a neutral one-line text you can show to a user.
Schedule a one-off message
POST /v1/events/{event_id}/messages
Idempotency-Key: <uuid>
{
"occurrence_id": "…",
"send_at": "2026-11-20T20:25:00+01:00",
"type": "text",
"text": "We start in 5 minutes, here is the link: https://…",
"label": "Late start"
}send_atis at least 60 seconds in the future. The occurrence must be upcoming, not live or finished.type:text,image,video,voiceorpoll. Media types need amedia_url: any URL the WhatsApp provider can fetch is accepted. Uploading first through Media is recommended: format and size are checked there, whereas a bad external file only surfaces at send time. Polls takepoll: { question, options, select_count }.label(60 characters) is shown in the app next to the message.- The content is frozen at creation. Date variables work.
- 30 per day per account. The response is the created
Job(201).
Edit a pending send
PATCH /v1/jobs/{job_id}
{ "text": "Updated text", "media_url": null }Only while editable is true: not attempted yet, subscription active, and not a poll. Only text and media_url can change, not the time. The override wins over the sequence message until it is sent, and a later resync keeps it.
Cancel a pending send
POST /v1/jobs/{job_id}/cancelOnly while cancelable is true (pending, time not reached). The send stays in the list with status: canceled. 409 otherwise.
Retry a failed send
POST /v1/jobs/{job_id}/retry
{ "mode": "failed" }mode | When |
|---|---|
failed | The send failed everywhere |
partial | Some communities got it, others did not |
overdue | Its time passed without an attempt (number disconnected, billing) |
force_now | Groupilot is waiting before an automatic retry and you want it now |
Groupilot only re-queues the communities where the send certainly failed before leaving. A send WhatsApp did not confirm is never repeated: check the group yourself. The response is { "job": { … }, "deliveries_reset": 2 }. 409 when nothing certain is left to retry.
Automatic retries
Groupilot retries on its own up to 5 times, after about 1, 3, 10, 25 and 60 minutes, on temporary errors. retry.next_at tells you when. Permanent errors (refused media, missing community) are final.