API reference: subscriptions
Recurring billing — an extension over Crypto Bot. You create a plan (amount + period), send users its approval link, and the platform charges them from their wallet balance every period, crediting your app balance net of fee. Conventions are on the Merchant API reference page.
The model
A plan is an immutable snapshot: the mandate a user approves is exactly this amount per this period. To change the price, create a new plan and archive the old one — existing subscribers keep renewing on the terms they approved. The first period is charged at approval.
Renewals bill automatically at each period’s end. When a renewal fails
(insufficient balance, restricted account), the subscription enters
grace and the platform retries hourly within the grace period
(currently 48 hours); if it still can’t collect, the subscription becomes
expired. Merchants read current_period_end as the access deadline.
Every lifecycle event has an opt-in webhook:
subscription_activated, subscription_charged,
subscription_cancelled, subscription_expired.
createSubscriptionPlan
POST /pay/api/createSubscriptionPlan — scope subscriptions.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
name | string | yes | 1–64 characters, shown to the subscriber |
asset | string | yes | asset code |
amount | string | yes | the per-period charge, positive decimal string |
period_days | integer | yes | billing period in days, from the platform minimum (currently 7) to 365 |
The result is the plan object: plan_id, name, asset, amount,
amount_minor, period_days, archived, mini_app_subscribe_url — the
t.me link you send users to approve — and created_at.
Errors: 404 unknown_asset, 400 invalid_amount, 409 invalid_period,
503 subs_disabled (the feature is switched off platform-side).
getSubscriptionPlans
GET /pay/api/getSubscriptionPlans — scope read, no parameters.
Returns {"items": [plan, …]}, newest first, each with one extra field:
active_subscribers — the count of live (active + grace)
subscriptions on the plan.
archiveSubscriptionPlan
POST /pay/api/archiveSubscriptionPlan — scope subscriptions. One
parameter: plan_id. Stops new approvals; existing subscriptions keep
renewing on their snapshot (end them one by one with
cancelSubscription). Archiving can’t be undone through the API. The
result is the updated plan object with archived: true. Error:
404 plan_not_found.
getSubscriptions
GET /pay/api/getSubscriptions — scope read. Filters: plan_id,
user_id, status (active / grace / cancelled / expired), plus
offset / count (max 500). Returns {"items": [subscription, …]},
newest first.
The subscription object: subscription_id, plan_id, user_id (the
subscriber’s Telegram ID), the snapshot terms (asset, amount,
amount_minor, period_days), status, auto_renew, period_no (paid
periods so far), current_period_start / current_period_end,
created_at, cancelled_at, cancelled_by (user or merchant),
expired_at.
cancelSubscription
POST /pay/api/cancelSubscription — scope subscriptions. One
parameter: subscription_id. Stops renewals (cancelled_by: "merchant");
the paid period stays usable until current_period_end, the status flips
to cancelled immediately, and the subscriber is notified. A canceled
subscriber can re-approve later through the same plan link. The result is
the updated subscription object.
Errors: 404 sub_not_found, 409 sub_not_active (already canceled or
expired).
Was this article helpful?
Thanks for the feedback.