Version

Members API

Members are the project-scoped subscribers.

Members are the project-scoped subscribers. Every payment is made on behalf of a member; every access grant a connector issues resolves to one. These endpoints list and read them, flip the three moderation states (ban, unban, kick) and manage the accounts a member has connected on the connectors.

Endpoints

List a project's members

GET
curl "https://api.subscriby.net/v1/projects/$PROJECT_ID/members?status=customer" \  -H "Authorization: Bearer $SUBSCRIBY_TOKEN"

Newest first, paged with page and per_page (default 25; limit is accepted as an alias). status narrows to one lifecycle state. identity looks one member up by the account they connected, connector:external_id, for a workflow that starts from a platform event and needs the member behind an account id; the page then holds that one member with their identities embedded, or no rows.

GET
/v1/projects/{project}/members

Requires ability

The token must hold this ability, or the call is refused with 403.

Run the same action from an agent, behind the same ability.

Authorization

bearerToken
AuthorizationBearer <token>

A personal access token minted on the dashboard under Settings, then Tokens, sent as Authorization: Bearer sbt_live_…. The token carries the abilities each endpoint lists under Requires ability and is frozen to one team.

In: header

Path Parameters

project*string

The project, resolved by the route binder.

Formatuuid

Query Parameters

status?|

Narrow the page to one lifecycle state: lead, trialing, customer, churned or banned. Any other value is refused rather than answered with an empty page, so a typo in an automation is noticed.

identity?|

Find the member who connected a given account: the connector key and the platform's own id for the account joined by a colon, connector:123456789. The page then holds that one member with their identities embedded, or no rows when nobody in the project connected that account. A value with no connector before the colon is refused.

Match^[a-z0-9][a-z0-9-]*:\S+$
Lengthlength <= 255
page?integer

The 1-based page to return. A page past the last answers an empty data array with meta.total still filled, so a loop can stop without guessing.

Range1 <= value
Default1
per_page?integer

Rows per page, 1 to 100. A higher value clamps to the cap silently. Defaults to 25.

Range1 <= value <= 100
Default25
sort_by?string

The column to order by. Defaults to created_at; a column the endpoint does not offer falls back to the default rather than failing.

Default"created_at"
sort_direction?string

asc or desc. Defaults to desc.

Default"desc"

Value in

  • "asc"
  • "desc"
limit?integer

Legacy alias of per_page, kept for clients that predate it. per_page wins when both are sent.

Range1 <= value <= 100

Responses

200OK

The page, newest first; one row or none when narrowed to an account, with its connected accounts embedded.

401Unauthorized

The request carries no bearer token, or one that is revoked, malformed, or minted for another environment (an sbt_test_ token on production).

403Forbidden

The token is valid but does not carry the ability this endpoint requires; error.context.required_ability names the one to grant. An endpoint that also checks who owns a row or which tier the account is on answers FORBIDDEN, TEAM_TIER_REQUIRED or CONNECTOR_TIER_REQUIRED with the same status, and says so in its own description.

404Not found

An id in the path names nothing the token can see. TENANT_MISMATCH: the project sits outside the token's scope:project: allow-list, or the token carries no team scope. Both answer 404 rather than 403 so that existence outside the token's scope cannot be inferred.

422Validation failed

The payload broke a rule, and error.fields maps each offending key to its messages. A refusal from the domain, such as a plan that cannot go on sale or a member who cannot be removed, uses the same code with error.message saying why and no fields. On this endpoint: VALIDATION_FAILED: when status is not one of the five states, or identity has no connector before the colon.

429Too many requests

The token has spent its 300 requests a minute or 10,000 an hour; Retry-After says when the next one is accepted.

Get a member

GET

One member with their connected accounts embedded as identities.

email and billing_email are present only when the calling token carries project-user:view, which this route requires; a roster-only token (project-user:view-any) never sees them on the list, where the keys are absent, not null. The two are not interchangeable:

FieldWhere it comes fromSafe to contact?
emailThe member chose it themselves and verified it. It is their portal sign-in credential.Yes
billing_emailWhatever address they gave a payment provider at checkout. Never verified, never used for authentication.Treat as identification only

Members join through a bot and are never asked for an email, so for most of them email is null and billing_email is the only address on record, which is what makes it useful for matching a refund request to a subscription.

billing_email is populated automatically from the payment provider on every new payment (Stripe, PayPal, Paystack, Razorpay and Skrill). Members who last paid before that capture existed may have null until their next payment, and members who joined by redeeming an access code never had a payment at all, so they have no billing address to record.

GET
/v1/projects/{project}/members/{member}

Requires ability

The token must hold this ability, or the call is refused with 403.

Runs the same action from an agent, behind the same ability.

Authorization

bearerToken
AuthorizationBearer <token>

A personal access token minted on the dashboard under Settings, then Tokens, sent as Authorization: Bearer sbt_live_…. The token carries the abilities each endpoint lists under Requires ability and is frozen to one team.

In: header

Path Parameters

project*string

The project, resolved by the route binder.

Formatuuid
member*string

The member, resolved within the project by the route binder.

Formatuuid

Responses

200OK

The member.

401Unauthorized

The request carries no bearer token, or one that is revoked, malformed, or minted for another environment (an sbt_test_ token on production).

403Forbidden

The token is valid but does not carry the ability this endpoint requires; error.context.required_ability names the one to grant. An endpoint that also checks who owns a row or which tier the account is on answers FORBIDDEN, TEAM_TIER_REQUIRED or CONNECTOR_TIER_REQUIRED with the same status, and says so in its own description.

404Not found

An id in the path names nothing the token can see. TENANT_MISMATCH: the project sits outside the token's scope:project: allow-list, or the token carries no team scope. Both answer 404 rather than 403 so that existence outside the token's scope cannot be inferred.

429Too many requests

The token has spent its 300 requests a minute or 10,000 an hour; Retry-After says when the next one is accepted.

curl https://api.subscriby.net/v1/projects/$PROJECT_ID/members/$MEMBER_ID/identities \  -H "Authorization: Bearer $SUBSCRIBY_TOKEN"

The member's connected accounts, preferred first. Never paginated. A member can connect one account per platform the project is on, from the portal's Account & Recovery screen or by talking to the project's bot; the member read embeds the same rows as identities. Connecting has no endpoint: it is a two-sided proof the member completes on the connector.

  • id is the link, which is what the disconnect endpoint takes; external_id is the platform's own id for the account.
  • source says how the link was proven: handshake (connected from the portal and confirmed by the bot, or a portal sign-in), adopted (taken over from another of the creator's projects), portal, bot (the bot met the account first) or backfill (migrated from before connectors).
  • preferred marks the account the project reaches first; a member's first account is, and the member can move it on the portal.
  • notify marks a further account the member switched the project's notices on for, from the portal. The preferred account always hears them, so it reads false there too; a grant notice stays on the connector of the grant and a support reply on the connector the member wrote from, whatever the switches say.
GET
/v1/projects/{project}/members/{member}/identities

Requires ability

The token must hold this ability, or the call is refused with 403.

Runs the same action from an agent, behind the same ability.

Authorization

bearerToken
AuthorizationBearer <token>

A personal access token minted on the dashboard under Settings, then Tokens, sent as Authorization: Bearer sbt_live_…. The token carries the abilities each endpoint lists under Requires ability and is frozen to one team.

In: header

Path Parameters

project*string

The project, resolved by the binder.

Formatuuid
member*string

The member, resolved within the project.

Formatuuid

Responses

200OK

Array of MemberIdentityResource

401Unauthorized

The request carries no bearer token, or one that is revoked, malformed, or minted for another environment (an sbt_test_ token on production).

403Forbidden

The token is valid but does not carry the ability this endpoint requires; error.context.required_ability names the one to grant. An endpoint that also checks who owns a row or which tier the account is on answers FORBIDDEN, TEAM_TIER_REQUIRED or CONNECTOR_TIER_REQUIRED with the same status, and says so in its own description.

404Not found

An id in the path names nothing the token can see. TENANT_MISMATCH: the project sits outside the token's scope:project: allow-list, or the token carries no team scope. Both answer 404 rather than 403 so that existence outside the token's scope cannot be inferred.

429Too many requests

The token has spent its 300 requests a minute or 10,000 an hour; Retry-After says when the next one is accepted.

Ban a member

POST
curl -X POST https://api.subscriby.net/v1/projects/$PROJECT_ID/members/$MEMBER_ID/ban \  -H "Authorization: Bearer $SUBSCRIBY_TOKEN" \  -H "Idempotency-Key: $(uuidgen)" \  -H "Content-Type: application/json" \  -d '{"reason": "Repeated spam in the research channel."}'

Moves a lead, customer, trialing or churned member to banned, removes their access on every connector and emits member.banned with the optional reason. Answers 200 with the member; a member already banned is answered unchanged and emits nothing.

Connector-side eviction (kicks from the gated spaces, revoked invite links) runs asynchronously on the connector pipeline after the flip. The call returns as soon as Subscriby's state has been updated and the webhook event has been fired; the platform actions complete in the background.

POST
/v1/projects/{project}/members/{member}/ban

Requires ability

The token must hold this ability, or the call is refused with 403.

Fires one event

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

MCP tool

Runs the same action from an agent, behind the same ability.

Idempotent

Send the header on every call; the same key replays the original response for 24 hours.

Authorization

bearerToken
AuthorizationBearer <token>

A personal access token minted on the dashboard under Settings, then Tokens, sent as Authorization: Bearer sbt_live_…. The token carries the abilities each endpoint lists under Requires ability and is frozen to one team.

In: header

Path Parameters

project*string

The project, resolved by the route binder.

Formatuuid
member*string

The member, resolved within the project by the route binder.

Formatuuid

Header Parameters

Idempotency-Key*string

A key unique to this operation, such as a fresh UUID. The same key replays the original 2xx response for 24 hours (with Idempotent-Replay: true), so a retry after a timeout never repeats the write; the same key with a different body is refused with 409.

Formatuuid

Request body

JSONWhat the request carries

Responses

200OK

The member after the change.

400Bad request

Every write needs an Idempotency-Key header. Send a fresh UUID per distinct operation.

401Unauthorized

The request carries no bearer token, or one that is revoked, malformed, or minted for another environment (an sbt_test_ token on production).

403Forbidden

The token is valid but does not carry the ability this endpoint requires; error.context.required_ability names the one to grant. An endpoint that also checks who owns a row or which tier the account is on answers FORBIDDEN, TEAM_TIER_REQUIRED or CONNECTOR_TIER_REQUIRED with the same status, and says so in its own description.

404Not found

An id in the path names nothing the token can see. TENANT_MISMATCH: the project sits outside the token's scope:project: allow-list, or the token carries no team scope. Both answer 404 rather than 403 so that existence outside the token's scope cannot be inferred.

409Conflict

The key was already used in the last 24 hours with a different request body.

422Validation failed

The payload broke a rule, and error.fields maps each offending key to its messages. A refusal from the domain, such as a plan that cannot go on sale or a member who cannot be removed, uses the same code with error.message saying why and no fields.

425Too early

The first request with this key is still running; retry in a few seconds and the original response is replayed.

429Too many requests

The token has spent its 300 requests a minute or 10,000 an hour; Retry-After says when the next one is accepted.

Kick a member

POST

Moves the member to churned, removes them from every resource and emits member.kicked with the optional reason. Unlike a ban, a kicked member may come back by subscribing again. Answers 200 with the member; a banned member is answered unchanged, since a ban already says more. As with a ban, the connector-side eviction completes in the background after the call returns.

POST
/v1/projects/{project}/members/{member}/kick

Requires ability

The token must hold this ability, or the call is refused with 403.

Fires one event

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

MCP tool

Runs the same action from an agent, behind the same ability.

Idempotent

Send the header on every call; the same key replays the original response for 24 hours.

Authorization

bearerToken
AuthorizationBearer <token>

A personal access token minted on the dashboard under Settings, then Tokens, sent as Authorization: Bearer sbt_live_…. The token carries the abilities each endpoint lists under Requires ability and is frozen to one team.

In: header

Path Parameters

project*string

The project, resolved by the route binder.

Formatuuid
member*string

The member, resolved within the project by the route binder.

Formatuuid

Header Parameters

Idempotency-Key*string

A key unique to this operation, such as a fresh UUID. The same key replays the original 2xx response for 24 hours (with Idempotent-Replay: true), so a retry after a timeout never repeats the write; the same key with a different body is refused with 409.

Formatuuid

Request body

JSONWhat the request carries

Responses

200OK

The member after the change.

400Bad request

Every write needs an Idempotency-Key header. Send a fresh UUID per distinct operation.

401Unauthorized

The request carries no bearer token, or one that is revoked, malformed, or minted for another environment (an sbt_test_ token on production).

403Forbidden

The token is valid but does not carry the ability this endpoint requires; error.context.required_ability names the one to grant. An endpoint that also checks who owns a row or which tier the account is on answers FORBIDDEN, TEAM_TIER_REQUIRED or CONNECTOR_TIER_REQUIRED with the same status, and says so in its own description.

404Not found

An id in the path names nothing the token can see. TENANT_MISMATCH: the project sits outside the token's scope:project: allow-list, or the token carries no team scope. Both answer 404 rather than 403 so that existence outside the token's scope cannot be inferred.

409Conflict

The key was already used in the last 24 hours with a different request body.

422Validation failed

The payload broke a rule, and error.fields maps each offending key to its messages. A refusal from the domain, such as a plan that cannot go on sale or a member who cannot be removed, uses the same code with error.message saying why and no fields.

425Too early

The first request with this key is still running; retry in a few seconds and the original response is replayed.

429Too many requests

The token has spent its 300 requests a minute or 10,000 an hour; Retry-After says when the next one is accepted.

Unban a member

POST

Moves a banned member to churned and emits member.unbanned. Access is not restored: the member subscribes again from the portal or the bot. Answers 200 with the member; a member who is not banned is answered unchanged and emits nothing.

POST
/v1/projects/{project}/members/{member}/unban

Requires ability

The token must hold this ability, or the call is refused with 403.

Fires one event

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

MCP tool

Runs the same action from an agent, behind the same ability.

Idempotent

Send the header on every call; the same key replays the original response for 24 hours.

Authorization

bearerToken
AuthorizationBearer <token>

A personal access token minted on the dashboard under Settings, then Tokens, sent as Authorization: Bearer sbt_live_…. The token carries the abilities each endpoint lists under Requires ability and is frozen to one team.

In: header

Path Parameters

project*string

The project, resolved by the route binder.

Formatuuid
member*string

The member, resolved within the project by the route binder.

Formatuuid

Header Parameters

Idempotency-Key*string

A key unique to this operation, such as a fresh UUID. The same key replays the original 2xx response for 24 hours (with Idempotent-Replay: true), so a retry after a timeout never repeats the write; the same key with a different body is refused with 409.

Formatuuid

Responses

200OK

The member after the change.

400Bad request

Every write needs an Idempotency-Key header. Send a fresh UUID per distinct operation.

401Unauthorized

The request carries no bearer token, or one that is revoked, malformed, or minted for another environment (an sbt_test_ token on production).

403Forbidden

The token is valid but does not carry the ability this endpoint requires; error.context.required_ability names the one to grant. An endpoint that also checks who owns a row or which tier the account is on answers FORBIDDEN, TEAM_TIER_REQUIRED or CONNECTOR_TIER_REQUIRED with the same status, and says so in its own description.

404Not found

An id in the path names nothing the token can see. TENANT_MISMATCH: the project sits outside the token's scope:project: allow-list, or the token carries no team scope. Both answer 404 rather than 403 so that existence outside the token's scope cannot be inferred.

409Conflict

The key was already used in the last 24 hours with a different request body.

425Too early

The first request with this key is still running; retry in a few seconds and the original response is replayed.

429Too many requests

The token has spent its 300 requests a minute or 10,000 an hour; Retry-After says when the next one is accepted.

DELETE
curl -X DELETE https://api.subscriby.net/v1/projects/$PROJECT_ID/members/$MEMBER_ID/identities/$LINK_ID \  -H "Authorization: Bearer $SUBSCRIBY_TOKEN" \  -H "Idempotency-Key: $(uuidgen)"

Disconnects an account on the creator's behalf, the counterpart of the member's own Disconnect on the portal: it no longer signs the member in and the bot no longer knows them by it. Answers an empty 204 and emits member.identity_unlinked.

DELETE
/v1/projects/{project}/members/{member}/identities/{link}

Requires ability

The token must hold this ability, or the call is refused with 403.

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

Runs the same action from an agent, behind the same ability.

Idempotent

Send the header on every call; the same key replays the original response for 24 hours.

Authorization

bearerToken
AuthorizationBearer <token>

A personal access token minted on the dashboard under Settings, then Tokens, sent as Authorization: Bearer sbt_live_…. The token carries the abilities each endpoint lists under Requires ability and is frozen to one team.

In: header

Path Parameters

project*string

The project, resolved by the binder.

Formatuuid
member*string

The member, resolved within the project.

Formatuuid

Header Parameters

Idempotency-Key*string

A key unique to this operation, such as a fresh UUID. The same key replays the original 2xx response for 24 hours (with Idempotent-Replay: true), so a retry after a timeout never repeats the write; the same key with a different body is refused with 409.

Formatuuid

Responses

204No content

No content

400Bad request

Every write needs an Idempotency-Key header. Send a fresh UUID per distinct operation.

401Unauthorized

The request carries no bearer token, or one that is revoked, malformed, or minted for another environment (an sbt_test_ token on production).

403Forbidden

The token is valid but does not carry the ability this endpoint requires; error.context.required_ability names the one to grant. An endpoint that also checks who owns a row or which tier the account is on answers FORBIDDEN, TEAM_TIER_REQUIRED or CONNECTOR_TIER_REQUIRED with the same status, and says so in its own description.

404Not found

An id in the path names nothing the token can see. TENANT_MISMATCH: the project sits outside the token's scope:project: allow-list, or the token carries no team scope. Both answer 404 rather than 403 so that existence outside the token's scope cannot be inferred. On this endpoint: RESOURCE_NOT_FOUND: for a link that is not that member's.

409Conflict

The key was already used in the last 24 hours with a different request body.

422Validation failed

When the account is the member's last way to sign in (no verified email, linked Google account or other connected account remains).

425Too early

The first request with this key is still running; retry in a few seconds and the original response is replayed.

429Too many requests

The token has spent its 300 requests a minute or 10,000 an hour; Retry-After says when the next one is accepted.

How is this guide?

Version

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