После оплаты заказа магазин может вернуть уплаченные средства пользователю. Осуществляются как полные, так и частичные возвраты. Частичные возвраты могут выполняться, пока клиенту не будет возвращена вся сумма.

Если к моменту возврата не было досрочного подтверждения исполнения заказа, либо не произошло автоматическое подтверждение исполнения заказа, то средства возвращаются на карту клиента. После подтверждения исполнения заказа средства возвращаются на баланс клинта в PayQR

Для полного возврата или возврата оставшейся суммы по заказу (если до этого были частичные возвраты), необходимо выполнить следующую команду.

Пример:  

HEADER PQRSecretKey = "..."
POST https://payqr.ru/shop/api/1.0/invoices/{id}/revert
Пример ответа:
{
  "object": "invoice",
  "id": "usr_inv_0lSaM2xIv8xydXdHl3f5qm",
  "created": "2015-03-17T15:24:04.311+03:00",
  "modified": "2015-05-17T19:10:08.107+03:00",
  "livemode": true,
  "amount": 13000.00,
  "status": "reverted",
  "reverts": [{
    "id": "rvt_hBNxk8ktYrHb58B2jCurOG"
  }]
}

В заголовке PQRSecretKey указывается секретный ключ из личного кабинета магазина (SecretKeyOut).


id
идентификатор счёта (invoiceId)

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

Пример:  

HEADER PQRSecretKey = "..."
POST https://payqr.ru/shop/api/1.0/invoices/{id}/revert?amount={amount}
Пример ответа:
{
  "object": "invoice",
  "id": "usr_inv_0lSaM2xIv8xydXdHl3f5qm",
  "created": "2015-03-17T15:24:04.311+03:00",
  "modified": "2015-05-17T19:10:08.107+03:00",
  "livemode": true,
  "amount": 13000.00,
  "status": "revertedPartially",
  "reverts": [{
    "id": "rvt_hBNxk8ktYrHb58B2jCurOG"
  }]
}

В заголовке PQRSecretKey указывается секретный ключ из личного кабинета магазина (SecretKeyOut).


id
идентификатор счёта (invoiceId)
amount
сумма к возврату

Если сумма возврата превышает сумму счета на оплату за вычетом уже проведенных остатков, то команда вернет статус 409 (Conflict).

После того, как возврат был проведен успешно, на сервер приходит уведомление revert.succeeded.

Команда на возврат выполняется асинхронно, поэтому, если какие-то ошибки возникнут в процессе выполнения (было запущено несколько возвратов одновременно), то придут уведомления revert.failed о невыполненных возвратах.

Когда счет был отменен полностью, дополнительно присылается уведомление invoice.reverted. Это уведомление было реализовано для более удобной обработки случая, когда заказ не нужно отсылать.

Мы рекомендуем логику обработки отмены заказа в учетной системе реализовывать именно в обработчиках событий, а не в момент вызова операции отмены. Т.к. система состоит из многих составляющих и интеграций с внешними системами - банками, эквайерами, другими источниками денежных средств, возможны ошибки во время исполнения заявки на возврат.

Сервер PayQR отправляет уведомления revert.succeeded и revert.failed. В данных приходят объекты возвратов следующего вида.

Пример:  

{
  "object": "event",
  "id": "evt_14EccV2eZvKYlo2C2j1B18pF",
  "created": "2015-08-09T18:31:42.201+04:00",
  "type": "revert.succeeded",
  "data": {
    "id": "rvt_T5JTgj544p45gG36g",
    "object": "revert",
    "created": "2015-08-09T18:31:42.201+04:00",
    "modified": "2015-08-09T18:33:42.201+04:00",
    "invoiceId": "usr_inv_gKSaFJxIv8xydXdOl3f4fm",
    "amount": 500.00,
    "status": "succeeded"
  }
}

В заголовке header PQRSecretKey должен быть указан ключ для сервера из личного кабинета (SecretKeyIn).

По уведомлению invoice.reverted приходят объекты счетов на оплату следующего вида.

Пример:  

{
  "object": "event",
  "id": "evt_14EccV2eZvKYlo2C2j1B18pF",
  "created": "2015-08-09T18:31:42.201+04:00",
  "type": "invoice.reverted",
  "data": {
    "id": "inv_14EeCA2eZvKYlo2C8nDrcXdp",
    "object": "invoice",
    "livemode": false,
    "created": "2015-08-09T18:31:42.201+04:00",
    "modified": "2015-08-09T18:33:42.201+04:00",
    "payqrNumber": "3213326680056410",
    "payqrUserId": "000000000000",
    "orderId": "123.456",
    "amount": 19648.44,
    "cart": [{
      "article": "5675657",
      "name": "Товар 1",
      "imageUrl": "http:/*goods.ru/item1.jpg",
      "quantity": 5,
      "amount": 19752.25
    }],
    "customer": {
      "firstName": "Иван",
      "lastName": "Иванов",
      "phone": "+79111111111",
      "email": "test@user.com"
    },
    "delivery": {
      "longitude": 55.718666,
      "latitude": 37.634119,
      "kladrId": "77000000000222600",
      "country": "Россия",
      "region": "Москва",
      "city": "Москва",
      "zip": "115093",
      "street": "Партийный пер.",
      "house": "1",
      "unit": "416 б",
      "hallway": "2",
      "floor": "4",
      "intercom": "к416к1234",
      "comment": "Пройти магазин Пионерия и повернуть направо. Охране сказать, что в PayQR",
    },
    "validityInMinutes": 129600,
    "confirmWaitingInMinutes": 4320,
    "status": "reverted"
  }
}

В заголовке header PQRSecretKey должен быть указан ключ для сервера из личного кабинета (SecretKeyIn).

Если вы используете PHP, обработчик может быть реализован так.

Пример:  

<?php
 /* Ключ системы PayQR для этого магазина, указанный в личном кабинете */
 $secretKeyIn = "XXX";
 /* Ключ магазина, указанный в личном кабинете */
 $secretKeyOut = "YYY";
 /* Получаем уведомление о событии из тела пришедшего POST запроса */
 $event = json_decode(file_get_contents("php://input"));
 /* Получаем хидеры запроса */
 $headers = getallheaders();
 /* Проверить, что запрос от сервера PayQR */
 if (isset($headers["PQRSecretKey"]) && $headers["PQRSecretKey"] == $secretKeyIn
         && isset($event->object) && $event->object == "event"
         && isset($event->type))
 {
    /* Подтвердить, что ответ от магазина */
    header("PQRSecretKey:" . $secretKeyOut);
    /* Проверяем событие на полную отмену счета на оплату */
    if ($event->type == "invoice.reverted")
    {
      /* Обработать полную отмену заказа */
    }
    /* Проверяем событие на успешную обработку возврата по счету */
    if ($event->type == "revert.succeeded")
    {
      /* Обработать частичную отмену заказа */
    }
    /* Проверяем событие на ошибку обработки возврата */
    if ($event->type == "revert.failed")
    {
      /* Обработать ошибки возвратов */
    }
 }
?>