Access Codes API
Access codes are pre-generated single-use subscription activations a creator hands out.
Access codes are pre-generated single-use subscription activations a creator hands out. Internally they are pending subscription rows that a subscriber redeems; redemption just claims the row. They live under the plan they activate, at /v1/projects/{project}/plans/{plan}/access-codes.
Endpoints
/v1/projects/{project}/plans/{plan}/access-codesList a plan's access codesGET/v1/projects/{project}/plans/{plan}/access-codes/previewPrice a batchPOST/v1/projects/{project}/plans/{plan}/access-codes/bulk-generateGenerate a batch of codesDELETE/v1/projects/{project}/plans/{plan}/access-codes/{accessCode}Revoke an access codePages the plan's codes, newest first, fifty per page unless you say otherwise. status narrows the list to unredeemed, redeemed or expired codes; the default all returns every state.
Raw access_code values are always masked in API responses to the last 5 characters. Plaintext codes ship only through the creator dashboard CSV export or the per-code messages a batch can be delivered as.
Requires ability
The token must hold this ability, or the call is refused with 403.
MCP tool
Runs the same action from an agent, behind the same ability.
Authorization
bearerToken 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
The project, resolved by the route binder.
uuidThe plan, resolved within the project by the route binder.
uuidQuery Parameters
Legacy alias of per_page, kept for clients that predate it. per_page wins when both are sent.
1 <= value <= 100Which codes to list: all (the default), unredeemed, redeemed or expired. An unknown value reads as all.
"all"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.
1 <= value1Rows per page, 1 to 100. A higher value clamps to the cap silently. Defaults to 15.
1 <= value <= 10015The column to order by. Defaults to created_at; a column the endpoint does not offer falls back to the default rather than failing.
"created_at"asc or desc. Defaults to desc.
"desc"Value in
- "asc"
- "desc"
Responses
200OKapplication/json
The page.
401UnauthorizedAUTHENTICATION_REQUIREDapplication/json
The request carries no bearer token, or one that is revoked, malformed, or minted for another environment (an sbt_test_ token on production).
403ForbiddenTOKEN_MISSING_ABILITYapplication/json
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 foundRESOURCE_NOT_FOUNDapplication/json
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 requestsRATE_LIMITEDapplication/json
The token has spent its 300 requests a minute or 10,000 an hour; Retry-After says when the next one is accepted.
Prices a batch of quantity codes without queuing it, so a caller can show the worst-case charge before generating.
curl "https://api.subscriby.net/v1/projects/$PROJECT/plans/$PLAN/access-codes/preview?quantity=50" \ -H "Authorization: Bearer $SUBSCRIBY_TOKEN"Generation is free. The metered overage is billed at redemption time, and only when your tier's free access-code allotment is already exhausted. Hand out codes freely; you only pay for the ones subscribers actually activate beyond the free quota.
The preview and the bulk-generate endpoint both return this cost breakdown so callers can surface the worst case ("if every one of these codes is redeemed, here is what you would owe").
Requires ability
The token must hold this ability, or the call is refused with 403.
MCP tool
Runs the same action from an agent, behind the same ability.
Authorization
bearerToken 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
The project, resolved by the route binder.
uuidThe plan, resolved within the project by the route binder.
uuidQuery Parameters
How many codes the batch would hold, 1 to 1,000.
Responses
200OKapplication/json
The cost preview.
401UnauthorizedAUTHENTICATION_REQUIREDapplication/json
The request carries no bearer token, or one that is revoked, malformed, or minted for another environment (an sbt_test_ token on production).
403ForbiddenTOKEN_MISSING_ABILITYapplication/json
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 foundRESOURCE_NOT_FOUNDapplication/json
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 failedVALIDATION_FAILEDapplication/json
When quantity is missing or outside 1 to 1,000; error.context.quantity says so.
429Too many requestsRATE_LIMITEDapplication/json
The token has spent its 300 requests a minute or 10,000 an hour; Retry-After says when the next one is accepted.
Queues a batch of codes for the plan and answers 202 Accepted at once; the codes are written by a background job and delivered the way export_type names. Poll the list endpoint, or subscribe to access_code.generated, to know when the batch is ready.
curl -X POST https://api.subscriby.net/v1/projects/$PROJECT/plans/$PLAN/access-codes/bulk-generate \ -H "Authorization: Bearer $SUBSCRIBY_TOKEN" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "quantity": 50, "export_type": "file", "expiry_preset": "1_month" }'Answers 202 with the job's key, the plan, the quantity and the cost preview the pricing endpoint describes. Bulk generation is limited to 10 batches per minute per token in its own bucket, on top of the token's general limits; the eleventh answers 429 RATE_LIMITED with Retry-After.
The validation rules are identical to the creator dashboard's: quantity 1 to 1,000; export_type file or messages, with consent: true required for messages because one bot message per code can trip the connector's rate limits; expiry_preset one of no_expiry, 1_day, 1_week, 1_month, 1_year or custom, the last needing custom_expiry_amount and custom_expiry_type (days, weeks, months or years).
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 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
The project, resolved by the route binder.
uuidThe plan, resolved within the project by the route binder.
uuidHeader Parameters
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.
uuidRequest body
JSONWhat the request carriesRequiredapplication/json
A batch of access codes to generate: how many, how they are delivered to you, and when they expire.
Responses
202Acceptedapplication/json
202 with the job key, the plan, the quantity and the preview.
400Bad requestIDEMPOTENCY_KEY_MISSINGapplication/json
Every write needs an Idempotency-Key header. Send a fresh UUID per distinct operation.
401UnauthorizedAUTHENTICATION_REQUIREDapplication/json
The request carries no bearer token, or one that is revoked, malformed, or minted for another environment (an sbt_test_ token on production).
403ForbiddenTOKEN_MISSING_ABILITYapplication/json
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 foundRESOURCE_NOT_FOUNDapplication/json
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.
409ConflictIDEMPOTENCY_KEY_REUSEDapplication/json
The key was already used in the last 24 hours with a different request body.
422Validation failedVALIDATION_FAILEDapplication/json
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 a rule above is broken; error.fields names the key, and the consent and custom-expiry messages spell out what was missing.
425Too earlyIDEMPOTENCY_REPLAY_IN_PROGRESSapplication/json
The first request with this key is still running; retry in a few seconds and the original response is replayed.
429Too many requestsRATE_LIMITEDapplication/json
The token has spent its 300 requests a minute or 10,000 an hour; Retry-After says when the next one is accepted.
On this endpoint: RATE_LIMITED: when the token has queued 10 batches within a minute.
Deletes an unredeemed code so it can no longer be claimed. The code is resolved within the plan, so an id from another plan is 404 RESOURCE_NOT_FOUND. Answers 204 with no body; no webhook fires.
Requires ability
The token must hold this ability, or the call is refused with 403.
Idempotent
Send the header on every call; the same key replays the original response for 24 hours.
Authorization
bearerToken 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
The project, resolved by the route binder.
uuidThe plan, resolved within the project by the route binder.
uuidThe unredeemed code, resolved within the plan by the route binder.
uuidHeader Parameters
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.
uuidResponses
204No content
No content
400Bad requestIDEMPOTENCY_KEY_MISSINGapplication/json
Every write needs an Idempotency-Key header. Send a fresh UUID per distinct operation.
401UnauthorizedAUTHENTICATION_REQUIREDapplication/json
The request carries no bearer token, or one that is revoked, malformed, or minted for another environment (an sbt_test_ token on production).
403ForbiddenTOKEN_MISSING_ABILITYapplication/json
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 foundRESOURCE_NOT_FOUNDapplication/json
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.
409ConflictIDEMPOTENCY_KEY_REUSEDapplication/json
The key was already used in the last 24 hours with a different request body.
425Too earlyIDEMPOTENCY_REPLAY_IN_PROGRESSapplication/json
The first request with this key is still running; retry in a few seconds and the original response is replayed.
429Too many requestsRATE_LIMITEDapplication/json
The token has spent its 300 requests a minute or 10,000 an hour; Retry-After says when the next one is accepted.
Related
How is this guide?
API Reference
Every operation of the REST API, generated from the OpenAPI document and grouped by resource.
Activity API
Every mutation Subscriby performs, whether from the dashboard, the REST API, an MCP tool call, a Zapier step or a scheduled system task, is recorded against its subject in the activity log.