Version

Distribution API

Every project exposes two public URLs: the subscriber portal and the deep link into the project's connector installation, with a start payload that decides what opens.

Every project exposes two public URLs: the subscriber portal and the deep link into the project's connector installation, with a start payload that decides what opens. These endpoints return the canonical strings so clients do not reconstruct them from project, installation and plan fields themselves; if the URL shapes ever change, REST callers get the update for free. The connector shapes its own links; nothing here spells a platform's URL.

Endpoints

GET

Builds a start link against the project's connected installation. The payload depends on which query parameter you pass (at most one; an access code wins over a plan, and a plan over a custom parameter):

Query parameterResulting payloadActed on by the bot?
access_codethe code verbatimYes: redeemed on open.
plan_idthe plan's bare UUIDYes: opens that plan's checkout flow.
customthe caller-supplied stringNo, see below.
(none)project_<uuid>No: falls through to the project home, which is the intent.

Only a bare UUID is acted on. The bot acts on a start payload only when it is a bare UUID: it is matched against the project's plans first, then tried as an access code. custom payloads and the default project_<uuid> do not match that shape, so the bot ignores them and opens its home screen. custom is therefore a passthrough for your own tracking: the platform delivers it and you can read it off the update in a webhook consumer, but Subscriby neither stores it nor attaches it to the member.

curl "https://api.subscriby.net/v1/projects/$PROJECT_ID/distribution/deep-link?plan_id=$PLAN_ID" \  -H "Authorization: Bearer $SUBSCRIBY_TOKEN"
GET
/v1/projects/{project}/distribution/deep-link

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

Query Parameters

plan_id?|

A plan of this project; the link then opens that plan's checkout. Answers 404 for a plan outside the project. Ignored when access_code is also sent.

Formatuuid
access_code?|

An access code, carried verbatim and redeemed when the link is opened. Wins over plan_id and custom.

Lengthlength <= 64
custom?|

Your own tracking string, 1 to 64 characters of letters, digits, underscore or hyphen. Delivered by the platform but not acted on or stored by Subscriby. Used only when neither access_code nor plan_id is sent.

Match^[A-Za-z0-9_-]{1,64}$

Responses

200OK

The bot URL, the start payload and the assembled deep link.

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: when plan_id does not belong to this project.

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: with reason: no_bot_attached when the project has no connected installation to link to. VALIDATION_FAILED: on plan_id when it is not a UUID, or on custom when it is not 1 to 64 characters of letters, digits, underscore or hyphen.

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 the portal URL

GET

The portal URL always uses the project's current handle. If you change the handle the portal URL updates in lock-step; any old link answers 404 on the portal host.

GET
/v1/projects/{project}/distribution/portal-url

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

Responses

200OK

The portal URL for the project's handle.

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.

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