Add contacts to a sequence
Enrolls up to 500 people in one synchronous call. Identify each by an existing contact id, or by email or linkedin_username; an email or LinkedIn username that matches no contact on the team creates one. For an existing contact, the other fields you send only fill gaps and never overwrite, except custom_fields, which replace values that have the same label.
The call is partial-tolerant and reports every outcome: enrolled counts who went in (including anyone held), held lists people a rule holds for a manager’s approval, warnings lists rules that matched without blocking, and skipped lists everyone refused. A 200 does not mean everyone went in: read skipped. Each refusal is also recorded, with a reason code, on GET /v2/sequencer/sequences/{id}/enrollment-attempts.
A person is skipped when they already have a live enrollment in this sequence, are on the suppression list (unless the sequence is transactional), are blocked by a rules-of-engagement rule, would exceed the sequence’s throttle_capacity or throttle_max_adds_per_day for the owner, or are named by a contact id that is not on the team. The whole request is refused with 422 when the sequence is archived, has no steps, or has throttle_paused set, or when owner_id is not on the team.
On an enabled sequence each person’s first step is scheduled at once; on a disabled one they wait as pending and start when it is enabled. Because a contact can hold only one live enrollment per sequence, re-sending someone already in it skips them rather than adding a duplicate. Send an Idempotency-Key so a retry returns the original response. For more than 500 people, start an enrollment run (POST /v2/sequencer/enrollment-runs). Counts toward the Sequencer writes rate limit.
Identifying people
Give each prospect one of:contact: the id of a contact already on your team.email: matched against your team’s contacts; a new contact is created when there is no match.linkedin_username: the handle, not a full URL. Matched and created the same way.
first_name, title, timezone and so on)
only fill fields that are empty on the contact; they never overwrite. custom_fields are the exception:
a value you send replaces the contact’s value for the same label, so {{custom.<label>}} merge fields
render what you sent. phone_number is added only when the contact has no phone number at all.
Example
owner_id is who ends up holding the enrollments, so whose queue their tasks land in. It defaults to
user_id.
Reading the response
A 200 does not mean everyone went in. Every response reports the whole outcome:skipped[].reason currently carries the refusal message, as above, not a reason code, and rule on a
skip is an object with id, name, action and reason. The schema below still shows a code and a
string. For the code, read List enrollment refusals,
where every skip is recorded.Why someone is skipped
throttle_paused set, or when owner_id is not on the team.
Timing
On an enabled sequence, each person’s first step is scheduled straight away: it comes due after the first step’sinterval_seconds, inside the sending window. On a disabled sequence people wait as
pending and start when it is enabled.
Retrying
Re-sending someone who is already in the sequence skips them as already enrolled rather than adding a duplicate, so a retry never enrolls anyone twice. Send anIdempotency-Key anyway: a retry with the
same key returns the original response, including the original skipped list.Authorizations
Team-scoped API key generated in the Salesfinity dashboard under Settings → Connections → API & Webhooks. A missing or invalid key returns HTTP 403.
Headers
Makes this write safe to retry. Send a unique value, such as a UUID, and send the same value again when you retry the same request. A retry with the same key and the same request (method, path including the query string, and JSON body) returns the original successful response without acting twice. The same key with a different body or path returns 409, and so does a retry while the first request is still running; that one is safe to repeat after a moment. A request that fails frees its key, so a retry runs the write again: after a 5xx on a create, confirm with a GET before retrying. Keys are kept for 24 hours and are scoped to your team.
Path Parameters
24-character sequence id.
Body
The team member this call acts as. Must be an active member of the key's team with an active plan or seat. A 24-character hexadecimal ID.
"507f1f77bcf86cd799439011"
1 to 500 people. For more, start an enrollment run (POST /v2/sequencer/enrollment-runs).
500Who owns the resulting enrollments, and so whose queue their tasks land in. Defaults to user_id. Must be a member of the team; otherwise the whole request is refused with 422. A 24-character hexadecimal ID.
Response
The outcome for every person sent.
The outcome of adding people. A 200 does not mean everyone went in: read skipped.
How many people went in, including anyone listed in held.
Everyone refused, in the order sent. Each refusal is also recorded, with a reason code, on GET /v2/sequencer/sequences/{id}/enrollment-attempts.
People enrolled but held in pending until a manager approves them, because a rule requires approval. They are counted in enrolled.
People who went in although a rule matched them with a warning.
The enrollments created, in the same shape as GET /v2/sequencer/enrollments/{id}, except that contact is expanded to _id, first_name, last_name, email, linkedin_username, account, title and channel_stats. On an enabled sequence their state is active; on a disabled one, or when held, it is pending.