# Get a flow

One flow with its steps, the step keys that need a text (`text_steps`) and the steps in words (`in_words`).

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

### Path parameters

- **`key`** `string` · **required** — The key of the flow (`cfo_after_funding`, or a ready-made one).

## Response

- **`object`** `string` · **required** — Always `flow`. One of: `flow`.
- **`key`** `string` · **required** — The key.
- **`name / description`** `string / string | null` · **required** — How the user sees it.
- **`preset`** `boolean` · **required** — A ready-made flow of mySDR: it cannot be changed or deleted; start from it with `based_on`.
- **`based_on`** `string | null` · **required** — The flow it started from.
- **`archived`** `boolean` · **required** — The user archived it in mySDR (under Flows): it no longer shows among their active flows.
- **`reply_handling`** `object` · **required** — What happens after a reply, besides the human tasks in `on_reply`; only the user sets it, under Reply handling on the Flows page: `notify_positive` (a positive reply posts to their Slack or Teams) and `agent_closes_negative` (you close a negative reply yourself: GET /outreach/replies then says `agent_closes`).
- **`approval_required`** `boolean` · **required** — Whether the texts prepared for a lead in this flow must be approved before they start (the default; only the user sets it, under Approval on the Flows page). If so, a start skips anyone whose prepared texts are not approved yet (`texts_not_approved`), unless the call has `texts_approved` after the user said yes; `flow_texts_to_approve` on GET /tables/leads lists them.
- **`steps`** `object[]` · **required** — `key` (the name of its text in `texts`), `type` (`email`, `linkedin_invite`, `linkedin_message`, `inmail`, `withdraw_invite`, `human_task`, `linkedin_like`), `branch` (`start`, `after_accept`, `if_connected`, `not_accepted`, `on_reply`), `note` (on the invite), `wait_days`, `text` (whether you write a text for it), `sent_by` (`agent` for an email you send yourself, `human` for a human task, otherwise `mysdr`), `task` on a human task, and `connections_only: true` on a LinkedIn message in `start` (it only goes to existing connections).
- **`channels`** `string[]` · **required** — The channels of the flow in the order they first come: `email`, `call` (a human task) and `linkedin`.
- **`uses_linkedin`** `boolean` · **required** — The flow does something on LinkedIn (an invite, a message, an InMail or a like). False: it needs no LinkedIn account, no LinkedIn profile of the person (an email address does) and no month of LinkedIn outreach.
- **`has_invite`** `boolean` · **required** — The flow has a LinkedIn invite, and so branches after it. False: everyone gets the steps of `start` in order.
- **`human_task_steps`** `string[]` · **required** — The human tasks of the flow: the sequence waits on their outcome (POST /human-tasks/{id}/complete); those in `on_reply` come after a reply.
- **`text_steps`** `string[]` · **required** — The step keys that need a text when you start.
- **`email_steps`** `string[]` · **required** — The emails you send yourself, in `start` or in a branch after the invite: their text and subject may come at the start or when the step is due.
- **`inmail_steps`** `string[]` · **required** — The InMails mySDR sends, in `start` (to anyone who is not a connection) or to people who did not accept: each needs a text (`texts`) and a subject (`subjects`) at the start.
- **`ready_needs`** `object` · **required** — What Ready for campaign asks you to prepare with POST /outreach/flows/assign: `texts` (a text per step key) and `subjects` (a subject per email and InMail step). An email step in a lead's `sent_steps` needs nothing.
- **`in_words`** `string[]` · **required** — The steps in plain sentences, to show the user.
- **`created_at / updated_at / via`** `string | null` · **required** — When it was saved, and by which key (`Claude`); null for a ready-made one.
- **`is_default`** `boolean` — The default flow of the workspace: every lead without a flow of its own follows it. On GET, and after a save with `make_default`.
- **`dashboard_url`** `string` · **required** — The flow in mySDR.

## Credits

Free. This call never uses credits.

## Errors

- **400** `invalid_request` — A key that is not valid.
- **404** `not_found` — The workspace has no flow with this key.
- **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

```bash
curl "https://mysdr.app/api/v1/outreach/flows/cfo_after_funding" \
  -H "Authorization: Bearer $MYSDR_API_KEY"
```

### JavaScript

```javascript
const response = await fetch('https://mysdr.app/api/v1/outreach/flows/cfo_after_funding', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.MYSDR_API_KEY}`
  }
});
const body = await response.json();
```

### Python

```python
import json
import os
import urllib.request

request = urllib.request.Request(
    "https://mysdr.app/api/v1/outreach/flows/cfo_after_funding",
    headers={
    "Authorization": f"Bearer {os.environ['MYSDR_API_KEY']}"
    },
    method="GET",
)
with urllib.request.urlopen(request) as response:
    body = json.load(response)
```

### Example response

```json
{
  "object": "flow",
  "key": "cfo_after_funding",
  "name": "CFOs after funding",
  "description": "For CFOs at companies that just raised.",
  "preset": false,
  "based_on": "invite_note_two_follow_ups",
  "steps": [
    {
      "key": "invite",
      "type": "linkedin_invite",
      "branch": "start",
      "note": true,
      "wait_days": 0,
      "text": true,
      "subject": false,
      "sent_by": "mysdr"
    },
    {
      "key": "message_1",
      "type": "linkedin_message",
      "branch": "after_accept",
      "wait_days": 0,
      "text": true,
      "subject": false,
      "sent_by": "mysdr"
    },
    {
      "key": "follow_up_1",
      "type": "linkedin_message",
      "branch": "after_accept",
      "wait_days": 3,
      "text": true,
      "subject": false,
      "sent_by": "mysdr"
    },
    {
      "key": "connected_1",
      "type": "linkedin_message",
      "branch": "if_connected",
      "wait_days": 0,
      "text": true,
      "subject": false,
      "sent_by": "mysdr"
    },
    {
      "key": "withdraw",
      "type": "withdraw_invite",
      "branch": "not_accepted",
      "wait_days": 16,
      "text": false,
      "subject": false,
      "sent_by": "mysdr"
    }
  ],
  "channels": [
    "linkedin"
  ],
  "uses_linkedin": true,
  "has_invite": true,
  "text_steps": [
    "invite",
    "message_1",
    "follow_up_1",
    "connected_1"
  ],
  "email_steps": [],
  "inmail_steps": [],
  "human_task_steps": [],
  "ready_needs": {
    "texts": [
      "invite",
      "message_1",
      "follow_up_1",
      "connected_1"
    ],
    "subjects": []
  },
  "in_words": [
    "invite: an invite with a note.",
    "message_1: a message right after the invite is accepted.",
    "follow_up_1: a message 3 days after the previous step.",
    "connected_1: for an existing connection, a message at the start.",
    "withdraw: not accepted after 16 days, the invite is withdrawn and the sequence ends.",
    "An email in a branch follows that branch: it only goes out once it is clear whether the invite was accepted.",
    "A reply stops the sequence for that person."
  ],
  "created_at": "2026-10-28T08:00:00.000Z",
  "updated_at": "2026-10-28T08:00:00.000Z",
  "via": "Claude",
  "archived": false,
  "reply_handling": {
    "notify_positive": false,
    "agent_closes_negative": false
  },
  "approval_required": true,
  "dashboard_url": "https://mysdr.app/en/gtm/flows?flow=cfo_after_funding"
}
```
