Приём криптоплатежей через GramPay
REST API для выставления счетов в долларах и приёма оплаты в Gram (GRAM, бывший Toncoin) и USDT. Клиент выбирает удобную сеть, GramPay сам находит перевод в блокчейне и отправляет вашему серверу подписанный вебхук.
https://grampay.top/api/v1application/jsonUTF-8Авторизация
Зарегистрируйтесь и создайте ключ в кабинете: Разработчикам → API-ключи. Ключ показывается один раз — храните его на сервере и никогда не передавайте в браузер.
Передавайте ключ в заголовке Authorization или X-API-Key:
Authorization: Bearer gp_live_XXXXXXXXXXXXXXXXXXXXXXXX
Как проходит оплата
- Создайте счёт через
POST /invoicesс суммой в USD. - Перенаправьте клиента на
pay_urlиз ответа или встройте страницу в iframe. - Клиент платит в выбранной сети. Курс GRAM фиксируется на время жизни счёта.
- Получите вебхук
invoice.paidи выдайте товар. Статус можно также проверить черезGET /invoices/{id}.
POST /invoices
Создаёт счёт. Все поля, кроме amount, необязательны.
| Поле | Тип | Описание |
|---|---|---|
amount обяз. | number | Сумма в USD, от 0.5 до 1 000 000 |
description | string | Описание для клиента, до 500 символов |
order_id | string | Ваш номер заказа, до 120 символов |
callback_url | string | URL для вебхуков по этому счёту |
success_url | string | Куда вернуть клиента после оплаты |
ttl_minutes | integer | Время на оплату: от 5 до 10080 минут (по умолчанию — из настроек) |
methods | string[] | Ограничить способы оплаты, например ["usdt_ton","usdt_trc20"] |
metadata | object | Произвольные данные до 4 КБ, возвращаются в ответах |
curl -X POST https://grampay.top/api/v1/invoices \
-H "Authorization: Bearer $GRAMPAY_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 25.00,
"description": "Заказ #1042",
"order_id": "1042",
"callback_url": "https://shop.example/api/grampay",
"success_url": "https://shop.example/thanks"
}'GET /invoices/{id}
Возвращает объект счёта с актуальным статусом и списком поступлений.
curl https://grampay.top/api/v1/invoices/inv_uRofqKNn1Ybc \ -H "Authorization: Bearer $GRAMPAY_KEY"
GET /invoices
Список счетов, новые первыми. Параметры: status, limit (до 200, по умолчанию 50), offset.
{ "total": 128, "items": [ { "id": "inv_…", "status": "paid", … } ] }POST /invoices/{id}/cancel
Отменяет счёт в статусе pending или underpaid. Если по счёту задан callback_url, придёт вебхук invoice.cancelled.
GET /balance
Баланс вашего аккаунта: оплаты в GRAM копятся в GRAM, оплаты USDT из любой сети — в USDT. Вывод — в кабинете, раздел Баланс.
{ "GRAM": 12.5, "USDT": 340.75 }Объект счёта
{
"id": "inv_uRofqKNn1Ybc",
"code": "GPVXYLFF", // код оплаты (комментарий для сетей TON)
"status": "paid",
"amount_usd": 25.0,
"received_usd": 25.0,
"description": "Заказ #1042",
"order_id": "1042",
"created_at": "2026-09-27T14:58:03+00:00",
"expires_at": "2026-09-27T15:28:03+00:00",
"paid_at": "2026-09-27T15:02:41+00:00",
"paid_method": "usdt_ton",
"rate_ton": 1.5886, // курс GRAM/USD, зафиксированный в счёте
"pay_url": "https://grampay.top/pay/inv_uRofqKNn1Ybc",
"success_url": "https://shop.example/thanks",
"callback_url": "https://shop.example/api/grampay",
"metadata": null,
"methods": [
{
"id": "usdt_ton", "asset": "USDT", "network": "ton", "network_label": "TON",
"amount": "25", "amount_units": "25000000",
"address": "UQBVJBdAXQ7dh1x…", "memo": "GPVXYLFF",
"deeplink": "ton://transfer/UQBV…?jetton=EQCx…&amount=25000000&text=GPVXYLFF"
}
],
"payments": [
{
"method": "usdt_ton", "amount": 25.0, "usd_value": 25.0,
"tx_hash": "…", "explorer": "https://tonviewer.com/transaction/…",
"block_time": "2026-09-27T15:02:35+00:00"
}
]
}Статусы
| pending | Ожидает оплаты |
| underpaid | Получена часть суммы. Клиент может доплатить до истечения срока |
| paid | Оплачен полностью (допуск 0.5% на округление). Финальный статус |
| expired | Срок оплаты истёк. Если перевод всё же придёт позже, счёт станет paid |
| cancelled | Отменён продавцом |
GET /methods
Способы оплаты, которые сейчас включены в магазине.
| id | Актив | Сеть | Как опознаётся платёж |
|---|---|---|---|
ton | GRAM | TON | по комментарию с кодом счёта |
usdt_ton | USDT | TON (jetton) | по комментарию с кодом счёта |
usdt_trc20 | USDT | Tron TRC-20 | по уникальной сумме |
usdt_bep20 | USDT | BNB Chain BEP-20 | по уникальной сумме |
usdt_erc20 | USDT | Ethereum ERC-20 | по уникальной сумме |
usdt_polygon | USDT | Polygon | по уникальной сумме |
usdt_arbitrum | USDT | Arbitrum One | по уникальной сумме |
Для сетей без комментариев к сумме добавляются доли цента (например, 25.0037 USDT), чтобы однозначно связать перевод со счётом.
GET /rates
Текущий курс — медиана котировок нескольких бирж.
{ "GRAM_USD": 1.5886, "TON_USD": 1.5886, "USDT_USD": 1.0, "updated_at": "2026-09-27T15:04:56+00:00" }Вебхуки
При смене статуса счёта GramPay отправляет POST на callback_url. События: invoice.paid, invoice.underpaid, invoice.expired, invoice.cancelled.
POST /api/grampay HTTP/1.1
Content-Type: application/json
User-Agent: GramPay-Webhooks/1.0
X-GramPay-Event: invoice.paid
X-GramPay-Timestamp: 1790521361
X-GramPay-Signature: 5f2b0c…e91a
{
"event": "invoice.paid",
"invoice": { "id": "inv_…", "status": "paid", "order_id": "1042", … },
"sent_at": "2026-09-27T15:02:41+00:00"
}Ответьте кодом 2xx в течение 15 секунд. Иначе доставка повторится через 1, 5, 30 минут, 2 и 6 часов. Обработчик должен быть идемпотентным: одно событие может прийти несколько раз.
Проверка подписи
Подпись — HMAC-SHA256 в hex от строки {timestamp}.{сырое тело запроса}. Секрет находится в кабинете: Разработчикам → Подпись вебхуков. Отклоняйте запросы старше 5 минут.
import hashlib, hmac, time
def verify(body: bytes, headers, secret: str) -> bool:
ts = headers["X-GramPay-Timestamp"]
sig = headers["X-GramPay-Signature"]
if abs(time.time() - int(ts)) > 300:
return False
expected = hmac.new(secret.encode(), f"{ts}.".encode() + body,
hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, sig)Встраивание
Страницу оплаты можно открыть в новой вкладке, в Telegram WebApp или встроить на сайт:
<iframe src="https://grampay.top/pay/inv_uRofqKNn1Ybc"
width="480" height="760" style="border:0;border-radius:24px"></iframe>Ошибки
Ошибки возвращаются с HTTP-кодом 4xx/5xx и телом {"error": "описание"}.
400 | Некорректные параметры (например, сумма вне диапазона или нет доступных способов оплаты) |
401 | Неверный или отозванный API-ключ |
404 | Счёт не найден |
422 | Ошибка валидации JSON |
5xx | Временная ошибка — повторите запрос позже |