POST /v1/actions/trigger-sequence
Start a published sequence for a contact. Returns the sequence session id, or `already_running` if the contact is already in it.
Enrolls a contact in a published sequence. Sequences are multi-step time-spaced campaigns — typically a "welcome" or "drip" series with delays between steps.
If the contact already has a running session for this sequence, the endpoint returns 200 with status: "already_running" and does not start a second one. This makes the call safe to retry.
POST /api/v1/actions/trigger-sequence
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
sequence_id |
UUID | yes | Must be a published sequence (published_at not null) |
contact_id |
UUID | one of | Lookup existing contact |
phone |
string | one of | Lookup or create contact (auto-upsert with opted_in_at: now) |
context |
object | no | Free-form key/value bag passed to every node in the sequence |
curl -X POST https://www.qyvo.io/api/v1/actions/trigger-sequence \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{
"sequence_id": "01J3S...",
"phone": "+14155550123",
"context": { "order_id": "ORD-1042", "first_name": "Romain" }
}'
const session = await fetch('https://www.qyvo.io/api/v1/actions/trigger-sequence', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.QYVO_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
sequence_id: '01J3S...',
phone: '+14155550123',
context: { order_id: 'ORD-1042', first_name: 'Romain' },
}),
}).then((r) => r.json());
$session = Http::withToken(env('QYVO_TOKEN'))
->post('https://www.qyvo.io/api/v1/actions/trigger-sequence', [
'sequence_id' => '01J3S...',
'phone' => '+14155550123',
'context' => ['order_id' => 'ORD-1042', 'first_name' => 'Romain'],
])
->json();
import os, httpx
session = httpx.post(
'https://www.qyvo.io/api/v1/actions/trigger-sequence',
headers={'Authorization': f"Bearer {os.environ['QYVO_TOKEN']}"},
json={
'sequence_id': '01J3S...',
'phone': '+14155550123',
'context': {'order_id': 'ORD-1042', 'first_name': 'Romain'},
},
).json()
Response — 201 Created
{
"id": "01J5B...",
"status": "started",
"sequence_id": "01J3S...",
"sequence_name": "Welcome 7-day",
"contact_id": "01J1Y..."
}
If the contact is already in the sequence:
{
"id": "01J5B...",
"status": "already_running",
"message": "Contact is already in this sequence"
}
Errors
| Status | Cause |
|---|---|
404 |
Sequence not found or not published — publish it first in the dashboard |
404 |
Contact not found (only when looking up by contact_id) |
422 |
Sequence has no entry node — the sequence graph is empty; edit it in the dashboard |
422 |
Neither contact_id nor phone provided |
Context usage
Anything you pass in context is available to template-message nodes inside the sequence as {{context.first_name}}, {{context.order_id}}, etc. Useful for personalizing the campaign with order or product data.
