API reference/Outreach/Flows

.md

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).

POSThttps://mysdr.app/api/v1/outreach/flows/assign

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#

  • flow string | null · required — The key of the flow, or null to take their flow away.
  • leads object[] · required — 1 to 50 people, each with exactly one of the keys below (email may go with it).
  • leads[].id string — A row of GET /tables/leads: its id (a number, per_… or sav_…).
  • leads[].lead_id integer — A lead from the signals: the number GET /tables/leads gives.
  • leads[].person_id string — A per_… from the Signals API, kept 30 days.
  • leads[].linkedin_url string — A LinkedIn profile URL (https://www.linkedin.com/in/…).
  • leads[].email string — Their email address. For a flow without LinkedIn (uses_linkedin false) it is enough on its own: someone without a LinkedIn profile follows the flow on their address.
  • texts object — Prepared texts for everyone in the call, per step key of the flow (text_steps and email_steps), e.g. {"invite": "Hi {{first_name}}, …", "message_1": "…"}. A lead's own text wins. Placeholders are filled at the start.
  • subjects object — Prepared subjects of the email steps, per step key.
  • leads[].texts object — This person's own prepared text per step key; null removes one. Sending the same flow again adds or replaces texts and keeps the others; another flow drops them.
  • leads[].subjects object — This person's own subject per email step key.
  • sent_steps object — 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_steps object — The same for this person (it wins over the shared one); null removes a step. The person then continues in the flow: the start skips these steps and the next one waits its wait_days after 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#

  • flow object | null · required — The flow (key, name), or null.
  • assigned / unassigned integer · required — How many people got the flow, or lost theirs.
  • leads object[] · required — Who it applies to: index, lead, and with a flow texts_missing (the steps without a prepared text, email_1.subject for a subject; empty = Ready for campaign as far as the texts go) and sent_steps when some already went out.
  • texts_complete integer — With a flow: how many of these people have every text of the flow prepared.
  • texts_cleared integer — With a flow: how many had texts prepared for another flow, which are gone now.
  • skipped object[] · required — Who it could not apply to, and why: index, lead, code, reason.
  • note string · required — What it means.
  • dashboard_url string · required — The Leads table in mySDR.

Credits#

Free. This call never uses credits.

Errors#

  • 400 invalid_request — No leads, 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 (param names 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

POST/outreach/flows/assign
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"
      }
    ]
  }'
Response
{
  "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"
}