API reference/Outreach/Flows
Assign a flow
Gives up to 50 people a flow, or takes it away with flow: null. They follow it from then on: a start with any other flow skips them (other_flow). One person is one assignment, on their LinkedIn profile whichever key you use for them, or without a profile on their email address (a flow without LinkedIn).
A flow is the skeleton of a sequence without its texts: which steps, on which channel, in which order and branch, after how many days. Any channel in any order: emails you send yourself, a call or another human task, and LinkedIn steps, with or without a LinkedIn invite, for example an email, a call and an email, or a call, a LinkedIn message and an email. A flow with nothing on LinkedIn (only emails and human tasks) needs no LinkedIn account, no LinkedIn profile of the person (an email address does) and no month of LinkedIn outreach (uses_linkedin). You write the texts per person when you start (POST /outreach/linkedin/sequences with flow and texts, or start_flow on the assistant server), and the sequence then has exactly the steps of the flow. There are ready-made flows (invite_note_then_message, invite_then_message, invite_note_two_follow_ups, invites_only, invite_then_inmail, like_then_invite, email_then_invite, email_then_call, emails_only) and the workspace’s own, at most 100. These routes are the tools list_flows, get_flow, save_flow, delete_flow and assign_flow of the assistant server. Free.
Authentication#
Send Authorization: Bearer gtk_…. Create the key under API keys in the menu. Every gtk_ key can call these routes, also while the Signals API is closed. A missing, invalid or revoked key is 401.
Body parameters#
flowstring | null· required — The key of the flow, ornullto take their flow away.leadsobject[]· required — 1 to 50 people, each with exactly one of the keys below (emailmay go with it).leads[].idstring— A row of GET /tables/leads: itsid(a number,per_…orsav_…).leads[].lead_idinteger— A lead from the signals: the number GET /tables/leads gives.leads[].person_idstring— Aper_…from the Signals API, kept 30 days.leads[].linkedin_urlstring— A LinkedIn profile URL (https://www.linkedin.com/in/…).leads[].emailstring— Their email address. For a flow without LinkedIn (uses_linkedinfalse) it is enough on its own: someone without a LinkedIn profile follows the flow on their address.textsobject— Prepared texts for everyone in the call, per step key of the flow (text_stepsandemail_steps), e.g.{"invite": "Hi {{first_name}}, …", "message_1": "…"}. A lead's own text wins. Placeholders are filled at the start.subjectsobject— Prepared subjects of the email steps, per step key.leads[].textsobject— This person's own prepared text per step key;nullremoves one. Sending the same flow again adds or replaces texts and keeps the others; another flow drops them.leads[].subjectsobject— This person's own subject per email step key.sent_stepsobject— For everyone in the call: the emails at the front of the main line (start, before its first step that is not an email) that already went out, outside the flow, with when (ISO 8601; a date is fine), e.g.{"email_1": "2026-10-27T09:15:00+01:00"}. In order from the first (email_2 needs email_1), not in the future, at most 90 days ago. Report those emails first with POST /outreach/activity.leads[].sent_stepsobject— The same for this person (it wins over the shared one);nullremoves a step. The person then continues in the flow: the start skips these steps and the next one waits itswait_daysafter the last of them; they need no prepared text, and someone who only got these emails (no LinkedIn sequence, no reply) can be Ready for campaign. Another flow drops them.
Response#
flowobject | null· required — The flow (key,name), or null.assigned / unassignedinteger· required — How many people got the flow, or lost theirs.leadsobject[]· required — Who it applies to:index,lead, and with a flowtexts_missing(the steps without a prepared text,email_1.subjectfor a subject; empty = Ready for campaign as far as the texts go) andsent_stepswhen some already went out.texts_completeinteger— With a flow: how many of these people have every text of the flow prepared.texts_clearedinteger— With a flow: how many had texts prepared for another flow, which are gone now.skippedobject[]· required — Who it could not apply to, and why:index,lead,code,reason.notestring· required — What it means.dashboard_urlstring· required — The Leads table in mySDR.
Credits#
Free. This call never uses credits.
Errors#
- 400
invalid_request— Noleads, more than the maximum, a person without a valid key, an unknown field, texts without a flow, or a text for a step the flow does not have or longer than that step takes (paramnames it). - 404
not_found— There is no flow with this key. - 503
service_unavailable— Saving flows is not available in this environment yet. - 409
invalid_state— The key has no user behind it, so mySDR cannot record who did it. - 401
authentication_error— The Authorization header is missing, or the key is unknown or revoked. - 403
permission_error— API access is not part of your plan, or your account is suspended. - 429
rate_limit_error— More than 60 requests per minute, or more than 3 at the same time, on one key. Wait for the Retry-After header. - 503
service_unavailable— The API is temporarily unavailable. Retry later. - 500
internal_error— Something went wrong on our side.
Example
curl -X POST "https://mysdr.app/api/v1/outreach/flows/assign" \
-H "Authorization: Bearer $MYSDR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"flow": "cfo_after_funding",
"texts": {
"message_1": "Thanks for connecting, {{first_name}}!"
},
"leads": [
{
"id": "201",
"texts": {
"invite": "Hi {{first_name}}, congrats on the round."
}
},
{
"linkedin_url": "https://www.linkedin.com/in/jane-example"
}
]
}'{
"flow": {
"key": "cfo_after_funding",
"name": "CFOs after funding"
},
"assigned": 2,
"unassigned": 0,
"leads": [
{
"index": 0,
"lead": "201",
"texts_missing": []
},
{
"index": 1,
"lead": "https://www.linkedin.com/in/jane-example",
"texts_missing": [
"invite"
]
}
],
"skipped": [],
"texts_complete": 1,
"texts_cleared": 0,
"note": "These people follow flow cfo_after_funding from now on. A start with another flow skips them (other_flow); sequences that already run keep their steps. 1 of 2 have every text of the flow prepared; texts_missing says what the others still need (assign_flow again with texts adds them). Start them with start_flow (POST /outreach/linkedin/sequences) and flow cfo_after_funding.",
"dashboard_url": "https://mysdr.app/en/gtm/leads?ready=1"
}