Member Tools

Members are a project's subscribers, the people every payment is made for and every access grant resolves to.

Members are a project's subscribers, the people every payment is made for and every access grant resolves to. These tools list and read them, ban, unban and kick, read the accounts they linked, and send a broadcast to a segment of them through the project's connector.

Tools

ban_member

DESTRUCTIVE

Ban a project member. Flips status to banned and emits member.banned. Noop when the member is already banned.

Ban a project member. Delegates to an Action so cache invalidation runs and a member.banned event emits with the optional reason. Removal from the gated places runs on the connector's pipeline. Noop when the member is already banned.

Requires ability

The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.

The REST endpoint and this tool share one action, so validation, permissions and events are identical.

Fires one event

Delivered to every endpoint subscribed to it once the change is made.

Annotations

DestructiveIdempotentOpen world

A client that honours annotations asks a person before running it. Sending the same arguments twice changes nothing the second time. It reaches beyond Subscriby: a connector, a provider or a member.

Arguments

member_id*string

UUID of the project member to ban.

reasonstringoptional

Optional human-readable reason that lands in the member.banned event payload.

What it returns

{  "data": {    "id": "2a91c4e7-6f38-4b52-8e0d-9c1a7b3f5d80",    "status": "banned"  }}

How it fails

RESOURCE_NOT_FOUND

unknown member_id, or the member belongs to a team outside the token's scope.

TOKEN_MISSING_ABILITY

token lacks project-user:update.

Send a message through the project's connector to a segment of its members. Destructive and irreversible — preview the audience and get human approval first.

Queue a message through the project's connector to a segment of its members. The send runs in the background at the pace the connector declares (28 messages a second on Telegram); the tool returns the audience it resolved and how many members it will reach.

Destructive and irreversible. Every recipient is a real person and the message lands in their private chat. Call preview_broadcast_audience first, show the human the exact message text, the segment and the recipient count, and get explicit approval before calling this. A broadcast cannot be recalled.

Not idempotent — calling twice sends twice. There is no de-duplication, because two identical broadcasts minutes apart is a legitimate thing a creator may want.

Requires ability

The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.

The REST endpoint and this tool share one action, so validation, permissions and events are identical.

Delivered to every endpoint subscribed to it once the change is made.

Annotations

DestructiveOpen world

A client that honours annotations asks a person before running it. It reaches beyond Subscriby: a connector, a provider or a member.

Arguments

project_id*string

UUID of the project whose members will receive the message.

message*string

The message body, 1-4096 characters. Canonical HTML subset only (<b>, <i>, <u>, <s>, <a>, <code>, <pre>, <blockquote>, <tg-spoiler>); anything else is stripped before sending.

audiencestringoptional

Segment to address: all, customer, trialing, lead, churned, expiring_soon, cancelled_still_active, paused, trialing_cardless, all_pass_holders, all_pass_holders_not_in_queue, pass_holders, pass_holders_not_in_queue. Defaults to `all`, which reaches every member with a linked chat.

pass_window_idstringoptional

Required for the single-window pass segments (`pass_holders`, `pass_holders_not_in_queue`); ignored by the others.

plan_idstringoptional

Optional. Narrows the segment to members on one subscription plan, by plan UUID. Composes with the segment rather than replacing it: `customer` plus a plan reaches people paying for that plan right now, `churned` plus a plan reaches people who held it and left. Rejected for `lead` (never subscribed) and for the pass segments (their plan is implied by the window).

expiring_within_daysintegeroptional

Only meaningful for `expiring_soon`. How many days ahead to look, 1-90, default 7. A member is counted only if their access genuinely lapses: an auto-renewing subscription is not expiring.

What it returns

{  "data": {    "project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13",    "audience": "customer",    "pass_window_id": null,    "plan_id": null,    "expiring_within_days": null,    "recipient_estimate": 128,    "estimated_seconds": 5,    "status": "queued"  }}

status is always queued — this reports what was addressed, not what was delivered. Subscribe to broadcast.completed for the sent and failed tallies.

Narrowing the audience

plan_id composes with audience rather than replacing it: customer plus a plan addresses people paying for that plan right now, churned plus a plan addresses people who held it and left. The plan and the state describe the same subscription, so a member paying for one plan who once trialled another is not matched by the first form.

Four of the segments describe a subscription rather than a member status, which is what a status cannot express — somebody who cancelled but has three weeks left carries the same status as somebody renewing happily:

SegmentAddresses
expiring_soonAccess lapses inside expiring_within_days.
cancelled_still_activeRenewal is off, but time remains.
pausedPaused rather than ended.
trialing_cardlessOn trial with no card on file.

An auto-renewing subscription is never `expiring_soon`

A subscription's end date is rewritten to the new period end on every renewal, so a date inside the horizon describes the next invoice, not an expiry — counting it would place every monthly subscriber in this segment once a month. A member appears only once their access genuinely lapses: renewal is off, or the plan does not renew at all.

Refusals

The tool returns a validation error, and sends nothing, when:

  • the project has no connected bot
  • the body is empty or longer than 4096 characters
  • the audience is unrecognised
  • a pass segment is requested by a project whose plan no longer includes passes
  • a single-window segment is requested with no pass_window_id
  • a plan_id is sent with lead or a pass segment, which cannot be narrowed by plan
  • a plan_id does not belong to the project

A plan filter the segment cannot use is refused rather than ignored: silently dropping it would return a recipient count for a different audience than the one described, and the caller has no way to notice.

Find the project member who connected a given account on a connector, from the connector key and the platform's own id.

Turns the id a bot or a server hands over into a Subscriby member: give it the project, the connector the account lives on and the platform's own id for the account, and it answers the same row get_subscriber does, with the member's connected accounts embedded as identities[]. This is the lookup for a workflow that starts from a platform event (a message, a join, a role change) and needs to know which member, if any, that account belongs to. An account nobody in the project has connected is RESOURCE_NOT_FOUND, indistinguishable from an unknown project, so a caller never learns whether an id exists elsewhere. The REST twin is the identity filter on GET /v1/projects/{project}/members, which returns a one-row page instead.

Requires ability

The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.

Runs the same action as

The REST endpoint and this tool share one action, so validation, permissions and events are identical.

Annotations

Read-only

It reads and never changes anything.

Arguments

project_id*string

UUID of the project the member belongs to.

connector*string

Connector key the account lives on, as `list_connectors` lists them.

external_id*string

The platform's own id for the account, as `list_member_identities` shows it.

What it returns

{  "data": {    "id": "2a91c4e7-6f38-4b52-8e0d-9c1a7b3f5d80",    "project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13",    "status": "customer",    "name": "Ada Lovelace",    "identities": [      {        "id": "6a1f0c3e-2d4b-4e8a-9c7d-1b5e3f9a2c4d",        "connector": "telegram",        "source": "handshake",        "preferred": true,        "external_id": "123456789",        "display_name": "Ada Lovelace",        "username": "ada",        "linked_at": "2026-09-12T10:05:00Z"      }    ],    "created_at": "2026-05-18T10:40:00Z"  }}

The row is the one get_subscriber and list_subscribers render; identities[] lists every account the member connected, not only the one asked about.

How it fails

RESOURCE_NOT_FOUND

unknown project_id, a project outside the token's scope, or an account nobody in the project has connected.

TOKEN_MISSING_ABILITY

token lacks project-user:view-any.

One project member by UUID, in the list_subscribers row shape. Returns two email addresses verbatim — scrub before forwarding.

Fetch one member (subscriber) of a project by id when you already know it — from a webhook payload's subscriber_id, a support conversation, or an earlier list. The row is the one list_subscribers returns, so a member read here is identical to the same member read from the list.

PII

Both email (member-chosen and verified) and billing_email (whatever they gave a payment provider) come back verbatim, as do the platform ids of the member's connected accounts under identities. Scrub them before forwarding to any third-party LLM, log sink or analytics surface.

Requires ability

The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.

The REST endpoint and this tool share one action, so validation, permissions and events are identical.

Annotations

Read-only

It reads and never changes anything.

Arguments

member_id*string

UUID of the project member to fetch.

What it returns

{  "data": {    "id": "2a91c4e7-6f38-4b52-8e0d-9c1a7b3f5d80",    "project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13",    "name": "Ada Lovelace",    "email": "[email protected]",    "email_verified": true,    "billing_email": "[email protected]",    "identities": [      {        "connector": "telegram",        "external_id": "123456789",        "display_name": "Ada Lovelace",        "username": "ada",        "preferred": true      }    ],    "status": "customer",    "joined_at": "2026-05-18T10:05:00+00:00"  }}

name is the display name Subscriby derived for the member; status is their standing in the project (lead, customer, and the churned and moderation states), not a subscription status.

identities lists the member's connected accounts, the one they prefer to be reached on first: the connector key, the platform's own id for the account, and the display name and username the platform reported. A member who only ever used the portal and connected nothing has an empty list.

How it fails

RESOURCE_NOT_FOUND

unknown member_id, or a member of a project outside the token's scope.

AUTHENTICATION_REQUIRED

no authenticated user on the request.

TOKEN_MISSING_ABILITY

token lacks project-user:view.

kick_member

DESTRUCTIVE

Kick a project member without banning them. Status rolls to churned; the subscriber can re-join later.

Kick a project member without a permanent ban. Status rolls to churned; removal from the gated places happens on the connector's pipeline. The subscriber can re-join via a fresh purchase or access code later. Delegates to an Action so cache invalidation runs and member.kicked emits with the optional reason.

Requires ability

The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.

The REST endpoint and this tool share one action, so validation, permissions and events are identical.

Fires one event

Delivered to every endpoint subscribed to it once the change is made.

Annotations

DestructiveIdempotentOpen world

A client that honours annotations asks a person before running it. Sending the same arguments twice changes nothing the second time. It reaches beyond Subscriby: a connector, a provider or a member.

Arguments

member_id*string

UUID of the project member to kick.

reasonstringoptional

Optional human-readable reason that lands in the member.kicked event payload.

What it returns

{  "data": {    "id": "2a91c4e7-6f38-4b52-8e0d-9c1a7b3f5d80",    "status": "churned"  }}

How it fails

RESOURCE_NOT_FOUND

unknown member_id, or the member belongs to a team outside the token's scope.

TOKEN_MISSING_ABILITY

token lacks project-user:update.

List the platform accounts a project member has connected, with which one the project reaches first.

Lists a member's connected accounts on the connectors: the platform (connector), the platform's own id, name and handle for the account, how the link was proven (source) and whether it is the one the project reaches first (preferred). Members connect accounts themselves — from the portal's Account & Recovery screen or by talking to the project's bot — so there is no tool to connect one for them. The same rows are embedded as identities[] in get_subscriber's REST counterpart, GET /v1/projects/{project}/members/{member}.

Requires ability

The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.

The REST endpoint and this tool share one action, so validation, permissions and events are identical.

Annotations

Read-only

It reads and never changes anything.

Arguments

member_id*string

UUID of the project member whose connected accounts to list.

What it returns

{  "data": [    {      "id": "6a1f0c3e-2d4b-4e8a-9c7d-1b5e3f9a2c4d",      "connector": "telegram",      "source": "handshake",      "preferred": true,      "external_id": "123456789",      "display_name": "Ada Lovelace",      "username": "ada",      "linked_at": "2026-09-12T10:05:00Z"    }  ]}

id is the link, which is what unlink_member_identity takes; external_id is the platform's id for the account. source is one of handshake (connected from the portal and confirmed by the bot, or a portal sign-in), adopted (taken over from a sibling project), portal, bot (the bot met the account first) or backfill (migrated from before connectors).

How it fails

RESOURCE_NOT_FOUND

unknown member_id, or the member belongs to a team outside the token's scope.

TOKEN_MISSING_ABILITY

token lacks project-user:view.

Paginated list of project members with optional filters by project, status, and free-text search.

List members (project subscribers) with optional filters by project_id, status, and a free-text search across name, email and billing email. Results are scoped to the token's team and ordered newest-first.

Emails are returned verbatim. Scrub before forwarding to external systems.

Requires ability

The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.

Runs the same action as

The REST endpoint and this tool share one action, so validation, permissions and events are identical.

Annotations

Read-only

It reads and never changes anything.

Arguments

project_idstringoptional

Optional project UUID to narrow the result.

statusstringoptional

Member status filter. One of: lead, trialing, customer, churned, banned

leadtrialingcustomerchurnedbanned
searchstringoptional

Case-insensitive partial match against name + email.

limitintegeroptional

Maximum members to return per page (1..100).

min1max100
pageintegeroptional

1-indexed page number.

min1

What it returns

{  "data": [    {      "id": "2a91c4e7-6f38-4b52-8e0d-9c1a7b3f5d80",      "project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13",      "name": "Jane Doe",      "email": "[email protected]",      "email_verified": true,      "billing_email": "[email protected]",      "identities": [        {          "connector": "telegram",          "external_id": "123456789",          "display_name": "Jane Doe",          "username": "janedoe",          "preferred": true        }      ],      "status": "customer",      "joined_at": "2026-05-18T10:05:00Z"    }  ],  "meta": {    "page": 1,    "limit": 25,    "total": 41,    "has_more": true  }}

How it fails

TOKEN_MISSING_ABILITY

token lacks project-user:view-any.

RESOURCE_NOT_FOUND

project_id names a project the token cannot see: unknown, another team's, or outside the token's scope:project: allow-list. Without a project_id, the list spans only the projects the allow-list admits.

VALIDATION_FAILED

status is not one of the member statuses; the error context lists the supported values.

Caveats

  • email and billing_email mean different things. email is an address the member chose and verified, and is their portal sign-in credential. billing_email is whatever they typed at a payment provider's checkout — never verified, never used for authentication. Do not treat a billing_email as a confirmed way to reach someone.
  • Most members have email: null. They join through a bot and are never asked for one, so billing_email is often the only address on record — which is what makes it useful for matching a refund request to a subscription.
  • billing_email is null for anyone who joined by redeeming an access code, because no payment ever took place. It is also null for members whose last payment predates automatic capture.

Size a broadcast without sending it. Returns every audience segment with its current recipient count.

Read-only. Returns how many members a broadcast would reach, either for one named segment or for every segment at once. Nothing is sent.

Call this before broadcast_message, every time, and show the human the count. An audience that silently resolves to everyone is the one broadcast mistake that cannot be undone.

Requires ability

The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.

The REST endpoint and this tool share one action, so validation, permissions and events are identical.

Annotations

Read-only

It reads and never changes anything.

Arguments

project_id*string

UUID of the project to size a broadcast for.

audiencestringoptional

Size one segment only. Omit to receive every segment with its count.

pass_window_idstringoptional

Needed to size the single-window pass segments; without it they report a null count.

plan_idstringoptional

Optional plan UUID. Sizes each segment as narrowed to that plan. Segments that cannot use a plan filter (`lead`, the pass segments) report their unnarrowed count and a null plan_id.

expiring_within_daysintegeroptional

How far ahead `expiring_soon` looks, 1-90, default 7. Ignored by every other segment.

What it returns

{  "data": {    "project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13",    "has_connected_bot": true,    "segments": [      {        "value": "customer",        "label": "Customers Only",        "description": "Members with an active paid subscription.",        "requires_pass_window": false,        "supports_plan_filter": true,        "requires_expiring_within_days": false,        "plan_id": null,        "expiring_within_days": null,        "recipient_estimate": 128,        "estimated_seconds": 5      }    ]  }}

Omitting audience returns every segment:

A segment that addresses a single window reports recipient_estimate: null unless a pass_window_id is supplied — it cannot be sized without knowing which window, and a misleading 0 would read as "nobody holds this".

supports_plan_filter and requires_expiring_within_days say which extra inputs each segment accepts, so an agent can decide what to ask a human for before proposing anything.

Unlike broadcast_message, a plan_id a segment cannot use is dropped for that segment rather than refused — the no-audience form sizes every segment in one call, and refusing would make a plan filter unusable for the very listing used to choose a segment. Each row reports the plan_id it actually applied, so nothing is silently ignored.

Check has_connected_bot before proposing a send: a project without one cannot broadcast at all.

unban_member

DESTRUCTIVE

Lift a ban on a project member. Status rolls to churned; next successful payment promotes them back to customer.

Lift a ban on a project member. Status moves from banned to churned — if the subscriber still has active subscriptions, the next successful-payment transition promotes them to customer automatically. Delegates to an Action so cache invalidation runs.

Requires ability

The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.

The REST endpoint and this tool share one action, so validation, permissions and events are identical.

Fires one event

Delivered to every endpoint subscribed to it once the change is made.

Annotations

DestructiveIdempotentOpen world

A client that honours annotations asks a person before running it. Sending the same arguments twice changes nothing the second time. It reaches beyond Subscriby: a connector, a provider or a member.

Arguments

member_id*string

UUID of the banned project member to unban.

What it returns

{  "data": {    "id": "2a91c4e7-6f38-4b52-8e0d-9c1a7b3f5d80",    "status": "churned"  }}

How it fails

RESOURCE_NOT_FOUND

unknown member_id, or the member belongs to a team outside the token's scope.

TOKEN_MISSING_ABILITY

token lacks project-user:update.

Disconnect one of a project member's platform accounts, keeping them a way to sign in.

Disconnects one of a member's connected accounts on the creator's behalf: the account no longer signs the member in to the portal, and the project's bot no longer knows them by it. The same recovery rule the portal applies to the member holds here — the account cannot be removed when it is the member's last way to sign in (no verified email, linked Google account or other connected account remains). Emits member.identity_unlinked. Destructive and not idempotent: a second call answers RESOURCE_NOT_FOUND.

Requires ability

The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.

The REST endpoint and this tool share one action, so validation, permissions and events are identical.

Delivered to every endpoint subscribed to it once the change is made.

Annotations

Destructive

A client that honours annotations asks a person before running it.

member_id*string

UUID of the project member.

identity_id*string

The link `id` from `list_member_identities` to disconnect.

{  "data": {    "member_id": "2a91c4e7-6f38-4b52-8e0d-9c1a7b3f5d80",    "identity_id": "6a1f0c3e-2d4b-4e8a-9c7d-1b5e3f9a2c4d",    "connector": "telegram",    "removed": true  }}
RESOURCE_NOT_FOUND

unknown member_id, an identity_id that is not one of that member's links, or a member outside the token's scope.

VALIDATION_FAILED

the account is the member's last way to sign in. Have them add an email or connect another account first.

TOKEN_MISSING_ABILITY

token lacks project-user:update.

How is this guide?

On this page

Subscriby is a product designed by you — for you.No boardroom full of executives deciding what we ships next. Our roadmap always shaped by you with your feedback.

Share feedback or a request