tgpay cryptoAPI
crypto-payapitransferspayouts

API reference: transfers and checks

4 min readUpdated Sep 7, 2026

The payout methods. A transfer sends funds from your app balance straight to a Telegram user’s wallet; a check is a claimable link you fund up front. Conventions (auth, envelope, amounts, spend_id) are on the Merchant API reference page.

All three money-out methods obey the app’s payout mode: a new app pays anyone from the start; if the owner tightened it, only listed recipients can be paid (403 recipient_not_allowed) or nothing at all (403 payouts_disabled). The owner sets the mode in the Mini App; the API cannot. What the payouts may be for is set by the Merchant API terms.

transfer

POST /pay/api/transfer — scope payouts, limit 30 per minute. Settles instantly and atomically; there is no pending state.

ParameterTypeRequiredMeaning
user_idintegeryesthe recipient’s Telegram user id. The recipient must already be a user of the app — a payout to an unknown id errors instead of stranding funds
assetstringyesasset code
amountstringyespositive decimal string; also bounded by the platform’s per-transfer minimum and maximum (a US-dollar-equivalent estimate at current rates)
spend_idstringyesidempotency key, 1–64 characters, unique per payout
commentstringnoup to 1024 characters, shown to the recipient
disable_send_notificationbooleannotrue = don’t notify the recipient in Telegram

The result is the transfer object: transfer_id, hash, user_id, asset, amount, amount_minor, spend_id, comment, status (always completed), created_at, completed_at.

Errors: 403 payouts_disabled / 403 recipient_not_allowed (the payout mode), 404 user_not_found (the recipient has never used the app), 409 recipient_blocked, 400 amount_too_small / 400 amount_too_big (outside the per-transfer bounds), 409 insufficient_funds, 404 unknown_asset, 400 invalid_amount, and the spend_id pair 409 idempotency_conflict / 409 idempotency_in_progress.

transferBatch

POST /pay/api/transferBatch — scope payouts, limit 10 per minute. An extension for mass payouts: up to 100 transfers in one call.

One parameter: items — an array where each item is a full transfer parameter set (user_id, asset, amount, spend_id, optional comment and disable_send_notification). spend_ids must be unique within the batch, or the whole call fails with 400 duplicate_spend_id before anything executes.

Items settle independently, in order — one failed item never rolls back the others. The call returns HTTP 200 with ok: true even when some items failed, so always check each item:

  • success: {"ok": true, "spend_id": "…", "result": <transfer object>}
  • failure: {"ok": false, "spend_id": "…", "error": {"code": …, "name": "…"}} with the same error names as a single transfer.

Batch items share the idempotency namespace with single transfers: retrying the whole batch — or re-sending one item as a single transfer with the same spend_id — replays instead of paying twice.

getTransfers

GET /pay/api/getTransfers — scope read. Filters: asset, transfer_ids (comma-separated), spend_id (exact match — look up a payout by your own key), plus offset / count. Returns {"items": [transfer, …]}, newest first.

createCheck

POST /pay/api/createCheck — scope checks, limit 60 per minute. Creates a single-use check funded from your app balance; anyone with the link — or only the pinned user — can claim it into their wallet. The amount is locked the moment the check is created (it moves from available to onhold in getBalance).

ParameterTypeRequiredMeaning
assetstringyesasset code
amountstringyespositive decimal string
pin_to_user_idintegernoonly this Telegram user id may claim
pin_to_usernamestringnoonly this @username may claim (the @ is optional; ignored when pin_to_user_id is also set). The username must belong to an existing user of the app
spend_idstringnoidempotency key (extension) — use one

The result is the check object: check_id, hash, asset, amount, amount_minor, bot_check_url (the t.me claim link), status (active / activated), pin_to_user_id, created_at, activated_at. A claim fires the opt-in check_activated webhook.

Errors: 403 payouts_disabled / 403 recipient_not_allowed (the payout mode — under the allowlist mode a check must be pinned to a listed user), 404 unknown_asset, 400 invalid_amount, 404 user_not_found (the pinned username matches nobody), 409 insufficient_funds, and the spend_id pair.

deleteCheck

POST /pay/api/deleteCheck — scope checks. One parameter: check_id. Cancels an unclaimed check and returns the locked amount to your app balance; returns true. Errors: 404 check_not_found, 409 check_not_active (already claimed or deleted).

getChecks

GET /pay/api/getChecks — scope read. Filters: asset, check_ids (comma-separated), status (active / activated), plus offset / count. Returns {"items": [check, …]}, newest first; deleted checks are never returned.