Version

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

GET

Pages 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.

GET
/v1/projects/{project}/plans/{plan}/access-codes

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
plan*string

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

Formatuuid

Query Parameters

limit?integer

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

Range1 <= value <= 100
status?string

Which codes to list: all (the default), unredeemed, redeemed or expired. An unknown value reads as all.

Default"all"
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 15.

Range1 <= value <= 100
Default15
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"

Responses

200OK

The page.

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.

Price a batch

GET

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").

GET
/v1/projects/{project}/plans/{plan}/access-codes/preview

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
plan*string

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

Formatuuid

Query Parameters

quantity*integer

How many codes the batch would hold, 1 to 1,000.

Responses

200OK

The cost preview.

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

When quantity is missing or outside 1 to 1,000; error.context.quantity says so.

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.

POST

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).

POST
/v1/projects/{project}/plans/{plan}/access-codes/bulk-generate

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.

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
plan*string

The plan, 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

A batch of access codes to generate: how many, how they are delivered to you, and when they expire.

Responses

202Accepted

202 with the job key, the plan, the quantity and the preview.

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. 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 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. On this endpoint: RATE_LIMITED: when the token has queued 10 batches within a minute.

Revoke an access code

DELETE

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.

DELETE
/v1/projects/{project}/plans/{plan}/access-codes/{accessCode}

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
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
plan*string

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

Formatuuid
accessCode*string

The unredeemed code, resolved within the plan 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

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.

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.

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