Learn how to generate dynamic UPI QR codes and send them directly as photo messages inside Telegram chats. Customers scan the QR or tap deep links, and your bot automatically fulfills the order upon payment credit.
If you are building your Telegram bot in Python, we strongly recommend using pip install famgateway instead of writing raw cURL requests. The official SDK has built-in connection management, automatic retry backoffs, and strongly-typed objects. Simply provide your API key and bot token, and all order creation, QR rendering, and verification calls work out of the box.
To prevent transaction collisions on bank IMAP credit listeners, FamGateway enforces a strict 3-second spacing policy per merchant API key. If your bot sends multiple order creation requests faster than 3 seconds, an automatic 5-second merchant protection lock is triggered (returning HTTP 429). When using the official Python SDK (pip install famgateway), internal throttling and retry handling ensure you never hit this lock. If you are writing custom HTTP requests in Node.js or PHP, ensure your bot queues order requests with at least a 3-second interval per merchant key.
Zero Customer Input Required: You do not need to ask buyers for their full name, email, or phone number before generating a payment order. FamGateway's automated IMAP verification engine automatically extracts the payer's official banking name and transaction reference directly from the incoming FamPay/bank credit receipt email.
The only mandatory field to create an order is amount. If you want to attach custom user identifiers for tracking in your dashboard, you can optionally pass parameters like customer_name:
| Parameter | Type | Requirement | Description & Behavior |
|---|---|---|---|
| amount | float | Required | The billing amount in INR (e.g. 50.00). This is the only mandatory field. |
| customer_name | string | Optional | Optional. FamGateway automatically extracts the payer's verified banking name from the bank receipt. You can optionally pass the buyer's Telegram user handle or chat ID (e.g. Aryan (ID: 102938475)) if you want custom account tagging in your merchant dashboard. |
| customer_email | string | Optional | Optional. Buyer's email address if you want FamGateway to dispatch automated payment receipt emails. |
| customer_phone | string | Optional | Optional. 10-digit mobile number for merchant bookkeeping. |
| redirect_url | string | Optional | Optional. Web URL where users are redirected if they open the fallback hosted checkout page. |
| webhook_url | string | Optional | Optional. Per-order webhook callback endpoint to override your account's global webhook setting. |
Attributes Returned in Response: FamGateway returns order_id (unique transaction key), payable_amount (clean exact amount in INR matching requested base amount with zero decimal alterations or fractional paise offsets), qr_url (direct hosted image ready to pass to Telegram's sendPhoto), and upi_intent (deep link string for mobile UPI app buttons).
Install the official FamGateway Python SDK and pyTelegramBotAPI:
pip install famgateway pyTelegramBotAPI
Here is a complete, production-ready bot script. When a user runs /buy, the bot creates an order, sends the dynamic QR image directly into the chat, attaches UPI intent buttons, and verifies payment on status check:
import telebot
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton
from famgateway import FamGateway, FamGatewayError
# 1. Initialize Bot & FamGateway Client
BOT_TOKEN = "YOUR_TELEGRAM_BOT_TOKEN"
FAMGATEWAY_API_KEY = "YOUR_FAMGATEWAY_API_KEY"
bot = telebot.TeleBot(BOT_TOKEN)
fg = FamGateway(api_key=FAMGATEWAY_API_KEY)
@bot.message_handler(commands=['start'])
def handle_start(message):
bot.reply_to(
message,
"Welcome! Send /buy to purchase premium VIP membership for INR 50."
)
@bot.message_handler(commands=['buy'])
def handle_buy(message):
user_id = message.from_user.id
user_name = message.from_user.first_name or "User"
bot.send_message(message.chat.id, "Generating your dynamic UPI QR code...")
try:
# 2. Call FamGateway SDK to create order
# Note: 'amount' is the only mandatory field. 'customer_name' is optional
# because FamGateway extracts the buyer's real bank name from email receipts automatically.
order = fg.create_order(
amount=50.00,
customer_name=f"{user_name} ({user_id})" # Optional custom tracking tag
)
caption_text = (
f"<b>Order Created:</b> <code>{order.order_id}</code>\n"
f"<b>Amount to Pay:</b> <code>INR {order.payable_amount}</code>\n\n"
f"Scan the QR code above with any UPI app (PhonePe, GPay, Paytm) or tap the button below:"
)
# 3. Create inline buttons for UPI App and Status Check
markup = InlineKeyboardMarkup()
markup.row(
InlineKeyboardButton("Pay via UPI App", url=order.upi_intent),
InlineKeyboardButton("Web Page", url=order.checkout_url)
)
markup.row(
InlineKeyboardButton("Check Status", callback_data=f"check_{order.order_id}")
)
# 4. SEND DIRECT QR IMAGE IN CHAT (Zero Browser Redirect!)
bot.send_photo(
chat_id=message.chat.id,
photo=order.qr_url,
caption=caption_text,
parse_mode="HTML",
reply_markup=markup
)
except FamGatewayError as e:
bot.send_message(message.chat.id, f"Error generating payment: {str(e)}")
@bot.callback_query_handler(func=lambda call: call.data.startswith("check_"))
def handle_status_check(call):
order_id = call.data.replace("check_", "")
try:
# Check payment status via FamGateway API
status = fg.get_order_status(order_id)
if status.is_paid:
bot.answer_callback_query(call.id, "Payment Verified! Thank you.")
bot.send_message(
call.message.chat.id,
f"Payment Successful!\n\n"
f"Order: {order_id}\n"
f"Amount: INR {status.amount}\n"
f"UTR: {status.utr}\n\n"
f"Your VIP access has been unlocked."
)
else:
bot.answer_callback_query(
call.id,
"Payment not detected yet. Please ensure you completed the transaction in your UPI app.",
show_alert=True
)
except FamGatewayError as e:
bot.answer_callback_query(call.id, f"Status check error: {str(e)}", show_alert=True)
if __name__ == '__main__':
print("Telegram bot is running...")
bot.infinity_polling()
For Node.js bots using telegraf, make a standard POST request with your API Key in the X-Api-Key header. Note: ensure your bot logic does not send rapid bursts faster than 3 seconds per merchant account:
const { Telegraf, Markup } = require('telegraf');
const axios = require('axios');
const bot = new Telegraf('YOUR_TELEGRAM_BOT_TOKEN');
const FAMGATEWAY_API_KEY = 'YOUR_FAMGATEWAY_API_KEY';
bot.command('buy', async (ctx) => {
await ctx.reply('Generating your UPI QR code...');
try {
// 1. Create order via FamGateway REST API (amount is required; customer_name is optional)
const response = await axios.post('https://famgateway.in/api/create-order.php', {
amount: 50.00,
customer_name: `${ctx.from.first_name} (${ctx.from.id})` // Optional tracking tag
}, {
headers: {
'Content-Type': 'application/json',
'X-Api-Key': FAMGATEWAY_API_KEY
}
});
const { order_id, payable_amount, qr_url, upi_intent } = response.data.data;
// 2. Send QR Photo directly in chat
await ctx.replyWithPhoto(qr_url, {
caption: `<b>Pay INR ${payable_amount} via UPI</b>\nOrder ID: <code>${order_id}</code>`,
parse_mode: 'HTML',
...Markup.inlineKeyboard([
[Markup.button.url('Open UPI App', upi_intent)],
[Markup.button.callback('Check Status', `check_${order_id}`)]
])
});
} catch (err) {
const errorMsg = err.response?.data?.message || 'Failed to create payment order.';
ctx.reply(`Error: ${errorMsg}`);
}
});
// Handle Status Check Callback
bot.action(/check_(.+)/, async (ctx) => {
const orderId = ctx.match[1];
try {
const res = await axios.get(`https://famgateway.in/api/verify-order.php?order_id=${orderId}&api_key=${FAMGATEWAY_API_KEY}`);
if (res.data.status === 'success' && res.data.data.is_paid) {
await ctx.answerCbQuery('Payment verified successfully!');
await ctx.reply(`Payment Confirmed for Order: ${orderId}. Bank UTR: ${res.data.data.utr}`);
} else {
await ctx.answerCbQuery('Payment not received yet. Please try after completing UPI payment.', { show_alert: true });
}
} catch (e) {
await ctx.answerCbQuery('Could not verify status. Try again shortly.', { show_alert: true });
}
});
bot.launch();
If you host your Telegram bot on a standard PHP web server or cPanel hosting, you can handle incoming Telegram updates via Webhook and call FamGateway using native cURL:
<?php
// Telegram Webhook Handler in PHP
$botToken = "YOUR_TELEGRAM_BOT_TOKEN";
$apiKey = "YOUR_FAMGATEWAY_API_KEY";
$content = file_get_contents("php://input");
$update = json_decode($content, true);
if (!$update) {
exit('No input');
}
$chatId = $update['message']['chat']['id'] ?? ($update['callback_query']['message']['chat']['id'] ?? null);
$text = $update['message']['text'] ?? '';
$callData = $update['callback_query']['data'] ?? '';
// Helper to make Telegram API requests
function tgRequest($method, $data, $botToken) {
$url = "https://api.telegram.org/bot{$botToken}/{$method}";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$res = curl_exec($ch);
curl_close($ch);
return json_decode($res, true);
}
// 1. Handle /buy Command
if ($text === '/buy') {
$userName = $update['message']['from']['first_name'] ?? 'User';
// Call FamGateway create-order API (amount is required; customer_name is optional)
$payload = json_encode([
'amount' => 50.00,
'customer_name' => "{$userName} ({$chatId})" // Optional custom tracking tag
]);
$ch = curl_init('https://famgateway.in/api/create-order.php');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'X-Api-Key: ' . $apiKey
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$apiRes = curl_exec($ch);
curl_close($ch);
$orderData = json_decode($apiRes, true);
if (isset($orderData['status']) && $orderData['status'] === 'success') {
$order = $orderData['data'];
$keyboard = json_encode([
'inline_keyboard' => [
[['text' => 'Pay via UPI App', 'url' => $order['upi_intent']]],
[['text' => 'Check Status', 'callback_data' => 'chk_' . $order['order_id']]]
]
]);
// Send QR Image directly into Telegram chat
tgRequest('sendPhoto', [
'chat_id' => $chatId,
'photo' => $order['qr_url'],
'caption' => "Pay INR {$order['payable_amount']} via UPI\nOrder: {$order['order_id']}",
'reply_markup' => $keyboard
], $botToken);
} else {
tgRequest('sendMessage', [
'chat_id' => $chatId,
'text' => 'Error generating payment order. Please try again shortly.'
], $botToken);
}
}
// 2. Handle Check Status Callback
if (strpos($callData, 'chk_') === 0) {
$orderId = substr($callData, 4);
$queryUrl = "https://famgateway.in/api/verify-order.php?order_id={$orderId}&api_key={$apiKey}";
$chkRes = json_decode(file_get_contents($queryUrl), true);
$callId = $update['callback_query']['id'];
if (isset($chkRes['data']['is_paid']) && $chkRes['data']['is_paid'] === true) {
tgRequest('answerCallbackQuery', ['callback_query_id' => $callId, 'text' => 'Payment Confirmed!'], $botToken);
tgRequest('sendMessage', [
'chat_id' => $chatId,
'text' => "Payment Successful! Order {$orderId} verified. Thank you."
], $botToken);
} else {
tgRequest('answerCallbackQuery', [
'callback_query_id' => $callId,
'text' => 'Payment not detected yet. Please ensure payment is completed.',
'show_alert' => true
], $botToken);
}
}
customer_name: "Aryan (738234312)") so you can easily trace orders back to Telegram accounts.