Merchant API fees and limits
Invoices carry a platform fee taken from what you receive; transfers and checks are bounded by amount limits. The figures below are the current settings, not contract terms — when they disagree with what you see, the app is right, and the reliable source is always your own paid invoices.
The invoice fee
The payer always pays the face amount of the invoice. The fee comes out of the merchant side: your app balance is credited the amount net of fee.
The fee is 3% of the invoice amount, before any volume-based tier is applied. Your rate depends on the configured tiers and trailing 30-day paid invoice volume:
| 30-day volume | Fee |
|---|---|
| under $10,000 | 3% |
| $10,000+ | 2.9% |
| $25,000+ | 2.8% |
| $50,000+ | 2.7% |
| $75,000+ | 2.6% |
| $100,000+ | 2.5% |
Two rules matter more than the number:
- The fee is resolved and locked in at payment time. A later change to the rate never touches an invoice that’s already been paid.
- Your rate can change with your volume. Higher payment volume over a trailing 30-day window can move you onto a lower tier automatically. You don’t apply for it and there’s nothing to configure.
To see exactly what was charged, read fee_asset and fee_amount off the paid
invoice — from the invoice_paid webhook payload or from getInvoices. That’s
the authoritative figure for your books.
Refunds don’t return the fee: what refundInvoice sends the payer comes out
of your balance, and the fee is not refunded — including on a partial refund.
Subscription charges also carry a merchant-side fee; each charge reports its
own figure in the charge.fee field of the subscription_charged webhook.
Transfer limits
transfer has a minimum and maximum per transfer, expressed as a
US-dollar equivalent rather than a separate amount for each asset.
Handle amount_too_small and amount_too_big in your integration when
an amount is rejected by these limits.
An unknown username instead creates a pending payout when the payout
mode allows it; see transfers and checks.
A transfer also fails when:
- your app balance is short in that asset,
- the recipient isn’t a user of the app — a payout to an unknown or mistyped Telegram ID errors instead of crediting a wallet nobody will open,
- the recipient’s account is blocked.
Daily payout limit
The owner can set a rolling 24-hour limit in the app’s Payout settings.
Transfers, checks and payouts from the app balance share this limit.
Exceeding it returns 403 daily_cap_exceeded; a batch is checked before
its first payout. Refunds do not count toward this limit. getMe returns
daily_payout_max_usd_cents and daily_payout_spent_usd_cents.
Owner restrictions can also block transfers, checks and refunds
(403 verification_required); a temporary pause returns
503 merchant_payouts_paused.
Rate limits
The money-moving methods are rate-limited per app (shared across all its
tokens): createInvoice and createCheck at 60
per minute, refundInvoice at 30 per minute,
transfer at 30 per minute, and
transferBatch at 10 per minute.
updateApp and createSubscriptionPlan also have limits; see the
API reference. On rate_limited, increase the
delay before retrying.
Idempotency
transfer requires a spend_id you generate; createCheck and
refundInvoice accept one. Reusing the same value with the same parameters replays the original result
instead of moving funds a second time — so a timed-out request is safe to
retry with the same spend_id, and only a genuinely new payout gets a new
one.
What costs nothing
There’s no network fee anywhere in the Merchant API — invoices, transfers and checks all settle inside the app, off-chain. Platform fees can apply to invoices and subscription charges. An optional automatic swap uses the exchange quote. Funding a payer’s wallet from an external wallet may incur fees charged by that wallet or network.
⚠️ Never derive the fee yourself
Don’t hardcode a percentage or reconstruct the net from the face amount. Tiers and rates change, and a stale constant silently corrupts your accounting. Read the recorded fee off the invoice every time.
Was this article helpful?
Thanks for the feedback.