Merchant API v1

Приём криптоплатежей через GramPay

REST API для выставления счетов в долларах и приёма оплаты в Gram (GRAM, бывший Toncoin) и USDT. Клиент выбирает удобную сеть, GramPay сам находит перевод в блокчейне и отправляет вашему серверу подписанный вебхук.

Базовый URLhttps://grampay.top/api/v1
Форматapplication/json
КодировкаUTF-8

Авторизация

Зарегистрируйтесь и создайте ключ в кабинете: Разработчикам → API-ключи. Ключ показывается один раз — храните его на сервере и никогда не передавайте в браузер.

Передавайте ключ в заголовке Authorization или X-API-Key:

Authorization: Bearer gp_live_XXXXXXXXXXXXXXXXXXXXXXXX

Как проходит оплата

  1. Создайте счёт через POST /invoices с суммой в USD.
  2. Перенаправьте клиента на pay_url из ответа или встройте страницу в iframe.
  3. Клиент платит в выбранной сети. Курс GRAM фиксируется на время жизни счёта.
  4. Получите вебхук invoice.paid и выдайте товар. Статус можно также проверить через GET /invoices/{id}.

POST /invoices

Создаёт счёт. Все поля, кроме amount, необязательны.

ПолеТипОписание
amount обяз.numberСумма в USD, от 0.5 до 1 000 000
descriptionstringОписание для клиента, до 500 символов
order_idstringВаш номер заказа, до 120 символов
callback_urlstringURL для вебхуков по этому счёту
success_urlstringКуда вернуть клиента после оплаты
ttl_minutesintegerВремя на оплату: от 5 до 10080 минут (по умолчанию — из настроек)
methodsstring[]Ограничить способы оплаты, например ["usdt_ton","usdt_trc20"]
metadataobjectПроизвольные данные до 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АктивСетьКак опознаётся платёж
tonGRAMTONпо комментарию с кодом счёта
usdt_tonUSDTTON (jetton)по комментарию с кодом счёта
usdt_trc20USDTTron TRC-20по уникальной сумме
usdt_bep20USDTBNB Chain BEP-20по уникальной сумме
usdt_erc20USDTEthereum ERC-20по уникальной сумме
usdt_polygonUSDTPolygonпо уникальной сумме
usdt_arbitrumUSDTArbitrum 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Временная ошибка — повторите запрос позже