Skip one pending step for a contact
curl --request POST \
--url http://localhost:8080/sequences/{sequenceId}/contacts/{contactId}/skip-step \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"step_index": 4503599627370495,
"reason": "<string>",
"idempotency_key": "<string>"
}
'import requests
url = "http://localhost:8080/sequences/{sequenceId}/contacts/{contactId}/skip-step"
payload = {
"step_index": 4503599627370495,
"reason": "<string>",
"idempotency_key": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({step_index: 4503599627370495, reason: '<string>', idempotency_key: '<string>'})
};
fetch('http://localhost:8080/sequences/{sequenceId}/contacts/{contactId}/skip-step', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_PORT => "8080",
CURLOPT_URL => "http://localhost:8080/sequences/{sequenceId}/contacts/{contactId}/skip-step",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'step_index' => 4503599627370495,
'reason' => '<string>',
'idempotency_key' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "http://localhost:8080/sequences/{sequenceId}/contacts/{contactId}/skip-step"
payload := strings.NewReader("{\n \"step_index\": 4503599627370495,\n \"reason\": \"<string>\",\n \"idempotency_key\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("http://localhost:8080/sequences/{sequenceId}/contacts/{contactId}/skip-step")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"step_index\": 4503599627370495,\n \"reason\": \"<string>\",\n \"idempotency_key\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("http://localhost:8080/sequences/{sequenceId}/contacts/{contactId}/skip-step")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"step_index\": 4503599627370495,\n \"reason\": \"<string>\",\n \"idempotency_key\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"outcome": "skipped",
"skipped": true,
"contact_id": "<string>",
"enrollment_id": "<string>",
"step_index": 0,
"channel": "whatsapp"
}{
"statusCode": 123,
"message": "<string>",
"error": "<string>"
}People
Skip one pending step for a contact
Skip one pending step for a contact while preserving their enrollment, remaining outreach, and waits. Use before continuing a sequence after a reply.
POST
/
sequences
/
{sequenceId}
/
contacts
/
{contactId}
/
skip-step
Skip one pending step for a contact
curl --request POST \
--url http://localhost:8080/sequences/{sequenceId}/contacts/{contactId}/skip-step \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"step_index": 4503599627370495,
"reason": "<string>",
"idempotency_key": "<string>"
}
'import requests
url = "http://localhost:8080/sequences/{sequenceId}/contacts/{contactId}/skip-step"
payload = {
"step_index": 4503599627370495,
"reason": "<string>",
"idempotency_key": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({step_index: 4503599627370495, reason: '<string>', idempotency_key: '<string>'})
};
fetch('http://localhost:8080/sequences/{sequenceId}/contacts/{contactId}/skip-step', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_PORT => "8080",
CURLOPT_URL => "http://localhost:8080/sequences/{sequenceId}/contacts/{contactId}/skip-step",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'step_index' => 4503599627370495,
'reason' => '<string>',
'idempotency_key' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "http://localhost:8080/sequences/{sequenceId}/contacts/{contactId}/skip-step"
payload := strings.NewReader("{\n \"step_index\": 4503599627370495,\n \"reason\": \"<string>\",\n \"idempotency_key\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("http://localhost:8080/sequences/{sequenceId}/contacts/{contactId}/skip-step")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"step_index\": 4503599627370495,\n \"reason\": \"<string>\",\n \"idempotency_key\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("http://localhost:8080/sequences/{sequenceId}/contacts/{contactId}/skip-step")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"step_index\": 4503599627370495,\n \"reason\": \"<string>\",\n \"idempotency_key\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"outcome": "skipped",
"skipped": true,
"contact_id": "<string>",
"enrollment_id": "<string>",
"step_index": 0,
"channel": "whatsapp"
}{
"statusCode": 123,
"message": "<string>",
"error": "<string>"
}Requires
A pending step has not been sent, completed, or skipped. A failed attempt that remains retryable is still pending once dispatch has finished. A step that is being sent returns
After
sequences:write. This operation changes one contact’s enrollment. It keeps the enrollment ID, previous sends, personalization, and history, and leaves the shared sequence unchanged.
Choose the pending step
mode | Additional input | Selection |
|---|---|---|
next_pending | None | First pending step at or after the contact’s current position, on any channel. |
next_channel | channel: voice, whatsapp, or email | First pending step on that channel. Phone is voice. Intervening steps stay in place. |
specific_step | step_index: nonnegative integer | That sequence position, starting at zero. |
dispatch_in_progress; the request does not cancel it. Missing mode-dependent inputs, invalid channels, and negative or fractional indexes return HTTP 400. Inputs for another mode are ignored.
A phone call that connected is already sent even if its sequence send record is still being reconciled. An unresolved dial cannot be skipped or continued past until its outcome is known.
The optional reason is a nonempty string up to 2,000 characters. The contact’s journey history records the step, channel, reason, timestamp, and workflow, operator, or API-key attribution. Without a reason, history shows “Requested skip.” The journey shows Skipped, including future steps.
Status and waiting time
- Active: the current due time stays in place. At that time the skipped slot is consumed and the next step’s wait begins. Future skips take effect when reached.
- Parked: status and park reason stay unchanged. Resolve the existing park through its normal controls before the sender progresses.
- Exited after a reply: the skip is saved, but the enrollment stays exited. Call Continue Sequence for Contact separately.
- Completed, suppressed, removed, or candidate: no step is newly skipped and no enrollment is revived.
nothing_to_continue and the enrollment stays exited.
If you later edit the pending step’s wait, it is recalculated from the latest continuation or the previous step’s effective completion time. Other history events do not restart that wait.
Results and retries
The response uses HTTP 201 for both a new skip and an expected no-op:{
"outcome": "skipped",
"skipped": true,
"contact_id": "01960000-0000-7000-8000-000000000002",
"enrollment_id": "01960000-0000-7000-8000-000000000003",
"step_index": 2,
"channel": "voice"
}
| Outcome | Meaning |
|---|---|
skipped | This request newly skipped the identified step. |
already_skipped | The step or idempotent request was already applied. Original history is retained. |
contact_not_found | No live enrollment, including a removed enrollment. |
not_skippable | The enrollment is completed, suppressed, a candidate, or otherwise ineligible. |
no_pending_step | No pending step matches the next-step selection. |
step_not_found | The specific index is outside this sequence. |
step_not_pending | The specific step was already sent, completed, or passed. |
dispatch_in_progress | Sending has started and cannot safely be skipped. Wait for its outcome before retrying. |
skipped is true only for a new skip. Index/channel fields identify the selected step where available; otherwise they are null. A missing or inaccessible sequence returns HTTP 404; insufficient scope returns HTTP 403.
Specific-step requests are always idempotent. For either next-step mode, supply an idempotency_key of up to 200 characters and reuse it on retries. The key is scoped to this enrollment and identifies the original selection, even if the cursor later moves. Use a new key for a new skip intent. Workflow executions supply a key automatically for each action in a run.
Recorded skips pin their step positions: removing that shared step or an earlier step is refused. Full replacement of a draft containing recorded skips is also refused. Use content/delay edits or append steps instead.
The MCP equivalent is skip_sequence_step, with sequence_id, contact_id, and the same body fields.
Skip the next phone step
{
"mode": "next_channel",
"channel": "voice",
"reason": "Customer cannot talk now",
"idempotency_key": "reply-123-skip-phone"
}
skipped or already_skipped, continue the same contact using the separate continuation operation. See the workflow example.Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Path Parameters
The unique identifier of the sequence
Pattern:
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$The person's contact id (from enroll results or the people list)
Pattern:
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$Body
application/json
Available options:
next_pending, next_channel, specific_step Required for next_channel. Phone uses voice.
Available options:
whatsapp, voice, email Required for specific_step; zero-based.
Required range:
0 <= x <= 9007199254740991Required string length:
1 - 2000Reuse for retries of a next-step request in this enrollment. Specific-step skips are always idempotent.
Required string length:
1 - 200Response
Default Response
Available options:
skipped, already_skipped, contact_not_found, not_skippable, no_pending_step, step_not_found, step_not_pending, dispatch_in_progress True only when this request newly skipped a step.
Required range:
-9007199254740991 <= x <= 9007199254740991Available options:
whatsapp, voice, email Was this page helpful?