# Обработчик платежа

Обработчик платежей — это URL вашего сервера, на который Unitpay отправляет серверные GET-запросы о ходе платежа. Через эти запросы вы можете:

* проверить заказ до оплаты;
* подтвердить, что заказ существует и может быть оплачен;
* автоматически выдать товар, оказать услугу или зачислить баланс после успешного списания;
* получать уведомления об ошибках по платежу.

{% hint style="info" %}
Важно: если URL обработчика не указан, callback-запросы не отправляются, а платеж считается успешным автоматически.
{% endhint %}

<figure><img src="/files/fPO0M4qZ0kzBXbOxZLzv" alt=""><figcaption></figcaption></figure>

## Требования к URL обработчика

Партнер может указать любой технически корректный URL обработчика. Домен обработчика не обязан совпадать с доменом сайта проекта.

### Что считается корректным URL

URL обработчика будет сохранен, если:

* используется протокол `http` или `https`;
* указан валидный домен;

#### Примеры корректных URL

* `https://example.com/payment-handler`
* `https://api.example.com/unitpay/callback`
* `http://merchant-service.net/pay`
* `https://xn--e1afmkfd.xn--p1ai/handler`

#### Примеры некорректных URL

* `ftp://example.com/callback` — недопустимый протокол
* `https://127.0.0.1/callback` — IP-адрес вместо домена
* `https://user:password@example.com/callback` — встроенные данные авторизации

## Как это работает

Обычно сценарий такой:

1. Покупатель начинает оплату.
2. Unitpay может отправить `check`, чтобы проверить заказ до списания.
3. После успешного списания Unitpay отправляет `pay`.
4. Если на одном из этапов возникла ошибка, может прийти `error`.
5. Для платежей с преавторизацией сначала может прийти `preauth`.

{% hint style="success" %}
Важно: при `preauth` деньги только заблокированы. Товар, услугу или баланс нужно выдавать только после успешного списания.
{% endhint %}

{% hint style="warning" %}
Важно: `error` не всегда означает окончательный статус. После `error` в некоторых случаях позже может прийти `pay`.
{% endhint %}

## Что нужно реализовать на своей стороне

Ваш обработчик должен:

* принимать GET-запросы от Unitpay;
* проверять [IP-адрес отправителя](/book-of-reference/ip-addresses.md);
* проверять `signature`;
* сверять `orderSum` и `orderCurrency` с данными заказа;
* на этапе `check` только проверять заказ;
* на этапе `pay` выдавать товар, оказывать услугу или зачислять баланс;
* корректно обрабатывать повторные запросы;
* возвращать JSON в нужном формате.

{% hint style="warning" %}
**Важно:** `unitpayId` — это уникальный идентификатор платежа в Unitpay. Если запрос с тем же `unitpayId` приходит повторно, не обрабатывайте платеж заново: не выдавайте товар повторно, не оказывайте услугу повторно и не зачисляйте баланс еще раз.
{% endhint %}

## Методы

### **`CHECK`**&#x20;

Запрос на проверку заказа до оплаты.

На этом этапе нужно убедиться, что:

* заказ существует;
* сумма и валюта совпадают;
* заказ можно оплатить;
* после успешной оплаты услугу можно оказать.

{% hint style="warning" %}
**Важно:** на этапе `check` не нужно выдавать товар, оказывать услугу или зачислять баланс.
{% endhint %}

{% hint style="info" %}
По умолчанию на новом проекте запрос `CHECK` выключен. Чтобы использовать его, включите эту опцию в настройках проекта.
{% endhint %}

<figure><img src="/files/Lx388wgSrCZHHENuGgop" alt=""><figcaption></figcaption></figure>

### **`PAY`**&#x20;

Уведомление об успешном списании средств.

Именно на этом этапе нужно:

* выдать товар;
* оказать услугу;
* зачислить баланс;
* сохранить результат обработки платежа.

Если на этом этапе ваш сервер вернет ошибку, платеж получит статус **«Не завершен»**. После устранения проблемы платеж можно повторно провести из интерфейса статистики.

{% hint style="info" %}
Важно: деньги зачисляются на баланс партнера независимо от ответа обработчика.
{% endhint %}

{% hint style="warning" %}
Важно: обработка pay должна быть идемпотентной. Повторный запрос не должен приводить к повторной выдаче товара или повторному зачислению.
{% endhint %}

### **`PREAUTH`**

Уведомление для [платежей с преавторизацией](/payments/pre-authorization-payments.md). Это значит, что деньги успешно заблокированы, но еще не списаны окончательно.

{% hint style="success" %}
Важно: не выдавайте товар и не оказывайте услугу при получении preauth. Делать это нужно только после успешного списания.
{% endhint %}

### **`ERROR`**

Уведомление об ошибке на одном из этапов платежа.

Если ошибка вызвана пустым или некорректным ответом сервера партнера, запрос `error` может не отправляться.

{% hint style="warning" %}
**Важно:** `error` не всегда является конечным статусом. После него иногда может прийти `pay`.
{% endhint %}

## Формат запроса

Unitpay отправляет GET-запрос на URL вашего обработчика.

Пример:

```json
GET https://адрес_вашего_обработчика

method               = check
params[account]      = userId
params[date]         = 2025-10-01 12:32:00
params[paymentType]  = card
params[projectId]    = 123456
params[payerSum]     = 10.00
params[payerCurrency]= RUB
params[signature]    = 9bdf52a4830779a1383ac24f1b3ed054
params[orderSum]     = 10.00
params[orderCurrency]= RUB
params[unitpayId]    = 1234567890
params[test]         = 0
```

### Параметры запроса

<table><thead><tr><th width="190.44441731770831">Параметр</th><th width="150.2222900390625">Значение</th><th>Описание</th></tr></thead><tbody><tr><td><strong>method</strong></td><td>string</td><td>Тип запроса: <code>check</code>, <code>pay</code>, <code>preauth</code>, <code>error</code></td></tr><tr><td><strong>unitpayId</strong> </td><td>число</td><td>Внутренний номер платежа в UnitPay</td></tr><tr><td><strong>projectId</strong> </td><td>число</td><td>ID проекта в UnitPay</td></tr><tr><td><strong>account</strong> </td><td>string</td><td>Идентификатор пользователя или заказа в вашей системе</td></tr><tr><td><strong>payerSum</strong></td><td>число</td><td>Сумма списания с лицевого счета абонента</td></tr><tr><td><strong>sum</strong></td><td>число</td><td>Сумма списания с лицевого счета абонента (дополнительное значение)</td></tr><tr><td><strong>ip</strong></td><td>string</td><td>IP-адрес плательщика (с которого инициировано создание платежа)</td></tr><tr><td><strong>isPreauth</strong></td><td>число</td><td>Признак преавторизации: 1 — да, 0 — нет</td></tr><tr><td><strong>payerCurrency</strong></td><td>string</td><td>Валюта списания с лицевого счета абонента по стандарту ISO 4217 (RUB, BYN, EUR, USD)   </td></tr><tr><td><strong>profit</strong></td><td>число</td><td>Ваш доход с данного платежа, в рублях</td></tr><tr><td><strong>paymentType</strong></td><td>string</td><td><a href="/pages/-M9y0PdOWFK4DxzzyaSC">Код платежной системы</a></td></tr><tr><td><strong>orderSum</strong></td><td>число</td><td><p>Сумма заказа</p><p><strong>Обязательно сверяйте поступившее значение с оригинальной суммой заказа</strong></p></td></tr><tr><td><strong>orderCurrency</strong></td><td>string</td><td><p>Валюта заказа по стандарту ISO 4217 (RUB, BYN, EUR, USD)</p><p><strong>Обязательно сверяйте поступившее значение с оригинальной валютой заказа</strong></p></td></tr><tr><td><strong>date</strong></td><td>string</td><td>Дата платежа в формате YYYY-mm-dd HH:ii:ss (например 2024-10-01 12:32:00)</td></tr><tr><td><strong>errorMessage</strong></td><td>string</td><td>Детализация ошибки (только для метода error)</td></tr><tr><td><strong>test</strong></td><td>число</td><td>Признак тестового режима: 1 — тест, 0 — реальный платеж</td></tr><tr><td><strong>3ds</strong></td><td>число</td><td>Признак наличия 3-DS для операций по карте, флаг присутствует при PAY уведомлениях</td></tr><tr><td><strong>subscriptionId</strong></td><td>число</td><td>Идентификатор подписки, может приходить в <code>preauth</code> и <code>pay</code></td></tr><tr><td><strong>signature</strong></td><td>string</td><td>Цифровая подпись. Образуется как <code>sha256(method + "{up}" + params + "{up}" + secretKey)</code>, <br>где <strong>sha256</strong> - метод шифрования;<br><strong>"{up}"</strong> - разделитель параметров в хеш-функции;<br><strong>method</strong> - тип вызова (check, pay, error);<br><strong>params</strong> - значения параметров из массива params, объединенные разделителем "{up}". Все параметры должны быть предварительно отсортированы по ключу, в склейке не участвует параметр signature;<br><strong>secretKey</strong> - секретный ключ проекта (доступен в личном кабинете);<br><br>Пример расчета подписи для запроса <a href="http://partnerurl/?method=check%20&#x26;%20params[b]=bob&#x26;params[c]=sam&#x26;params[a]=tod"><strong>http://partnerUrl?method=check &#x26; params[b]=bob &#x26; params[c]=sam &#x26; params[a]=tod</strong></a> и секретного ключа <strong>"a1b1c1d1"</strong><br><br><strong><code>sha256</code></strong><code> ("check{up}tod{up}bob{up}sam{up}a1b1c1d1")</code></td></tr></tbody></table>

### Успешный ответ

Если запрос обработан успешно, верните:

```json
{
    "result": {
        "message": "Запрос успешно обработан"
    }
}
```

| Параметр    | Значение | Описание                             |
| ----------- | -------- | ------------------------------------ |
| **message** | string   | Текстовый статус выполнения запроса. |

### Ошибочный ответ

Если запрос не может быть обработан, верните:

```json
{
    "error": {
        "message": "Описание ошибки"
    }
}
```

<table data-header-hidden><thead><tr><th width="200.44441731770831">Парамтер</th><th width="186.3333740234375">Значение</th><th>Описание</th></tr></thead><tbody><tr><td><strong>message</strong></td><td>string</td><td><p>Информация с описанием ошибки формирования платежа.</p><p>При использовании формы оплаты текст из параметра "message" будет показан плательщику. </p></td></tr><tr><td><strong>locale</strong></td><td>string</td><td><p>Настраивает язык вводной части. </p><p><strong>Возможные значения</strong>: "en" или "ru". По умолчанию "ru"</p><p></p><p>Например: "Магазин отклонил платеж: <em>причина блокировки</em>", где "Магазин отклонил платеж:" - вводная часть. "<em>Причина блокировки</em>" - значение параметра message</p></td></tr></tbody></table>

### Частые ошибки интеграции

Чаще всего проблемы возникают из-за того, что:

* не проверяется `signature`;
* не проверяются IP-адреса;
* не сверяются `orderSum` и `orderCurrency`;
* товар выдается на этапе `check`, а не на этапе `pay`;
* сервер возвращает некорректный JSON.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://help.unitpay.ru/payments/payment-handler.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
