П Платёжка Документация

Вебхуки

Мы отправляем POST JSON на адрес, указанный в кабинете (Интеграция → Подключение, только https). На него приходят все события. Ожидаем ответ 2xx в течение 10 с; иначе повторяем через 1 мин, 5 мин, 30 мин, 2 ч, 12 ч, 24 ч. Журнал и ручной повтор — в кабинете. Обработчик должен быть идемпотентным по id события.

СобытиеКогдаdata
payment.pendingПлатёж созданpayment
payment.authorizedХолд по картеpayment
payment.succeededПлатёж оплаченpayment
payment.canceledПлатёж отклонён или отменёнpayment
payment.expiredПлатёж просроченpayment
refund.succeededВозврат выполненrefund
refund.failedВозврат не выполненrefund
receipt.readyЧек готовreceipt
payment_method.savedСпособ оплаты сохранён для автосписанийpayment_method
payout.succeededВыплата выполненаpayout
payout.failedВыплата не выполненаpayout

Обрабатывайте нужные события, остальные просто подтверждайте ответом 200. В событиях платежа data.order_id — номер заказа, переданный при создании.

Пример тела:

{
  "id": "evt_Ab12Cd34Ef56Gh78Ij90",
  "type": "payment.succeeded",
  "created_at": "2026-09-22T12:05:00+03:00",
  "data": {
    "id": "pay_3kZ1x9QmT0aBcDeFgHiJkL",
    "object": "payment",
    "shop_id": "723612",
    "mode": "live",
    "test": false,
    "status": "succeeded",
    "amount": 100000,
    "currency": "RUB",
    "captured_amount": 100000,
    "refunded_amount": 0,
    "order_id": "1001",
    "description": "Заказ 1001",
    "capture_mode": "auto",
    "method": "card",
    "confirmation": {
      "type": "hosted"
    },
    "payment_url": "https://platezhka.online/pay/pay_3kZ1x9QmT0aBcDeFgHiJkL",
    "return_url": "https://shop.example/orders/1001",
    "customer": {
      "id": "user-42",
      "email": "buyer@example.com"
    },
    "items": [
      {
        "itemId": 1,
        "text": "Товар",
        "price": 100000,
        "quantity": 1
      }
    ],
    "metadata": {},
    "source": "api",
    "receipt_status": null,
    "paygine_order_id": 3504676,
    "expires_at": "2026-09-22T13:00:00+03:00",
    "created_at": "2026-09-22T12:00:00+03:00",
    "paid_at": "2026-09-22T12:05:00+03:00"
  }
}

Проверка подписи

Заголовки: X-Event, X-Delivery-Id, X-Signature: t=<unix>,v1=<hex>, где v1 = HMAC-SHA256(ключ, "<t>.<тело>"), а ключ — секретный ключ API магазина (sk_test_… или sk_live_…), как в CloudPayments. Отдельного секрета для вебхуков нет. Отклоняйте запросы старше 5 минут.

require "openssl"
def valid_signature?(secret, body, header)
  parts = header.split(",").to_h { |kv| kv.split("=", 2) }
  expected = OpenSSL::HMAC.hexdigest("SHA256", secret, "#{parts["t"]}.#{body}")
  (Time.now.to_i - parts["t"].to_i).abs < 300 && Rack::Utils.secure_compare(expected, parts["v1"])
end
import hmac, hashlib, time
def valid_signature(secret: str, body: bytes, header: str) -> bool:
    parts = dict(kv.split("=", 1) for kv in header.split(","))
    expected = hmac.new(secret.encode(), f"{parts['t']}.".encode() + body, hashlib.sha256).hexdigest()
    return abs(time.time() - int(parts["t"])) < 300 and hmac.compare_digest(expected, parts["v1"])

Готовый обработчик

Проверка подписи и обработка payment.succeeded целиком:

<?php
$secret = 'sk_test_...';
$body = file_get_contents('php://input');
parse_str(str_replace(',', '&', $_SERVER['HTTP_X_SIGNATURE'] ?? ''), $sig);
$expected = hash_hmac('sha256', ($sig['t'] ?? '') . '.' . $body, $secret);
if (abs(time() - (int) ($sig['t'] ?? 0)) > 300 || !hash_equals($expected, $sig['v1'] ?? '')) {
    http_response_code(400);
    exit;
}

$event = json_decode($body, true);
if ($event['type'] === 'payment.succeeded') {
    $payment = $event['data'];
    // Найдите заказ по $payment['order_id'], сверьте $payment['amount'] и отметьте его оплаченным.
    // Событие может прийти повторно: обработка должна быть идемпотентной по $event['id'].
}
http_response_code(200);

Дополнительные адреса через API

GET /webhook_endpoints, POST /webhook_endpoints {url, events} (без events — все события, кроме payment.pending; подпись — тем же секретным ключом), DELETE /webhook_endpoints/{id}.