Outreach

Follow an outreach stream's progress: how many people it has reached, on which channels, and how many replied, booked or bought.

Follow an outreach stream's progress: how many people it has reached, on which channels, and how many replied, booked or bought.

Read only, and for server-only applications. People reach a stream as leads (see CRM: leads), never through this endpoint. The guide Outreach streams walks through it.

Get an outreach stream

GET https://subcontext.com/api/v1/outreach/streams/{id} Try it

Token scopes: read or write

An outreach stream's settings and progress: how many people are in it, how many have been messaged, and how many replied, booked, applied and bought. Server-only applications.

Outreach streams must be switched on for your organisation. If they aren't, every stream is 404.

Parameters

NameInTypeDescription
id required path string (uuid)

The stream's id (in the dashboard, in the stream's address).

Responses

200 The stream.

FieldTypeDescription
data required OutreachStream

An outreach stream and its progress.

data.id required string (uuid)
data.name required string
data.status required string

active or closed (no new people; those in it carry on). cancelled (stopped for good) is only on streams cancelled before what's in progress could be cancelled on its own.

One of: "active", "cancelled", "closed"
data.archived_at required string or null (date-time)

When the stream was archived off the dashboard's streams list; null while it's on it. Archiving changes nothing else.

data.kind required string

Its shape: mailshot (one message, no link or follow-up), conversation (an opening message the agent follows through, with an optional link and one follow-up), sequence (a message then later steps, each a while after the one before, until the person engages), reminder (messages placed around a date each person has, like a renewal), newsletter (the same message to its subscribers on a schedule, each run an issue) or survey (one question, with at most one reminder, whose answers are recorded).

One of: "conversation", "sequence", "mailshot", "reminder", "newsletter", "survey"
data.purpose required string

What its messages are for, as consent sees it: service, first_party_marketing or third_party_marketing. Each person is checked against it as they join and as each message sends.

One of: "service", "first_party_marketing", "third_party_marketing"
data.goal required string

What the stream is for.

One of: "bookings", "sales", "engagement", "other"
data.channels required array of string

The channels it messages on, in order of preference.

data.all_channels required boolean

Whether each person is messaged on every channel, rather than the first that reaches them.

data.follow_up_after_days required integer

Days before a follow-up to people who haven't replied (0 for none).

data.auto_send required boolean

Whether messages go without a person approving each one.

data.pace_per_hour required integer or null

The most messages sent an hour.

data.message_mode required string

Messages written for each person (drafted) or one fixed message (fixed).

One of: "drafted", "fixed"
data.from_name required string or null

The name its emails come from, when it sets its own (the address doesn't change); null sends them under the name of the agent, or of the team member it's written as.

data.reply_email_template_key required string or null

The built-in email design (e.g. plain, gmail) its emails wear once the person has replied: the agent's answers and the team's. Null with a null reply_email_template_id keeps the outreach emails' own design.

data.reply_email_template_id required string or null (uuid)

One of the organisation's own email templates its emails wear once the person has replied, in place of a built-in one.

data.date_column required string or null

A reminder: the column of an uploaded list that holds each person's date.

data.date_field required string or null

A reminder: the lead field (its key) a workflow or the leads list reads each person's date from.

data.offset_days required integer or null

A reminder: the days from each person's date its first message is sent (negative before it, 0 on the day, positive after).

data.send_at_local_time required string or null

A reminder or newsletter: the time of day (HH:MM, the organisation's time zone) its messages are sent.

data.schedule required object or null

A newsletter: when its issues go. cadence is weekly or fortnightly (with a weekday) or monthly (on a day, 1 to 31 or last, or a week, first to fourth or last, and a weekday); starts_on (YYYY-MM-DD) is the first day one may go.

data.next_issue_at required string or null (date-time)

A newsletter: when its next issue is due.

data.skip_if_unchanged required boolean or null

A newsletter: whether an issue is skipped when the content it's built from hasn't changed since the last.

data.issues_sent_count required integer or null

A newsletter: how many issues have gone.

data.subscribed_count required integer or null

A newsletter: the people subscribed to it now.

data.survey required object or null

A survey: its question, the lead field its answers are kept in (question_key), the answer_type (nps, rating, yes_no or text) and any follow_up_question asked after a low score.

data.survey_answered_count required integer or null

A survey: how many people have answered.

data.awaiting_approval_count required integer

Messages waiting for a person to approve them.

data.rows_count required integer

People in the stream.

data.analysed_count required integer

People whose message has been prepared.

data.skipped_count required integer

People left out (no way to reach them, or no consent).

data.sent_count required integer
data.errored_count required integer
data.outcomes required object

How many people replied, booked, started an application and bought.

data.outcomes.replied required integer
data.outcomes.booked required integer
data.outcomes.applications required integer
data.outcomes.bound required integer
data.total_cost_pence required integer

What the stream's AI work has cost so far, in whole pence. It's metered in US dollars, so this is converted at today's exchange rate and rounded to the nearest penny.

data.cost_ceiling_pence required integer

The most it may cost, in whole pence (converted and rounded the same way). The stream stops when it's reached (budget_exceeded).

data.budget_exceeded required boolean
data.created_at required string (date-time)
Example
{
  "data": {
    "id": "0199a3c2-8900-7ebb-9b3c-b02132435465",
    "name": "Mortgage renewals, October",
    "status": "active",
    "archived_at": null,
    "kind": "conversation",
    "purpose": "first_party_marketing",
    "goal": "bookings",
    "channels": [
      "whatsapp",
      "email"
    ],
    "all_channels": false,
    "follow_up_after_days": 3,
    "auto_send": true,
    "pace_per_hour": 40,
    "message_mode": "drafted",
    "from_name": null,
    "reply_email_template_key": "plain",
    "reply_email_template_id": null,
    "date_column": null,
    "date_field": null,
    "offset_days": null,
    "send_at_local_time": null,
    "schedule": null,
    "next_issue_at": null,
    "skip_if_unchanged": null,
    "issues_sent_count": null,
    "subscribed_count": null,
    "survey": null,
    "survey_answered_count": null,
    "awaiting_approval_count": 0,
    "rows_count": 420,
    "analysed_count": 418,
    "skipped_count": 12,
    "sent_count": 396,
    "errored_count": 2,
    "outcomes": {
      "replied": 88,
      "booked": 31,
      "applications": 9,
      "bound": 4
    },
    "total_cost_pence": 1454,
    "cost_ceiling_pence": 3950,
    "budget_exceeded": false,
    "created_at": "2026-10-01T09:00:00+01:00"
  }
}

401 No token was sent, or it isn't valid because it has expired, was revoked (for example because the application's secret was rotated), or was cut short. Get a new token and try once more.

FieldTypeDescription
error required object
error.code required string

A short code for the kind of error, such as invalid_token, forbidden, not_found or validation_failed. Each code means one thing wherever it appears.

error.message required string

What went wrong and what to do about it, in plain English.

error.fields object

When the error is about particular inputs, which ones and why, by name: a nested one with a dot (customer.email), one in a list with its place (components[0].term_years). Left out when the error isn't about particular inputs.

Example
{
  "error": {
    "code": "invalid_token",
    "message": "The access token has expired. Ask for a new one."
  }
}

403 The token can't be used here. It's missing a scope, it was used from the wrong place (a server-only application's token in a browser, or a browser application's token from a server, another website or a request only server-only applications may make), or it wasn't asked for with `resource=https://subcontext.com/api/v1`.

FieldTypeDescription
error required object
error.code required string

A short code for the kind of error, such as invalid_token, forbidden, not_found or validation_failed. Each code means one thing wherever it appears.

error.message required string

What went wrong and what to do about it, in plain English.

error.fields object

When the error is about particular inputs, which ones and why, by name: a nested one with a dot (customer.email), one in a list with its place (components[0].term_years). Left out when the error isn't about particular inputs.

Example
{
  "error": {
    "code": "forbidden",
    "message": "origin 'https://www.example.com' is not allowlisted for this OAuth application"
  }
}

404 There's no such record in your organisation.

FieldTypeDescription
error required object
error.code required string

A short code for the kind of error, such as invalid_token, forbidden, not_found or validation_failed. Each code means one thing wherever it appears.

error.message required string

What went wrong and what to do about it, in plain English.

error.fields object

When the error is about particular inputs, which ones and why, by name: a nested one with a dot (customer.email), one in a list with its place (components[0].term_years). Left out when the error isn't about particular inputs.

Example
{
  "error": {
    "code": "not_found",
    "message": "Resource not found"
  }
}

Stuck, or something missing?

Get in touch and a person on the team will help.

Contact us