Skip to main content

Scheduler API

The Scheduler sends a message or email at a set time, once or on a repeating schedule. It has two parts:

  • Scheduled sends: one message to one contact at send_at, optionally repeating.
  • Rules: a sender that creates scheduled sends for many contacts by itself: on each contact's birthday, on a recurring date for a segment, or once to a segment.

The Scheduler is available on every plan except Basic (including API Only). On a plan without it, every Scheduler call returns 403 with {"detail": {"code": "feature_disabled", "feature": "scheduler"}}.

To run a multi-step automation on a schedule rather than send one message, use a flow with a schedule trigger.

Required Scopes​

ScopePurpose
scheduler:readList and view scheduled sends and rules
scheduler:writeCreate, change, pause and cancel them
scheduler:read + contacts:readGET /contacts/{contact_id}/scheduled-sends

Schedule a Send​

curl -X POST "https://api.sendseven.com/api/v1/scheduler/sends" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json" \
-d '{
"contact_id": "contact_d4e5f6a7",
"channel_type": "telegram",
"channel_id": "ch_telegram_main",
"payload": {"text": "Hi {{contact.first_name}}, your appointment is tomorrow at 10:00."},
"send_at": "2026-11-04T08:00:00Z"
}'

Returns 201 with the scheduled send.

FieldRequiredDescription
contact_idYesThe recipient. 404 if unknown
channel_typeYeswhatsapp, sms, telegram, messenger, instagram, rcs or email
channel_idAll except emailThe channel that sends it (for example the WhatsApp number or Telegram bot)
email_mailbox_idEmailThe mailbox that sends it (its address is the sender). channel_id stays empty for email
payloadYesWhat to send, see Payloads. Up to 64 KB
send_atYesISO 8601 with a time zone (Z or +01:00), at least one minute in the future (400 otherwise)
recurrence_ruleNoiCalendar RRULE, such as FREQ=WEEKLY;BYDAY=MO;BYHOUR=9. The send then stays scheduled after each run and next_run_at moves to the next date. Max 255 characters
timezoneNoStored for display. Recurrence is calculated in UTC

The contact must be reachable on the chosen channel (it needs a matching contact method), otherwise 400.

Payloads​

Channelpayload
WhatsApp{"template_id": "...", "variables": {"1": "Anna"}}: an approved WhatsApp template (its SendSeven ID or its WhatsApp template ID). Free text is not allowed, because nobody can know at scheduling time whether the 24-hour window will be open
SMS, Telegram, Messenger, Instagram, RCS{"text": "...", "attachments": ["<attachment id>"]}. Up to 20 attachments from your workspace, each sent as its own message. No templates
Email, free text{"subject": "...", "html": "..."} or "text" instead of "html"; optional include_signature, cc, bcc, attachments
Email, saved template{"template_id": "...", "variables": {"discount_code": "AUTUMN10"}}: saved email content. Cannot be combined with subject

For WhatsApp, variables fill the template's placeholders; values you leave out come from the template's own variable mapping.

Variables​

Emails (free text and templates; subject and body) resolve:

VariableValue
{{contact.name}}, {{contact.first_name}}, {{contact.last_name}}, {{contact.email}}, {{contact.phone}}, {{contact.birthday}}The recipient
{{contact.custom.<key>}}A custom field of the recipient
{{company.name}}, {{company.legal_name}}, {{company.address}}, {{company.phone}}, {{company.email}}, {{company.website}}, {{company.logo_url}}, {{company.brand_color_*}}Your company profile
{{agent.name}}, {{agent.first_name}}, {{agent.last_name}}, {{agent.email}}, {{agent.phone}}, {{agent.job_title}}, {{agent.role}}The team member who scheduled the send, while they are still an active member
{{system.year}}, {{system.date}}The current year and date when the email goes out
{{your_key}}Any plain key from payload.variables (keys with dots are ignored). For a template, these override the template's saved values

Values are HTML-escaped in HTML bodies. A variable without a value renders empty. The older {{now}} and {{tenant.name}} still work.

Chat messages (text) and WhatsApp template variables resolve {{contact.*}}, {{contact.custom.<key>}}, {{now}} and {{tenant.name}}.

Manage scheduled sends​

MethodPathDescription
GET/scheduler/sendsFilter by status (scheduled, running, completed, failed, canceled), channel_type, contact_id; page, page_size (default 50, max 100)
GET/scheduler/sends/{send_id}One send
PATCH/scheduler/sends/{send_id}Change payload, send_at, recurrence_rule ("" removes the repetition) or email_mailbox_id. Only while status is scheduled, else 409
DELETE/scheduler/sends/{send_id}Cancel (the send stays visible as canceled). Idempotent, returns {"success": true, "id": "..."}
GET/contacts/{contact_id}/scheduled-sendsA contact's upcoming sends (scheduled and running); pass status to see past ones

A send carries id, contact_id, channel_type, channel_id, email_mailbox_id, payload, send_at, next_run_at, recurrence_rule, status, rule_id (when a rule created it), created_by_user_id, created_at and updated_at.

Rules​

A rule creates scheduled sends for every matching contact when they fall due. Rules use the same channel_type, channel_id, email_mailbox_id and payload as a single send.

curl -X POST "https://api.sendseven.com/api/v1/scheduler/rules" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json" \
-d '{
"name": "Birthday email",
"kind": "birthday",
"channel_type": "email",
"email_mailbox_id": "mbx_hello",
"payload": {
"subject": "Happy birthday, {{contact.first_name}}!",
"html": "<p>Enjoy 10% off this week with code <b>{{discount_code}}</b>.</p><p>{{agent.name}}, {{company.name}}</p>",
"variables": {"discount_code": "BDAY10"}
},
"time_of_day_local": "09:00",
"timezone": "Europe/Berlin"
}'
kindSendsRequired fields
birthdayEvery year on each contact's birthday, at time_of_day_local (HH:MM) in timezone (UTC if empty). Contacts without a birthday are skippedtime_of_day_local. No recurrence_rule, no segment_filter
recurring_cronTo the contacts in segment_filter on every date of recurrence_rulerecurrence_rule
segment_blastOnce, to the contacts in segment_filter, at next_evaluation_at. The rule is archived afterwardsnext_evaluation_at. No recurrence_rule

Other fields: name (required, max 200), description (max 500), timezone (IANA name; UTC when empty).

segment_filter chooses the audience:

{
"match_op": "all",
"rules": [
{"kind": "tag", "op": "has_any", "values": ["vip", "newsletter"]},
{"kind": "list", "op": "in_list", "values": ["<list id>"]},
{"kind": "language", "op": "in", "values": ["de", "en"]}
]
}
kindopvalues
taghas_any, has_allTag names (case-insensitive)
listin_list, not_in_listList IDs
languagein, not_inTwo-letter language codes

match_op is all (every rule must match) or any.

Manage rules​

MethodPathDescription
GET/scheduler/rulesFilter by status (active, paused, archived) and kind
GET / PATCH/scheduler/rules/{rule_id}Read or change a rule. status can only switch between active and paused; an archived rule returns 409
POST/scheduler/rules/{rule_id}/pause, /resumePause or resume
DELETE/scheduler/rules/{rule_id}Archive the rule, returns {"success": true, "id": "..."}
GET/scheduler/rules/{rule_id}/sendsThe scheduled sends the rule created

Error Responses​

StatusWhen
400send_at in the past or less than a minute ahead; contact not reachable on the channel; wrong sender field for the channel; payload not allowed for the channel
403Missing scope, or the plan does not include the Scheduler (feature_disabled)
404Unknown contact, send, rule or attachment
409Changing a send that is no longer scheduled, or an archived rule
422Invalid body (for example a malformed segment_filter or a missing field the kind requires)