К содержимому
Разработчикам

Интеграция за считаные минуты

Один PHP-SDK без зависимостей: создать счёт, отправить на готовый чек-аут и проверить подпись вебхука. Для любого другого языка есть REST.

API коротко
  • Базовый адресapi.payora.money
  • АутентификацияHMAC-SHA256
  • ФорматJSON · HTTPS
  • SDKPHP · Node.js · Python
  • СпецификацияOpenAPI 3.0
быстрый старт

От счёта до вебхука

  1. 01

    Создайте счёт

    Один вызов API с номером заказа и суммой в фиате или крипте возвращает ссылку на оплату.

  2. 02

    Клиент платит

    Он выбирает монету, сканирует QR или открывает кошелёк — оплата подтверждается вживую по финализации.

  3. 03

    Вы получаете подписанный вебхук

    Проверьте подпись HMAC, зачтите заказ один раз — и платёж уже на вашем балансе.

PHP-SDK

Один файл, без зависимостей. createInvoice(), getInvoice() и verifyWebhook() — кладётся в любой проект.

Аутентификация HMAC

Запросы и вебхуки подписаны HMAC-SHA256 с допуском по времени и ключами идемпотентности.

REST API

Обычный JSON поверх HTTPS — интеграция с любого стека, не только с PHP.

checkout
<?php
require 'Payora.php';
$payora = new Payora('https://api.payora.money', getenv('PAYORA_KEY'), getenv('PAYORA_SECRET'));

// 1 — create an invoice (fiat-priced; the payer picks a coin)
$inv = $payora->createInvoice([
  'order_id'   => 'ORDER-42',
  'mode'       => 'fiat',
  'amount'     => '9.99',
  'return_url' => 'https://shop.example/thanks',
  'lang'       => 'en',
], 'ORDER-42'); // Idempotency-Key: a retry never creates a second invoice
header('Location: ' . $inv['pay_url']);

// 2 — webhook endpoint: ALWAYS verify the signature first
$event = $payora->verifyWebhook(file_get_contents('php://input'), getallheaders());
if ($event === null) { http_response_code(400); exit; }
if ($event['status'] === 'paid') {
  creditOrderOnce($event['id'], $event['order_id'], $event['amount'], $event['currency']);
}
http_response_code(200); // 2xx stops retries

Получите свой API key и secret, создав аккаунт. Полный SDK — в вашей панели.

аутентификация

Аутентификация

Каждый вызов, кроме /v1/health, несёт три подписанных заголовка. Подпись доказывает, что запрос отправил владелец вашего api_secret и по дороге его не изменили.

ЗаголовокЗначениеОписание
X-Payora-Keypk_…Ваш публичный api_key. Определяет магазин.
X-Payora-Timestampunix secondsМомент подписи запроса, в секундах Unix.
X-Payora-Signaturehex · 64HMAC-SHA256 от timestamp + "." + сырое тело на ключе api_secret, строчным hex.
X-Payora-Test1Помечает счёт как проверку интеграции: счёт настоящий и может принять монеты, но в показатели спроса и конверсии не идёт.
Idempotency-KeystringНеобязателен для POST /v1/invoice и POST /v1/payout. Повтор с тем же ключом возвращает первый результат вместо дубликата; тот же ключ с другим телом получает 409.
Content-Typeapplication/jsonОбязателен для запросов с телом.
X-Payora-Signature=hex( HMAC-SHA256( api_secret, timestamp + "." + raw_body ) )

Подписывайте ровно те байты, которые отправляете. Повторная сборка JSON после подписи — даже другой порядок ключей или лишний пробел — ломает подпись.

У GET-запроса тело пустое, поэтому подписывается timestamp с точкой в конце.

API отклоняет timestamp, который расходится с его часами больше чем на 120 секунд. Синхронизируйте время сервера по NTP.

Храните api_secret только на сервере. Им подписываются и запросы, и вебхуки: у кого он есть, тот может создавать счета от вашего имени и подделывать уведомления.

sign-request
<?php
$body = json_encode(['order_id' => 'ORDER-42', 'mode' => 'fiat', 'amount' => '9.99'], JSON_UNESCAPED_SLASHES);
$ts   = (string) time();
$sig  = hash_hmac('sha256', $ts . '.' . $body, $apiSecret); // lowercase hex

$ch = curl_init('https://api.payora.money/v1/invoice');
curl_setopt_array($ch, [
  CURLOPT_POST => true, CURLOPT_POSTFIELDS => $body, CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'X-Payora-Key: ' . $apiKey,
    'X-Payora-Timestamp: ' . $ts,
    'X-Payora-Signature: ' . $sig,
    'Idempotency-Key: ORDER-42',
    'Content-Type: application/json',
  ],
]);
$invoice = json_decode(curl_exec($ch), true);
POST /v1/invoice

Параметры счёта

Всё необязательно, кроме order_id и amount. В режиме fiat плательщик может выбрать любую монету, включённую в вашем аккаунте; режиму crypto также нужен currency.

ПараметрТипОписание
order_idstring · requiredВаш уникальный идентификатор заказа (≤190 символов). Повтор отклоняется с 409 — защита от двойной отправки.
amountstring · requiredСумма в фиате (mode=fiat) или точная сумма в крипте (mode=crypto).
modefiat | cryptoПо умолчанию fiat: курс фиксируется по каждой монете на checkout. crypto заранее фиксирует монету и сумму.
fiat_currencystringISO-код фиата для режима fiat (default USD).
currencystringМонета для режима crypto (например, TON, TRX, USDT_TRON).
return_urlhttps URLКуда кнопка «Вернуться в магазин» на checkout возвращает клиента — на ваш сайт. Только абсолютный http(s).
langen·ru·uk·es·deЯзык checkout, чтобы клиент из вашего российского магазина видел checkout на русском, а не на английском. Также задаётся как ?lang=ru в URL оплаты.
ttlsecondsСколько счёт остаётся доступным для оплаты (120–86400 секунд, по умолчанию 1800).
customer_emailemailНеобязательно — попадает в чек и отправляется плательщику по почте.
notesstringПроизвольная заметка, сохраняемая в счёте.

return_url и lang также работают как query-параметры, добавляемые к pay_url, который отдаёт API — <pay_url>&lang=ru&return_url=https://shop.example/thanks. Всегда отправляйте покупателя на pay_url, возвращённый API: он несёт одноразовый токен доступа к счёту, поэтому страницу checkout нельзя открыть, угадав номер счёта. Не собирайте ссылку заново из id счёта.

Конструктор запроса

Соберите подписанный запрос на счёт

Заполните поля и скопируйте готовую команду cURL. Она подписывается сама в вашей оболочке через $PAYORA_KEY и $PAYORA_SECRET — эта страница не видит ваших ключей и ничего не отправляет.

mode
POST /v1/invoice
BODY='{"order_id":"ORDER-42","mode":"fiat","amount":"9.99","fiat_currency":"USD","return_url":"https://shop.example/thanks","lang":"ru","ttl":1800}'
TS=$(date +%s)
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$PAYORA_SECRET" | cut -d' ' -f2)

curl -X POST https://api.payora.money/v1/invoice \
  -H "X-Payora-Key: $PAYORA_KEY" \
  -H "X-Payora-Timestamp: $TS" \
  -H "X-Payora-Signature: $SIG" \
  -H 'Idempotency-Key: ORDER-42' \
  -H 'Content-Type: application/json' \
  -d "$BODY"

С этой страницы ничего не отправляется.

вебхуки

Вебхуки

Когда счёт или выплата меняет состояние, Payora отправляет POST с подписанным JSON-событием на ваш адрес уведомлений. Сначала проверьте подпись, зачислите заказ один раз, ответьте 2xx.

СобытиеstatusКогда приходит
invoice.paidpaidПлатёж подтверждён в сети. Содержит сумму, монету и tx_hash.
invoice.underpaidunderpaidСрок счёта истёк, а пришло меньше ожидаемой суммы.
invoice.expiredexpiredСрок счёта истёк, оплаты не было.
invoice.cancelledcancelledСчёт отменён. Если деньги уже пришли, это описано в событии.
invoice.cancel_settled—С деньгами, пришедшими на отменённый счёт, всё решено: зачислены или возвращены.
invoice.late_payment—Деньги пришли на счёт уже после его отмены. Отправляется на каждое такое поступление; в result — зачислены они или возвращаются.
payout.sentsentПакет выплат подписан и отправлен в сеть. Содержит каждую выплату с её tx_hash.

Заголовки каждой доставки

ЗаголовокЗначениеОписание
X-Payora-IduuidУникальный id события, тот же, что id в теле. Сохраняйте его, чтобы пропускать повторы.
X-Payora-Eventinvoice.paidНазвание события.
X-Payora-Timestampunix secondsКогда подписана эта попытка.
X-Payora-Signaturehex · 64Та же схема, что у запросов: HMAC-SHA256 от timestamp + "." + сырое тело на ключе api_secret.

Тело invoice.paid

ПолеТипОписание
iduuidId события для защиты от повторов.
eventstringНазвание события.
invoice_idintНомер счёта в Payora.
order_idstringВаш номер заказа, как он был передан при создании счёта.
statusstringpaid для invoice.paid.
currencystringМонета, которой заплатили, например USDT_TRON.
amountdecimal stringПолученная сумма.
amount_unitsinteger stringТа же сумма в наименьших единицах монеты — для точных сравнений.
expecteddecimal stringСумма, выставленная в счёте.
fiat_amountdecimal string | nullЦена счёта в фиате, как вы её выставили; null у счетов в крипто-режиме.
fiat_currencystring | nullISO-код валюты fiat_amount; null у счетов в крипто-режиме.
tx_hashstringХеш транзакции в сети.
paid_atunix secondsКогда создано событие.
testbooltrue для тестовых счетов.
invoice.paid
{
    "id": "6f1c2a4e-8b0d-4c1e-9a57-2f3d9e1b7c40",
    "event": "invoice.paid",
    "invoice_id": 1042,
    "order_id": "ORDER-42",
    "status": "paid",
    "currency": "USDT_TRON",
    "amount": "9.99",
    "amount_units": "9990000",
    "expected": "9.99",
    "fiat_amount": "9.99",
    "fiat_currency": "USD",
    "tx_hash": "3f9a…c21e",
    "paid_at": 1758038400,
    "test": false
}

Если полученная сумма отличается от суммы счёта, добавляются amount_received и amount_expected.

Доставка и повторы

Любой ответ, кроме 2xx, или отсутствие ответа за 15 секунд — повтор с экспоненциальной паузой, не больше часа между попытками, всего до 12 попыток. Каждая попытка подписывается заново с новым timestamp; тело и id события не меняются, поэтому отсекайте повторы по id.

После последней попытки событие помечается неудавшимся, а владелец магазина получает письмо. Перенаправления не выполняются, а адрес уведомлений должен быть доступен из интернета — без localhost и частных адресов.

Прежде чем зачислить заказ

  • Читайте сырое тело до любого разбора JSON.
  • Пересчитайте подпись и сравните за постоянное время: hash_equals, crypto.timingSafeEqual, hmac.compare_digest.
  • Отклоняйте timestamp вне своего окна — SDK принимают ±300 секунд.
  • Сверьте статус и сумму с заказом, затем зачисляйте один раз на id события.
  • Отвечайте 2xx быстро, а долгую работу делайте после ответа.
webhook
<?php
require 'Payora.php';
$payora = new Payora('https://api.payora.money', getenv('PAYORA_KEY'), getenv('PAYORA_SECRET'));

$raw   = file_get_contents('php://input');           // raw, before any parsing
$event = $payora->verifyWebhook($raw, getallheaders()); // HMAC + ±300 s window, constant-time
if ($event === null) { http_response_code(400); exit; } // bad / forged / stale

if ($event['event'] === 'invoice.paid' && !alreadyProcessed($event['id'])) {
  creditOrder($event['order_id'], $event['amount'], $event['currency'], $event['tx_hash']);
  rememberProcessed($event['id']);
}
http_response_code(200); // 2xx stops retries
Песочница

Песочница подписи вебхука

Введите секрет, timestamp и сырое тело — и увидите ровно ту подпись, которую отправит Payora. Или проверьте полученную.

Работает в вашем браузере через WebCrypto. Ничего из введённого не покидает эту страницу. На чужом компьютере используйте тестовый секрет, а не боевой.

X-Payora-Timestamp
Подписываемая строка
1758038400.{…}
Заголовки, которые отправит Payora
headers
X-Payora-Timestamp: 1758038400
X-Payora-Signature: …

Вставьте подпись для сравнения

массовые выплаты

API массовых выплат

Отправляйте крипту на 500 кошельков одним подписанным идемпотентным запросом — зарплата, партнёрские выплаты, выводы. Сумма пачки плюс построчная комиссия сразу удерживается на внутреннем балансе; дальше оператор подписывает и транслирует, и срабатывает подписанный вебхук payout.sent. Авторизация HMAC та же, что и везде.

payout
# create a payout batch — funds held instantly, sent by the operator
curl -X POST https://api.payora.money/v1/payout \
  -H 'X-Payora-Key: pk_…' -H 'X-Payora-Timestamp: 1700000000' \
  -H 'X-Payora-Signature: <hmac-sha256>' -H 'Idempotency-Key: payroll-2026-01' \
  -d '{"currency":"USDT_TRON","items":[
        {"address":"TR7…","amount":"250.00"},
        {"address":"TX9…","amount":"99.50","tag":"batch-A"}]}'

# → 201 Created
{ "batch_id": 812, "status": "pending", "currency": "USDT_TRON",
  "item_count": 2, "total": "349.50", "fee": "…", "items": [ … ] }

# poll status, or receive a signed payout.sent webhook when it is sent
curl https://api.payora.money/v1/payout/812 -H 'X-Payora-Key: …' …

Проверка строгая: любой неверный адрес или сумма с избыточной точностью отклоняют весь пакет (HTTP 422) с индексами проблемных позиций — при выплате зарплат ни один получатель не пропадёт молча. Отмените ещё ожидающий пакет через POST /v1/payout/{id}/cancel, чтобы снять удержание. См. разбор архитектуры.

справочник

Справочник по адресам API

Каждый эндпоинт общается обычным JSON поверх HTTPS по адресу api.payora.money. Все, кроме /v1/health, используют одну и ту же аутентификацию запросов по HMAC-SHA256. Машиночитаемая спецификация находится по адресу openapi.json.

МетодДоступОписание
GET/v1/healthno authСтатус сервиса плюс список включённых валют.
POST/v1/invoiceauthСоздайте счёт (режим fiat или crypto). Поддерживает Idempotency-Key. Возвращает 201 с invoice_id, status, pay_url и expires; в режиме crypto добавляются адрес, сумма и deeplink.
GET/v1/invoice/{id}authСтатус счёта (только собственные счета): status, remaining и charge — currency, адрес, ожидаемая/полученная суммы и tx_hash.
POST/v1/payoutauth · Pro+Создайте пакет массовых выплат (строгая проверка, средства удерживаются мгновенно). Поддерживает Idempotency-Key. Возвращает 201 с представлением пакета: batch_id, status, итоги, комиссия, позиции.
GET/v1/payoutauthСписок ваших недавних пакетов выплат (?limit=, default 50).
GET/v1/payout/{id}authСтатус пакета выплат и его позиции (только собственные пакеты).
POST/v1/payout/{id}/cancelauthОтмените ещё ожидающий пакет и освободите удержанный баланс. Возвращает 409, если пакет уже нельзя отменить.
загрузки

SDK и загрузки

Одиночные файлы без зависимостей. Все SDK одинаково подписывают запросы и проверяют вебхуки.

phpPHPPayora.php

PHP 7.4+ и cURL, один файл. createInvoice, getInvoice и verifyWebhook.

jsNode.jspayora.js

Node.js только со встроенными https и crypto. Счета, баланс, выплаты и verifyWebhook.

pyPythonpayora.py

Только стандартная библиотека Python. Счета, баланс, выплаты и verify_webhook.

{ }Postmanpayora.postman_collection.json

Коллекция Postman, которая сама подписывает каждый вызов.

{…}OpenAPI 3.0openapi.json

Машиночитаемая спецификация всех методов — для генераторов кода и API-клиентов.

api.payora.moneyОткрыть
У вас WooCommerce, WHMCS, Magento или другая CMS?

Готовый модуль сделает всё это за вас: счёт, переход на оплату и проверенный вебхук.

Каталог плагинов
Вопросы

Часто задаваемые вопросы

Прямые ответы, в том числе на неудобные вопросы: хранение средств, комиссии и что будет, если что-то пойдёт не так.

Справочный центр

Как интегрировать Payora?

Поставьте однофайловый PHP-SDK (без зависимостей) или обращайтесь к REST API напрямую. Создайте счёт через createInvoice(), отправьте покупателя на его pay_url и обработайте одно событие вебхука: status=paid. Опытный разработчик запускается за 30–60 минут.

Есть ли REST API для не-PHP?

Да. Всё это обычный JSON поверх HTTPS, поэтому интегрироваться можно с любого языка. PHP-SDK — просто удобная обёртка над теми же адресами: создать счёт, получить счёт и проверить подпись вебхука.

Вернётся ли покупатель после оплаты на мой сайт и на нужном языке?

Да. Передайте return_url при создании счёта (или ?return_url= в платёжной ссылке) — и на экране успеха, и во время оплаты чек-аут покажет кнопку «Вернуться в магазин». Передайте lang (en, ru, uk, es, de) или ?lang= в ссылке, чтобы покупатель из русского магазина попал на русский чек-аут, а не на английский. Оба параметра необязательны; return_url должен быть абсолютным http(s)-адресом.

Как устроена аутентификация API?

Запросы и вебхуки подписываются HMAC-SHA256 по метке времени и сырому телу с вашим api_secret, допуск по времени ±120 секунд, плюс ключи идемпотентности. Подписи сравниваются за постоянное время, чтобы исключить атаку по времени.

Как получить ключи API?

Создайте бесплатный аккаунт. Публичный api_key и секретный api_secret появятся в кабинете вместе с SDK для скачивания и полным описанием вебхуков. Ключи можно в любой момент перевыпустить в настройках.

Что приходит в вебхуке?

Подписанное событие в JSON: идентификатор счёта, ваш order_id, статус (например, paid), сумма и валюта, а также уникальный id события для идемпотентности. Всегда проверяйте подпись до зачисления заказа и запоминайте id события, чтобы повторная доставка не обработалась дважды.

Есть ли API для массовых крипто-выплат?

Да. POST /v1/payout отправляет крипту на 500 кошельков одним запросом — по одному {address, amount, optional tag} на строку, в любой включённой у вас монете. Та же авторизация HMAC-SHA256 и тот же Idempotency-Key, что и у API счетов, поэтому повтор запроса не создаёт вторую пачку. Сумма пачки плюс построчная комиссия резервируется на балансе сразу; подписывает и транслирует оператор, после чего срабатывает подписанный вебхук payout.sent. Проверка строгая: один неверный адрес или слишком точная сумма отклоняют всю пачку (422), чтобы зарплатный прогон не потерял получателя молча.

Как автоматизировать зарплату или партнёрские выплаты в крипте?

Соберите список получателей у себя, затем вызовите POST /v1/payout один раз за прогон с устойчивым Idempotency-Key (например, payroll-2026-01). Опрашивайте GET /v1/payout/{id} или дождитесь вебхука payout.sent, чтобы подтвердить доставку и записать хеши. Отправка пачки резервирует средства, но сама их не двигает: подписывает и транслирует оператор, поэтому по одному вызову API ничего не уходит.

Получить ключи API

Один PHP-SDK без зависимостей: создать счёт, отправить на готовый чек-аут и проверить подпись вебхука. Для любого другого языка есть REST.

На какие запросы отвечает эта страница