Telegram communities with affiliates
Sell access to a Telegram channel or group for USDT, open the checkout as a Mini-App inside your bot, and pay each affiliate their share automatically from the same payment.
Last updated Nov 1, 2026
A paid Telegram community can take USDT or USDC with Aliquot and give every affiliate who brought a member a fixed percentage of that member's payment. The bot creates an invoice that names the affiliate in splits, opens the hosted checkout as a Telegram Mini-App, and sends an invite link when the invoice.paid webhook arrives. The affiliate's share is credited to their own balance the moment the payment is confirmed, and you pay it out to their wallet with one API call. No spreadsheets, no manual commission run.
This guide uses Sandbox (BSC_TESTNET, USDT) and plain fetch calls to the Telegram Bot API, so it works with any bot library. You need an Aliquot API key (see Quickstart), a bot token from @BotFather, and the bot added as an administrator of the private channel or group, with the right to invite users.
How the money splits
For a 20.00 USD membership with a 20 % affiliate share and the default fee_payer CUSTOMER:
| Part | Amount |
|---|---|
Buyer sends (total) | 20.00 + processing fee |
| Affiliate share (20 %) | 4.00 |
| Your platform account (seller net) | 16.00 |
| Aliquot processing fee | by monthly volume, see Processing fee |
Every part is a percentage of the base price, booked on the double-entry ledger when the invoice is paid. With fee_payer MERCHANT the buyer sends exactly 20.00 and the fee comes out of your share instead. The full arithmetic is in Ledger and splits.
1. Give each affiliate a partner account and a link
An affiliate is a PARTNER account. Create one per affiliate (permission crypto-accounts:create), with a reference you can derive from your own data, such as their Telegram user ID:
curl -X POST https://api.aliquot.cc/api/v1/crypto/accounts \
-H "Authorization: Bearer $ALIQUOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "kind": "PARTNER", "reference": "aff-5550001", "name": "Ana (affiliate)", "settlement_address": "0x7a3B9c1D5e2F4a6B8c0D1e3F5a7B9c2D4e6F8a0B" }'References are 2–63 characters of lowercase letters, digits, _ and -, and unique in your organization; a duplicate answers 409, so creating the account again is safe to treat as "already exists".
Give the affiliate a Telegram deep link that carries their reference: https://t.me/<your_bot>?start=aff-5550001. When someone opens it, Telegram sends your bot the message /start aff-5550001. Store that reference against the new member's Telegram user ID in your database; it is who gets the share when that member pays.
2. Create the invoice with the affiliate's split
When the member asks to join, create an invoice. Put their Telegram user ID in merchant_order_id: invoice webhooks carry it back, so you know whom to invite.
const BOT = `https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}`;
async function createMembershipInvoice(telegramUserId, affiliateRef) {
const orderId = `tg-${telegramUserId}-${Date.now()}`;
const res = await fetch('https://api.aliquot.cc/api/v1/crypto/invoices', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.ALIQUOT_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': orderId,
},
body: JSON.stringify({
amount: '20.00',
title: 'VIP channel · 30 days',
network: 'BSC_TESTNET',
token: 'USDT',
merchant_order_id: orderId,
...(affiliateRef ? { splits: [{ account: affiliateRef, percent: 20 }] } : {}),
}),
});
const invoice = await res.json();
if (!res.ok) throw new Error(`${res.status} ${invoice.code}: ${invoice.message}`);
return invoice; // invoice.pay_url is the hosted checkout
}- Without an affiliate, leave
splitsout: yourplatformaccount keeps the whole net. - An unknown account reference in
splitsis a422on that field. Create the partner account first. - Live is the same request on
BSC_MAINNETwith a Live key. See Networks and tokens for every pair.
3. Open the checkout as a Mini-App
Add ?tg=1 to pay_url and send it as a web_app button. Telegram opens the hosted checkout inside the chat: the same amount, QR code, wallet button and live confirmation status as /pay/:id, with the main action on Telegram's own MainButton.
async function sendCheckout(chatId, invoice) {
await fetch(`${BOT}/sendMessage`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
chat_id: chatId,
text: `VIP channel · 30 days: ${invoice.total} ${invoice.token}`,
reply_markup: {
inline_keyboard: [[{ text: 'Pay with USDT', web_app: { url: `${invoice.pay_url}?tg=1` } }]],
},
}),
});
}Telegram only allows web_app buttons in a private chat between the user and the bot. In a group, send a regular url button with pay_url instead; it opens the same checkout in the browser.
merchant_order_id, never by what the page displays.4. Send the invite when invoice.paid arrives
Subscribe an endpoint to invoice.paid (Developers → Webhooks) and verify the signature exactly as in the Quickstart receiver. Then read the Telegram user ID back from merchant_order_id and create a single-use invite link:
async function onInvoicePaid(event) {
const [, telegramUserId] = event.data.merchant_order_id.split('-');
const invite = await fetch(`${BOT}/createChatInviteLink`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
chat_id: process.env.VIP_CHAT_ID,
member_limit: 1,
expire_date: Math.floor(Date.now() / 1000) + 24 * 60 * 60,
}),
}).then((r) => r.json());
await fetch(`${BOT}/sendMessage`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ chat_id: telegramUserId, text: `Paid. Your invite: ${invite.result.invite_link}` }),
});
}Make it idempotent on event.data.invoice_id: a delivery your endpoint does not answer with 2xx is retried, so the same event can arrive more than once (see Webhooks). invoice.paid also fires for OVERPAID invoices; the overpaid difference is held for the buyer to claim back (see Refunds).
Fulfil only from the webhook. A payment counts once it reaches the confirmation threshold of its network; see Confirmations.
5. Pay affiliates
Each affiliate's share sits in their partner balance. Read it with GET /api/v1/crypto/balances and send it to their wallet with a payout:
curl -X POST https://api.aliquot.cc/api/v1/crypto/payouts \
-H "Authorization: Bearer $ALIQUOT_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: payout-2026-11-aff-5550001" \
-d '{
"account": "aff-5550001",
"network": "BSC_TESTNET",
"token": "USDT",
"amount": "40.00",
"destination_address": "0x7a3B9c1D5e2F4a6B8c0D1e3F5a7B9c2D4e6F8a0B"
}'The key needs crypto-payouts:create, which only a user with two-factor authentication can grant. Each payout has a fee that comes out of amount, and a maximum per payout; both are in Payouts. You can also pay out from the dashboard (Payouts → New payout) with a code from your authenticator app.
Next
- Ledger and splits: markup, several partners on one invoice, and the ledger postings.
- Payment links: a fixed-price page you can pin in a channel, when you don't need per-member attribution.
- Webhooks: every event, retries and secret rotation.