tgpay cryptoAPI
crypto-payapisubscriptionsrecurring

API reference: subscriptions

3 min readUpdated Oct 9, 2026

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 (the duration is set by the platform); 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.

ParameterTypeRequiredMeaning
namestringyes1–64 characters, shown to the subscriber
assetstringyesasset code
amountstringyesthe per-period charge, positive decimal string
period_daysintegeryesbilling period in days, from the platform minimum (reported by invalid_period when the period is too short) 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: 400 unknown_asset, 400 invalid_amount, 409 invalid_period, 503 subs_disabled (the feature is unavailable), and 409 too_many_plans (archive an unused plan before creating another).

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 through the same link while the plan and app remain available. Re-approval charges immediately and starts a new period. The result is the updated subscription object.

Errors: 404 sub_not_found, 409 sub_not_active (already canceled or expired).