# Telegram Bot Crypto Payments

> Take crypto payments in a Telegram bot for subscriptions or access.

Section: Build with AI
Source: https://coincircuit.io/docs/guides/telegram-subscription-bot/
Interactive version: https://coincircuit.io/api-reference?tab=guides&guide=telegram-subscription-bot

Tags: Telegram, Payments, Webhooks, Node.js

Paste this prompt into Claude, ChatGPT, or any AI tool. It works best with the CoinCircuit MCP server connected: https://mcp.coincircuit.io

---

You are helping me integrate CoinCircuit crypto payments into my existing Telegram bot. I have the CoinCircuit MCP server connected.

**If you have access to the CoinCircuit MCP server, call these tools for the most accurate and detailed schema outputs:**
- Call `get_api_overview` in the CoinCircuit MCP for base URLs, auth method, and available features.
- Call `get_endpoint` with method `post` and path `/api/v1/payments` for the full payment session creation schema.
- Call `search_api` with query `webhook` and type `schemas` to list all webhook payload schemas.
- Call `get_schema` with name `PaymentCompletedWebhookDto` for the exact payment.completed webhook payload.
- Call `get_schema` with name `TransactionReceivedWebhookDto` for the transaction.received webhook payload.

Use the live MCP data as your source of truth. The details below are a guide, but if the MCP returns something different, trust the MCP.

## API Basics

- **Base URL (production):** `https://api.coincircuit.io`
- **Base URL (sandbox):** `https://sandbox-api.coincircuit.io`
- **Auth:** Pass your API key in the `x-api-key` header on every request.

## Project Context

I have an existing Telegram bot and I want to add crypto payment support using CoinCircuit. The integration should:

1. Create a CoinCircuit payment session when a user wants to pay
2. Send the hosted checkout URL to the user in chat
3. Listen for payment confirmation via webhook
4. Trigger the appropriate action in my bot (grant access, deliver content, activate subscription, etc.)

This pattern works for any Telegram bot use case: subscription access, one-time purchases, premium features, tip jars, or pay-per-use commands.

## What I Need You to Implement

### 1. Create a payment session from a bot command

When a user triggers a payment (e.g. via a command or button callback), create a CoinCircuit payment session from your bot's backend:

**Endpoint:** `POST /api/v1/payments`
*(Call `get_endpoint` with method `post`, path `/api/v1/payments`, section `request` in the CoinCircuit MCP for the exact request body schema.)*

**Required fields:**
- `title` (string) - e.g. "Premium Channel - 30 Days"
- `description` (string) - e.g. "Subscription payment for premium access"
- `amount` (string) - subscription price as a string, e.g. `"9.99"`
- `currency` (string) - `"USD"` or `"NGN"`
- `customer` (object) - must include `email` (required). Include `telegramId` for linking.

**Optional fields:**
- `metadata` (object) - store `telegramUserId`, `telegramUsername`, `plan`, `channelId`, `subscriptionPeriodEnd` for webhook reconciliation
- `successUrl` (string) - redirect after payment (HTTPS)
- `cancelUrl` (string) - redirect if cancelled
- `webhookUrl` (string) - per-session webhook URL override (HTTPS)
- `asset` (string) - lock to a specific crypto: `"BTC"`, `"ETH"`, `"USDT"`, `"USDC"`, `"SOL"`, `"BNB"`, `"TRX"`
- `chain` (string) - lock to a specific blockchain: `"bitcoin"`, `"ethereum"`, `"solana"`, `"bsc"`, `"tron"`, `"base"`, `"arbitrum"`

**Example request body:**
```json
{
  "title": "Premium Channel - 30 Days",
  "description": "Subscription payment for premium Telegram access",
  "amount": "9.99",
  "currency": "USD",
  "customer": {
    "email": "user@example.com",
    "telegramId": "123456789"
  },
  "metadata": {
    "telegramUserId": "123456789",
    "telegramUsername": "johndoe",
    "plan": "premium-monthly",
    "channelId": "-1001234567890",
    "subscriptionPeriodEnd": "2026-04-30T23:59:59.000Z"
  },
  "successUrl": "https://mybot.com/subscription/success"
}
```

**Response (201):** Returns a session object. Key fields:
- `data.reference` - session reference (store this alongside the subscription)
- `data.url` - hosted checkout page URL. **Send this to the user via Telegram.**
- `data.payment.status` - starts as `"pending"`
- `data.expiresAt` - session expiration timestamp

*(Call `get_endpoint` with method `post`, path `/api/v1/payments`, section `success` in the CoinCircuit MCP for the full response schema.)*

### 2. Send checkout link to the user

After creating the session, send the `data.url` to the user in chat. The hosted checkout page handles crypto selection, address display, and payment detection automatically. No additional frontend work needed.

### 3. Webhook handler: process payment confirmation

Set up an endpoint to receive CoinCircuit webhooks. This is where your bot takes action after payment.

*(Call `get_schema` with name `PaymentCompletedWebhookDto` in the CoinCircuit MCP for the full payload.)*

**Payment events** (envelope: `{ event: string, data: { session: PaymentSession } }`):
- `payment.completed` - full payment confirmed. **This is your trigger to take action in your bot.**
  - Read `data.session.metadata.telegramUserId` to identify the user
  - Read `data.session.metadata` for any custom data you stored (plan, product, channel ID, etc.)
  - Execute your bot's logic: grant access, send a file, activate a feature, update a subscription, etc.
- `payment.expired` - session expired before payment. Optionally notify the user and offer a new session.
- `payment.partial` - customer sent crypto but not enough. The session stays open for more payments.
- `payment.underpaid` - session closed with less than the required amount. Check `data.session.payment.amountReceived` vs `data.session.payment.amount`. Handle accordingly (refund, manual review, etc.).

**Transaction events:**
- `transaction.received` - payment detected on-chain but unconfirmed. Optionally notify the user that payment was detected.
- `transaction.confirmed` - payment confirmed on the blockchain.

**Webhook security:**
- Verify the HMAC-SHA256 signature in the `x-coincircuit-signature` header using your webhook secret
- Use the `x-coincircuit-delivery-id` header for idempotency (store processed delivery IDs and skip duplicates)

### 4. Track payment state

Store a record linking the CoinCircuit session to your bot's user:
- `telegramUserId`
- `sessionReference` - the CoinCircuit payment session reference
- `status` (`"pending"`, `"completed"`, `"expired"`)
- Any use-case-specific fields (subscription expiry, product ID, etc.)

This lets you look up payment status when a user asks, and lets your webhook handler find the right user to notify.

### 5. Recurring payments (if applicable)

For subscription-based flows, create a new payment session each billing cycle:

1. **Before expiry:** Send the user a renewal payment link
2. **On expiry:** If not renewed, revoke access or downgrade
3. **On renewal payment:** Update the subscription period

Store the `subscriptionPeriodEnd` in session metadata so your webhook handler knows the new expiry.

## Constraints

- Session `amount` is a **string** in fiat, not a number (e.g. `"9.99"`)
- Store the `telegramUserId` in both the session `metadata` and `customer.telegramId` for reconciliation
- Always verify webhook signatures before taking action
- Only act on `payment.completed`, not on partial or pending events
- `successUrl` and `cancelUrl` must be HTTPS
- Supported currencies: NGN, USD. Supported assets: BTC, ETH, USDT, USDC, SOL, BNB, TRX. Supported chains: bitcoin, ethereum, solana, bsc, tron, base, arbitrum.
