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 (a handle or a profile URL); an email or LinkedIn username that matches no contact on the team creates one. A prospect can also carry phone_numbers (up to 10, primary first) and website. A phone number is never used to match a contact. 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, skipped lists everyone refused, and routed lists anyone a route_to_sequence rule started in another sequence instead. Routed people are counted apart from enrolled and skipped: they are not in this sequence, and nothing went wrong. A 200 does not mean everyone went in: read skipped and routed. 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, or a profile URL. Matched and created the same way.
https://www.linkedin.com/in/ada-lovelace/,
linkedin.com/in/ada-lovelace and https://uk.linkedin.com/in/ada-lovelace?trk=... all become ada-lovelace.
Anything else, such as a company page or a URL on another site, is sent on as it is.
When the person already exists, the other fields you send (first_name, title, website, 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>}}
variables render what you sent.
Phone numbers
Sendphone_numbers with every number you have for the person, primary first, up to 10:
- The numbers are added to the contact’s numbers. None are taken away, and a number the contact already has, compared on its last 10 digits, is not added twice.
- Write
numberin E.164, such as+14155552671. - Send
type(mobile,directoroffice) to keep the entry as you wrote it,country_codeandextensionincluded. Without atype, the number is read again fromnumberalone: a number starting with+keeps its country code, a leading0is read as a UK number, and a bare 10-digit number as US. It is filed asmobile, orofficewhen it has an extension, anycountry_codeorextensionyou sent is ignored, and a number that cannot be read is dropped. phone_number(withphone_type) still works. Withphone_numbers, it is added after them unless it is already listed.- A phone number is never used to match a person to an existing contact: colleagues who share a company line are not one person.
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.People started in another sequence
A rule of engagement with theroute_to_sequence action starts some people in another sequence instead of
this one. They are listed in routed, and counted apart from enrolled and skipped: they are not in this
sequence, and nothing went wrong.
sequence_stateis their enrollment in the other sequence.routed_to.existing: truemeans they were already live there, andsequence_stateis that enrollment.- Someone routed into a sequence is not routed again from there.
- When the other sequence can’t take them (adding to it is paused, it is full or archived, or they are
suppressed), they land in
skipped, with a reason such asCouldn't start them in "Email follow-up": it is at capacityand the rule. A sequence that is turned off still takes them; they wait there until it is turned on. - The refusals list records them with the reason
routed. See Start them in another sequence instead.
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 and routed.
How many people went in, including anyone listed in held. People in routed are not counted.
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.
People a route_to_sequence rule started in another sequence instead of this one. They are not counted in enrolled, and are not in skipped or sequence_states. Someone routed into a sequence is not routed again from there. When the other sequence cannot take them (adding to it is paused, it is full or archived, or they are suppressed), they land in skipped instead, with the reason and the rule. A sequence that is turned off still takes them; they wait there until it is turned on.
The enrollments created in this sequence, 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.