UpdateSequenceV2
Creates or fully replaces the sequence (workflow) of a campaign, voice steps included.
The v2 version of UpdateSequence, and the write to use for any campaign whose sequence has voice notes. Two things differ from v1:
-
A
MESSAGEnode’s payload carriesmessageVersionsinstead ofmessages, so you can read, write and delete voice versions, not only text. -
The
messageVersionslist you send replaces what is stored: any version you leave out is deleted, voice versions included. Read the sequence with GetCampaignSequenceV2 first and send back what you want to keep. Deleting a version never deletes the recording behind it.
The START node is implicit; the root of the request must be your first action node. Every path through the tree must end with an END node.
Allowed statuses: DRAFT, SCHEDULED, PAUSED. Any other status returns 400 CAMPAIGN_STATUS_NOT_EDITABLE. Once leads have entered the campaign, the shape of the sequence must stay the same - only payloads and delays can change - and a request that changes it returns 400 SEQUENCE_UPDATE_INCONSISTENT.
Body Parameters
-
campaignId (long, required): The campaign to update.
-
sequence (PublicSequenceNodeDtoV2, required): Root node of the workflow tree.
PublicSequenceNodeDtoV2 fields
The same as the v1 node (see UpdateSequence), except for the MESSAGE payload.
-
nodeType (string, required): One of
CONNECTION_REQUEST,MESSAGE,INMAIL,VIEW_PROFILE,FOLLOW,LIKE_POST,FIND_EMAIL,CHECK_IS_CONNECTION,CHECK_IS_OPEN_PROFILE,SEND_LEAD_TO_INSTANTLY,SEND_LEAD_TO_SMARTLEAD,SEND_LEAD_TO_BISON,END. A node without anodeTypeis rejected with 400FIELD_VALUE_INVALID. -
unconditionalNode (PublicSequenceNodeDtoV2, required for non-END nodes): The next node to follow unconditionally, or when a branching condition is
false. -
conditionalNode (PublicSequenceNodeDtoV2): The next node when the branching condition is
true. Required forCONNECTION_REQUEST,CHECK_IS_CONNECTION,CHECK_IS_OPEN_PROFILEandFIND_EMAIL. OnMESSAGEandINMAILit is the exit taken when the lead replies and must be anENDnode; if you leave it out, anENDnode is added for you. Other nodes must not set it. -
actionDelay (int, optional) / actionDelayUnit (string, optional): The wait before this node runs. Range 0-100; unit
HOUR(the default) orDAY. An omittedactionDelayis0. The unconditional child ofCONNECTION_REQUEST,MESSAGE,INMAIL,VIEW_PROFILE,FOLLOWandLIKE_POST, and the conditional child ofCONNECTION_REQUEST, need a delay of at least 3 hours and at most 500 days -ENDnodes included - or the request is rejected with 400SEQUENCE_NODE_DELAY_INVALID.actionDelay: 3withactionDelayUnit: "HOUR"is always valid. -
payload (object, conditional): Node-specific. Required for
CONNECTION_REQUEST,MESSAGE,INMAIL,LIKE_POST,SEND_LEAD_TO_INSTANTLY,SEND_LEAD_TO_SMARTLEADandSEND_LEAD_TO_BISON; omitting it is rejected with 400SEQUENCE_NODE_PAYLOAD_MISSING. Every payload exceptMESSAGEis the same as in v1 - see UpdateSequence. -
externalReference (string, optional): Your own tracking ID for this step. Max 100 characters.
MESSAGE payload
-
messageVersions (PublicMessageVersion[], required): One entry per version of the step; one version is picked at random for each lead. At least one is required. The list replaces what is stored.
-
fallbackMessage (string): Plain text sent instead of a version whose text uses a variable the lead has no value for, and instead of a voice version whose voice note cannot be produced. Required when any version is VOICE, and when a TEXT or DYNAMIC version uses a variable other than
{FIRST_NAME},{LAST_NAME},{MY_FIRST_NAME}and{MY_LAST_NAME}. It may itself use only those four variables. Max 8000 characters.
PublicMessageVersion fields
-
type (string):
TEXT(the default) orVOICE. -
voiceMode (string): Used only when
typeisVOICE.DYNAMIC(the default) speaksmessageas an AI voice note in each sender’s assigned voice;STATICsends one uploaded recording (staticClipId) as it is. -
message (string): For
TEXT, the message text, max 8000 characters. For a DYNAMIC voice version, the script that is spoken: max 800 characters and at least 3 spoken words (a{VARIABLE}counts as one word). Must be empty on a STATIC version. -
staticClipId (long): STATIC versions only, and required there: the
clipIdreturned by UploadStaticClip. It must be a recording in your workspace. -
messageId (string, optional): The version’s id. When you edit a sequence, send back the id GetCampaignSequenceV2 returned: a voice note being generated for a lead is tied to its version’s id, and a version sent without an id gets a new one. Leave it out only for a new version. Ids must be unique within a step, and
FALLBACK,MANUALandunknown(in any letter case) are reserved. -
durationMs (int, read-only): Length of the version’s recording in milliseconds. Ignored on write.
-
transcript (string, read-only): Transcript of the version’s recording.
nullis normal and never blocks sending. Ignored on write. -
staticClipTranscript (string): Read-only on a STATIC version: the server always reports the recording’s own transcript and ignores any value you send. Must be empty on a TEXT or DYNAMIC version.
-
importedTranscript (string): Read-only on a STATIC version: the script a shared step arrived with, shown only while the step has no recording, and ignored on write. Must be empty on a TEXT or DYNAMIC version.
-
needsRecording (bool, read-only):
trueon a STATIC version that has no recording. Ignored on write.
Sending back what GetCampaignSequenceV2 returned
A body read from GetCampaignSequenceV2 can be sent back unchanged: durationMs, transcript and needsRecording are ignored, and on a STATIC version so are staticClipTranscript and importedTranscript, which the server sets from the version’s recording. Sending them back never causes a 400. Two cases still need a change first:
- A STATIC version that needs a recording (
needsRecording: true) is rejected with 400SEQUENCE_NODE_PAYLOAD_INVALID:
Give it a staticClipId, or replace it with a DYNAMIC version whose message is the script, or remove it (the step must keep at least one version).
- A version whose
staticClipIdis not a recording in your workspace is rejected with 400STATIC_CLIP_NOT_FOUND:Error in one of the nodes in the campaign sequence. A pre-recorded voice clip in a "Send Message" action refers to a recording that does not exist in this workspace. Upload the clip again in this workspace.
Voice rules that return 400
Nothing is saved when any of these is broken:
-
messageson aMESSAGEpayload (FIELD_NOT_SUPPORTED). It is the v1 field, and even"messages": []is refused:'messages' is not supported on the v2 endpoints. Use 'messageVersions', or call GetCampaignSequence, UpdateSequence or Create for the text-only v1 contract.messagesstays valid onCONNECTION_REQUESTandINMAILpayloads. -
staticClipId, or a non-emptystaticClipTranscriptorimportedTranscript, on a TEXT or DYNAMIC version (FIELD_VALUE_INVALID). The message names the field, for example:'staticClipTranscript' only applies to a STATIC voice version (type VOICE, voiceMode STATIC); remove it from this version. -
A non-empty
messageon a STATIC version (FIELD_VALUE_INVALID):'message' must be empty on a STATIC voice version: what the lead hears, and its transcript, come from the recording (staticClipId). Use a DYNAMIC voice version to have a script spoken, or a TEXT version to send text. -
A reserved
messageId, or the samemessageIdtwice in one step (FIELD_VALUE_INVALID). -
A DYNAMIC script with fewer than 3 spoken words (
VOICE_SCRIPT_TOO_SHORT), for example:The AI voice script at sequence.conditionalNode.payload.messageVersions[1] has 2 spoken word(s). AI voice scripts need at least 3 words — very short scripts come out garbled.A short script already stored on the campaign and sent back unchanged with itsmessageIdis accepted. -
A DYNAMIC script over 800 characters, an empty TEXT or DYNAMIC
message, a voice step without a validfallbackMessage, or a step without versions (SEQUENCE_NODE_PAYLOAD_INVALID).
Errors
Every { "errorMessage": "..." } error body carries an errorCode; branch on the code, not on the message. Request-validation 400s (for example actionDelay outside 0-100, or a nodeType name that does not exist) use the standard problem-details shape instead.
- 400
CAMPAIGN_STATUS_NOT_EDITABLE,SEQUENCE_UPDATE_INCONSISTENT,SEQUENCE_INVALID(the tree’s structure is not valid),SEQUENCE_NODE_PAYLOAD_MISSING,SEQUENCE_NODE_PAYLOAD_INVALID,SEQUENCE_NODE_DELAY_INVALID,FIELD_NOT_SUPPORTED,FIELD_VALUE_INVALID,REQUIRED_FIELD_MISSING(aSEND_LEAD_TO_*payload is missing a required field),VOICE_SCRIPT_TOO_SHORT,STATIC_CLIP_NOT_FOUND, and forSEND_LEAD_TO_*nodesINTEGRATION_NOT_CONFIGURED,INTEGRATION_CREDENTIALS_INVALIDandINTEGRATION_REQUEST_FAILED. - 403
NO_ACTIVE_SUBSCRIPTION: the workspace has no active subscription. - 404
CAMPAIGN_NOT_FOUND,CAMPAIGN_API_NOT_ENABLED(the campaign API is not enabled for your account), andINTEGRATION_RESOURCE_NOT_FOUND(the Instantly, Smartlead or EmailBison campaign or list of aSEND_LEAD_TO_*node was not found).
Headers
API key header using this scheme. Example: “X-API-KEY: {API_KEY}”
Request
One node of a campaign sequence on the v2 endpoints (GetCampaignSequenceV2, UpdateSequenceV2, CreateV2). Nodes form a tree through conditionalNode and unconditionalNode. The START node is implicit - the root is your first action node - and every path ends with an END node.
