Access Code Tools
An access code is a pre-generated, single-use activation a creator hands out; redeeming it claims a pending subscription.
An access code is a pre-generated, single-use activation a creator hands out; redeeming it claims a pending subscription. These tools mint codes singly or in bulk, list them and revoke the ones that should no longer work.
Tools
bulk_generate_access_codesBulk Generate Access Codes (Async)READlist_access_codesList Access CodesREADpreview_access_code_costPreview Access-Code Generation Costbulk_generate_access_codes
DESTRUCTIVEQueue a bulk access-code generation batch. Returns a job_id immediately — poll get_job_status for completion.
Bulk-generate access codes for a plan. The underlying job can take minutes for large batches, so the tool returns a job_id immediately; clients poll get_job_status until status=completed. The access_code.generated event emits once per batch when the worker finishes.
Billing model: generation is free. The Stripe metered overage triggers on
redemption when the creator's tier free allotment is exhausted. The
response embeds a preview so callers can still surface the worst-case cost
("if all N get redeemed"). For a cost-only query, call
preview_access_code_cost.
Delivery goes through the creator's connector chat (the Telegram bot today),
never through this tool's response. export_type must be file (a CSV sent
to the creator) or messages (one forwardable message per code) — both
require the creator account to have a linked connector identity. Agents that
need programmatic access must also call
list_access_codes after the batch completes.
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.
Fires one event
Delivered to every endpoint subscribed to it once the change is made.
Annotations
A client that honours annotations asks a person before running it. It reaches beyond Subscriby: a connector, a provider or a member.
Arguments
plan_id*stringUUID of the plan to attach the generated codes to.
quantity*integerHow many access codes to generate (1-1000).
export_type*stringHow the job delivers the codes to the creator — file (CSV via bot) or messages (one per code via bot). Required.
expiry_preset*stringRequired. One of no_expiry, 1_day, 1_week, 1_month, 1_year, custom.
custom_expiry_amountintegeroptionalWhen expiry_preset=custom, the amount of custom_expiry_type units. Required when preset=custom.
custom_expiry_typestringoptionalWhen expiry_preset=custom, one of days/weeks/months/years. Required when preset=custom.
consentbooleanoptionalRequired and must be true when export_type=messages — acknowledges that one message per code will be sent to the creator's connector chat.
What it returns
{ "data": { "job_id": "0a4e7b96-c358-4d12-9f6b-25a8013ce74f", "status": "queued", "enqueued_at": "2026-05-18T10:05:00Z", "plan_id": "c4e82f16-93a7-4d5b-b81c-6e0f27a94d3b", "quantity": 50, "preview": { "free_remaining": 3, "chargeable_quantity": 47, "cost": "1.41" } }}Poll get_job_status with the returned job_id until status is completed or failed. It always reaches one of the two.
On completion the job's result carries the batch summary:
{
"plan_id": "c4e82f16-93a7-4d5b-b81c-6e0f27a94d3b",
"plan_name": "Premium Monthly",
"count": 50,
"export_type": "file",
"expires_at": null,
"delivered": true,
"delivery_error": null
}Generation and delivery succeed separately
The codes are written first, then handed to the creator over their connector.
If that delivery fails — the bot is disconnected, the platform is down — the
job still completes: the codes exist and are redeemable, and
access_code.generated
still fires. delivered goes false and delivery_error carries the reason,
so you can tell the creator their CSV never arrived without anyone concluding
the batch failed and generating it twice.
How it fails
VALIDATION_FAILEDquantity out of range, unknown export_type, missing consent when export_type=messages, missing custom_expiry_amount / custom_expiry_type when expiry_preset=custom, unknown expiry_preset, a batch for the same plan already in flight, or the underlying Action rejects the inputs.
RESOURCE_NOT_FOUNDunknown plan_id, or the plan belongs to a team outside the token's scope.
AUTHENTICATION_REQUIREDno authenticated user on the request.
TOKEN_MISSING_ABILITYtoken lacks project-access-code:create.
One batch per plan at a time
Queueing a second batch for a plan whose previous one has not reported an
outcome is refused with VALIDATION_FAILED, and the message names the live
job_id to poll instead.
The worker deduplicates by creator, project and plan, so a second batch inside that window would be dropped without a word — handing you a job id for work that was never going to run. Refusing up front is the honest version of the same constraint.
Paginated list of access codes for a plan, with first/last-4 masked prefixes only — full codes are never surfaced.
List access codes for a plan. Requires plan_id, accepts an optional status filter (unredeemed, redeemed, expired, or all). Results are scoped to the caller's team.
Codes are returned with a masked prefix (first 4 + asterisks + last 4). The
plaintext value is delivered to the creator's connector chat by
bulk_generate_access_codes — the
MCP layer is read-only on the secret itself.
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
It reads and never changes anything.
Arguments
plan_id*stringUUID of the plan to list codes for.
statusstringoptionalFilter by code state. One of: unredeemed, redeemed, expired, all.
allunredeemedredeemedexpiredlimitintegeroptionalMaximum codes to return per page (1..100).
1max100pageintegeroptional1-indexed page number.
1What it returns
{ "data": [ { "id": "5b7e2d40-1a86-4c39-97f2-e83d0b16c5a4", "plan_id": "c4e82f16-93a7-4d5b-b81c-6e0f27a94d3b", "code_masked": "A3F1****7Z9P", "redeemed_at": null, "expires_at": "2026-08-01T00:00:00Z", "redeemed_by": null, "created_at": "2026-05-18T10:05:00Z" } ], "meta": { "page": 1, "limit": 25, "total": 47, "has_more": true, "status": "unredeemed" }}How it fails
TOKEN_MISSING_ABILITYtoken lacks project-access-code:view-any.
Preview the cost of generating access codes before queuing the batch. Returns free_remaining, chargeable_quantity, and cost.
Preview the cost of generating access codes before queuing the batch. Returns free_remaining, chargeable_quantity, and the resulting cost in the creator-tier currency so the agent can surface the charge to a human. Always call this first when quantity might exceed the creator tier free allotment — the generation tool refuses to run with chargeable codes unless the caller acknowledges overage.
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
It reads and never changes anything.
Arguments
plan_id*stringUUID of the plan the batch would be attached to.
quantity*integerHow many access codes the agent is considering generating (1-10000).
What it returns
{ "data": { "plan_id": "c4e82f16-93a7-4d5b-b81c-6e0f27a94d3b", "quantity": 50, "preview": { "free_remaining": 3, "chargeable_quantity": 47, "cost": "1.41" }, "will_bill_overage": true }}How it fails
RESOURCE_NOT_FOUNDunknown plan_id, or the plan belongs to a team outside the token's scope.
VALIDATION_FAILEDquantity is outside the 1..10,000 range.
AUTHENTICATION_REQUIREDno authenticated user on the request.
TOKEN_MISSING_ABILITYtoken lacks project-access-code:create.
How is this guide?