# Telegram communities with affiliates
URL: https://aliquot.cc/docs/payments/telegram

> 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.

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](https://core.telegram.org/bots/api), so it works with any bot library. You need an Aliquot API key (see [Quickstart](/docs/payments/quickstart)), a bot token from [@BotFather](https://t.me/BotFather), and the bot added as an administrator of the private channel or group, with the right to invite users.

## How the money splits [#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](/docs/payments/ledger-and-splits#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](/docs/payments/ledger-and-splits#the-fee-waterfall).

## 1. Give each affiliate a partner account and a link [#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:

```bash
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 [#2-create-the-invoice-with-the-affiliates-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.

```js
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 `splits` out: your `platform` account keeps the whole net.
* An unknown account reference in `splits` is a `422` on that field. Create the partner account first.
* Live is the same request on `BSC_MAINNET` with a Live key. See [Networks and tokens](/docs/payments#networks-and-tokens) for every pair.

## 3. Open the checkout as a Mini-App [#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.

```js
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.

<Callout>
  The Mini-App shows the buyer's Telegram name only when it can verify the signed session; otherwise it shows "Telegram session not verified". The payment works the same either way. Identify the buyer by your 

  `merchant_order_id`

  , never by what the page displays.
</Callout>

## 4. Send the invite when `invoice.paid` arrives [#4-send-the-invite-when-invoicepaid-arrives]

Subscribe an endpoint to `invoice.paid` (**Developers → Webhooks**) and verify the signature exactly as in the [Quickstart receiver](/docs/payments/quickstart#4-receive-invoicepaid). Then read the Telegram user ID back from `merchant_order_id` and create a single-use invite link:

```js
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](/docs/payments/webhooks)). `invoice.paid` also fires for `OVERPAID` invoices; the overpaid difference is held for the buyer to claim back (see [Refunds](/docs/payments/refunds)).

Fulfil only from the webhook. A payment counts once it reaches the confirmation threshold of its network; see [Confirmations](/docs/payments/confirmations).

## 5. Pay affiliates [#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:

```bash
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](/docs/payments/payouts#amount-and-fee). You can also pay out from the dashboard (**Payouts → New payout**) with a code from your authenticator app.

## Next [#next]

* [Ledger and splits](/docs/payments/ledger-and-splits): markup, several partners on one invoice, and the ledger postings.
* [Payment links](/docs/payments/payment-links): a fixed-price page you can pin in a channel, when you don't need per-member attribution.
* [Webhooks](/docs/payments/webhooks): every event, retries and secret rotation.
