Вопросы
P2P Help Bot
NAV Navbar
PHP SDK Node.js SDK Java SDK .Net SDK HTTP

Условия использования

Для подключения на свой сайт сервиса приема переводов для физических лиц p2p необходимо иметь QIWI Кошелек со статусом идентификации «Основной» или «Профессиональный». Если Ваш кошелек имеет статус «Анонимный» – пройдите идентификацию удобным для вас способом. Для получения «Основного» статуса достаточно указать паспортные данные, для получения «Профессионального» статуса необходимо пройти очную идентификацию.

Рекомендуем получить «Профессиональный» статус, т.к. такой статус имеет повышенные лимиты на остаток на балансе, сумму платежей и переводов в месяц, максимальную сумму одной операции – подробнее про лимиты.

Рекомендуем ознакомиться с частыми вопросами по нашему сервису, а также с информацией о том, как избежать блокировки кошелька.

Активация p2p

Поздравляем! Вы можете приступить к интеграции.

Персонализация формы

Вы можете настроить персонализированную форму оплаты – изменить свое имя на название магазина и настроить цвет фона и кнопок. Перейдите в личном кабинете в раздел Форма приема переводов, нажмите на кнопку Настроить, произведите настройку и нажмите на кнопку Сохранить.

При использовании API или SDK Вам необходимо будет передавать в параметр customFields переменную themeCode, значение которой у вас отображается в личном кабинете – подробнее на шаге 4.

Обратите внимание, что значение themeCode индивидуально для разных кошельков.

alt_text

Процесс интеграции через SDK

Ознакомьтесь с нашей документацией.

Шаг 1. Подготовка среды разработки

//Установка с помощью npm

$ npm install @qiwi/bill-payments-node-js-sdk --save
//Установка с помощью composer

$ composer require qiwi/bill-payments-php-sdk
//Установка с помощью maven

<dependency>
    <groupId>com.qiwi</groupId>
    <artifactId>bill-payments-java-sdk</artifactId>
    <version>1.5.0</version>
</dependency>
//Установка с помощью Nuget

nuget install Qiwi.BillPayments

Шаг 2. Создание секретного ключа

Шаг 3. Авторизация

const QiwiBillPaymentsAPI = require('@qiwi/bill-payments-node-js-sdk');

const SECRET_KEY = 'eyJ2ZXJzaW9uIjoicmVzdF92MyIsImRhdGEiOnsibWVyY2hhbnRfaWQiOjUyNjgxMiwiYXBpX3VzZXJfaWQiOjcxNjI2MTk3LCJzZWNyZXQiOiJmZjBiZmJiM2UxYzc0MjY3YjIyZDIzOGYzMDBkNDhlYjhiNTnONPININONPN090MTg5Z**********************=';
const qiwiApi = new QiwiBillPaymentsAPI(SECRET_KEY);
<?php
const SECRET_KEY = 'eyJ2ZXJzaW9uIjoicmVzdF92MyIsImRhdGEiOnsibWVyY2hhbnRfaWQiOjUyNjgxMiwiYXBpX3VzZXJfaWQiOjcxNjI2MTk3LCJzZWNyZXQiOiJmZjBiZmJiM2UxYzc0MjY3YjIyZDIzOGYzMDBkNDhlYjhiNTnONPININONPN090MTg5Z**********************=';

$billPayments = new Qiwi\Api\BillPayments(SECRET_KEY);

?>
String secretKey = "eyJ2ZXJzaW9uIjoicmVzdF92MyIsImRhdGEiOnsibWVyY2hhbnRfaWQiOjUyNjgxMiwiYXBpX3VzZXJfaWQiOjcxNjI2MTk3LCJzZWNyZXQiOiJmZjBiZmJiM2UxYzc0MjY3YjIyZDIzOGYzMDBkNDhlYjhiNTnONPININONPN090MTg5Z**********************=";

BillPaymentClient client = BillPaymentClientFactory.createDefault(secretKey);
var client = BillPaymentClientFactory.Create(
    secretKey: "eyJ2ZXJzaW9uIjoicmVzdF92MyIsImRhdGEiOnsibWVyY2hhbnRfaWQiOjUyNjgxMiwiYXBpX3VzZXJfaWQiOjcxNjI2MTk3LCJzZWNyZXQiOiJmZjBiZmJiM2UxYzc0MjY3YjIyZDIzOGYzMDBkNDhlYjhiNTnONPININONPN090MTg5Z**********************="
);

В разрабатываемом коде заведите константу SECRET_KEY и присвойте ей значение секретного ключа, вставив его из буфера обмена комбинацией клавиш Ctrl+V.

Проверьте, что ключ скопирован полностью, в конце должен быть знак "равно" =.

Раздел документации с примерами авторизации находится здесь.

Если возвращается ошибка авторизации HTTP/1.1 401 Unauthorized, это значит что-то не так с секретным ключом. Выпустите новый ключ и скопируйте его полностью, в конце должен быть знак "равно" =.

Шаг 4. Выставление счета

Реализуйте вызов метода createBill.

Пример генерации billId

<?php

/** @var \Qiwi\Api\BillPayments $billPayments */
$billId = $billPayments->generateId();
//e9b47ee9-b2f9-4b45-9438-52370670e2a6

?>
const billId = qiwiApi.generateId();
//e9b47ee9-b2f9-4b45-9438-52370670e2a6

Примеры генерации expirationDateTime. Входной параметр - сколько дней счёт будет доступен, по умолчанию 45 дней. Метод возвращает строку в формате ISO 8601 UTC±0:00

<?php

//now: 2021-01-28T17:16:58.033Z
/** @var \Qiwi\Api\BillPayments $billPayments */
$lifetime = $billPayments->getLifetimeByDay(1);
//2021-01-29T17:16:58.033Z

?>

<?php

//now: 2021-01-28T17:16:58.033Z
/** @var \Qiwi\Api\BillPayments $billPayments */
$lifetime = $billPayments->getLifetimeByDay(0.5);
//2021-01-29T05:16:58.033Z

?>
//now: 2021-01-28T17:16:58.033Z
const lifetime = qiwiApi.getLifetimeByDay(1);
//2021-01-29T17:16:58.033Z

//now: 2021-01-28T17:16:58.033Z
const lifetime = qiwiApi.getLifetimeByDay(0.5);
//2021-01-29T05:16:58.033Z

Запрос создания счета

const billId = 'cc961e8d-d4d6-4f02-b737-2297e51fb48e';

const fields = {
    amount: 1.00,
    currency: 'RUB',
    comment: 'Hello world',
    expirationDateTime: '2020-08-28T19:44:07',
    email: 'example@mail.org',
    account : 'client4563',
    customFields : {themeCode: 'кодСтиля'},
    successUrl: 'http://test.ru/'
};

qiwiApi.createBill( billId, fields ).then( data => {
    //do with data
});
<?php

$billId = 'cc961e8d-d4d6-4f02-b737-2297e51fb48e';
$customFields = ['themeCode' => 'кодСтиля'];
$fields = [
  'amount' => 1.00,
  'currency' => 'RUB',
  'comment' => 'Hello world',
  'expirationDateTime' => '2020-08-28T19:44:07+03:00',
  'email' => 'example@mail.org',
  'account' => 'client4563',
  'successUrl' => 'http://test.ru/',
  'customFields' => $customFields,
  ];

/** @var \Qiwi\Api\BillPayments $billPayments */
$response = $billPayments->createBill($billId, $fields);

print_r($response);

?>
CreateBillInfo billInfo = new CreateBillInfo(
                UUID.randomUUID().toString(),
                new MoneyAmount(
                        BigDecimal.valueOf(199.90),
                        Currency.getInstance("RUB")
                ),
                "Hello world",
                ZonedDateTime.now().plusDays(45),
                new Customer(
                        "example@mail.org",
                        UUID.randomUUID().toString(),
                        "79123456789"
                ),
                "http://merchant.ru/success"
        );
BillResponse response = client.createBill(billInfo);
client.CreateBill(
    info: new CreateBillInfo
    {
        BillId = Guid.NewGuid().ToString(),
        Amount = new MoneyAmount
        {
            ValueDecimal = 199.9m,
            CurrencyEnum = CurrencyEnum.Rub
        },
        Comment = "Hello world",
        ExpirationDateTime = DateTime.Now.AddDays(45),
        Customer = new Customer
        {
            Email = "example@mail.org",
            Account = Guid.NewGuid().ToString(),
            Phone = "79123456789"
        },
        SuccessUrl = new Uri("http://merchant.ru/success")
        CustomFields: new CustomFields
        {
            ThemeCode = "Ivan-VbRVlW-YGL"
        }
    },
);
curl --location --request PUT 'https://api.qiwi.com/partner/bill/v1/bills/cc961e8d-d4d6-4f02-b737-2297e51fb48e' \
--header 'content-type: application/json' \
--header 'accept: application/json' \
--header 'Authorization: Bearer eyJ2ZXJzaW9uIjoicmVzdF92MyIsImRhdGEiOnsibWVyY2hhbnRfaWQiOjIwNDIsImFwaV91c2VyX2lkIjo1NjYwMzk3Miwic2VjcmV0IjoiQjIwODlDNkI5Q0NDNTdCNDQzNGHJK43JFJDK595FJFJMjlCRkFFRDM5OE***********************' \
--data-raw '{  
   "amount": {   
     "currency": "RUB",   
     "value": "1.00" 
   },  
   "comment": "Text comment",  
   "expirationDateTime": "2025-12-10T09:02:00+03:00",  
   "customer": {
     "phone": "78710009999",
     "email": "test@tester.com",
     "account": "454678"
   }, 
   "customFields" : {
     "paySourcesFilter":"qw",
     "themeCode": "Yvan-YKaSh",
     "yourParam1": "64728940",
     "yourParam2": "order 678"
   }
 }'

Обязательные параметры:

Рекомендуем использовать дополнительные параметры:

alt_text

Необязательные параметры для выставления счета:

Ответ

{
  "siteId": "270305",
  "billId": "cc961e8d-d4d6-4f02-b737-2297e51fb48e",
  "amount": {
    "currency": "RUB",
    "value": "1.00"
  },
  "status": {
    "value": "WAITING",
    "changedDateTime": "2020-07-28T19:44:07.855+03:00"
  },
  "comment": "Hello world",
  "customFields": {
    "themeCode": "кодСтиля",
  },
  "creationDateTime": "2020-07-28T19:44:07.855+03:00",
  "expirationDateTime": "2020-08-28T19:44:07.855+03:00",
  "payUrl": "https://oplata.qiwi.com/form/?invoice_uid=bb773791-9bd9-42c1-b8fc-3358cd108422&successUrl=http%3A%2F%2Ftest.ru%2F"
}
Array
(
    [siteId] => 270305
    [billId] => cc961e8d-d4d6-4f02-b737-2297e51fb48e
    [amount] => Array
        (
            [currency] => RUB
            [value] => 1.00
        )

    [status] => Array
        (
            [value] => WAITING
            [changedDateTime] => 2020-07-28T19:44:38.855+03:00
        )

    [comment] => Hello world
    [customFields] => Array
        (
            [themeCode] => кодТемы
        )
    [creationDateTime] => 2020-07-28T19:44:07.855+03:00
    [expirationDateTime] => 2020-08-28T19:44:07.855+03:00
    [payUrl] => https://oplata.qiwi.com/form/?invoice_uid=bb773791-9bd9-42c1-b8fc-3358cd108422&successUrl=http%3A%2F%2Ftest.ru%2F
)
{
  "siteId": "270304",
  "billId": "cc961e8d-d4d6-4f02-b737-2297e51fb48e",
  "amount": {
    "value": "199.90",
    "currency": "RUB"
  },
  "status": {
    "value": "WAITING",
    "changedDateTime": "2020-08-28T19:44:51.407Z"
  },
  "comment": "Hello world",
  "customer": {
    "email": "example@mail.org",
    "account": "040c3bb8-b207-4ecc-9ff9-90168d3bc34f",
    "phone": "79123456789"
  },
  "creationDateTime": "2020-07-28T19:49:07.407Z",
  "expirationDateTime": "2020-09-10T19:49:07.407Z",
  "payUrl": "https://oplata.qiwi.com/form/?invoice_uid=c77a9051-1467-416b-991e-c25f06c61168&successUrl=http%3A%2F%2Fmerchant.ru%2Fsuccess",
  "customFields": {
    "apiClient": "java_sdk",
    "apiClientVersion": "1.0.0"
  }
}
new BillResponse
{
    SiteId = "270304",
    BillId = "cc961e8d-d4d6-4f02-b737-2297e51fb48e",
    Amount = new MoneyAmount
    {
        ValueString = "199.90",
        CurrencyString = "RUB"
    },
    Status = new ResponseStatus
    {
        ValueString: "WAITING",
        ChangedDateTime: BillPaymentsUtils.ParseDate("2020-07-28T19:44:07+03:00")
    },
    Comment = "Hello world",
    Customer = new Customer
    {
        Email = "example@mail.org",
        Account = "040c3bb8-b207-4ecc-9ff9-90168d3bc34f",
        Phone = "79123456789"
    },
    CreationDateTime = BillPaymentsUtils.ParseDate("2020-07-28T19:44:07+03:00"),
    ExpirationDateTime = BillPaymentsUtils.ParseDate("2020-09-10T19:44:07+03:00"),
    PayUrl = new Uri("https://oplata.qiwi.com/form/?invoice_uid=c77a9051-1467-416b-991e-c25f06c61168&successUrl=http%3A%2F%2Fmerchant.ru%2Fsuccess"),
    CustomFields = new CustomFields
    {
        ApiClient = "dotnet_sdk",
        ApiClientVersion = "0.1.0",
        ThemeCode = "Ivan-VbRVlW-YGL"
    }
};
{
    "siteId": "9hh4jb-00",
    "billId": "cc961e8d-d4d6-4f02-b737-2297e51fb48e",
    "amount": {
        "currency": "RUB",
        "value": "1.00"
    },
    "status": {
        "value": "WAITING",
        "changedDateTime": "2021-01-18T14:22:56.672+03:00"
    },
    "customer": {
        "phone": "78710009999",
        "email": "test@tester.com",
        "account": "454678"
    },
    "customFields": {
        "paySourcesFilter": "qw",
        "themeCode": "Yvan-YKaSh",
        "yourParam1": "64728940",
        "yourParam2": "order 678"
    },
    "comment": "Text comment",
    "creationDateTime": "2021-01-18T14:22:56.672+03:00",
    "expirationDateTime": "2025-12-10T09:02:00+03:00",
    "payUrl": "https://oplata.qiwi.com/form/?invoice_uid=aa0fa2bb-5452-47ca-9190-cd9c1a73718f"
}

В ответе на запрос выставления счета возвращаются следующие поля:

Если на запрос создания счёта вернулась ошибка - проверьте формат переданных в запрос параметров. Если не получается разобраться самостоятельно - опишите ситуацию и отправьте нам traceId из ответа в Telegram-бот.

Для тестирования и отладки сервиса рекомендуем выставлять и оплачивать счета суммой 1 рубль.

Раздел документации с примерами выставления счетов находится здесь.

Шаг 5. Установка дополнительных параметров к ссылке на счёт

https://oplata.qiwi.com/form/?invoice_uid=aa0fa2bb-5452-47ca-9190-cd9c1a73718f&successUrl=qiwi.com&paySource=qw

При выставлении счета через API в ответе приходит payUrl, содержащий ссылку на форму. К данной ссылке можно добавить следующие параметры:

Шаг 6. Редирект пользователя на платежную форму

Пример получения URL оплаты по счету

<?php
/** @var array $bill */
/** @var \Qiwi\Api\BillPayments $billPayments */
$payUrl = $billPayments->getPayUrl($bill, 'http://test.ru/');
// https://oplata.qiwi.com/form/?invoice_uid=d875277b-6f0f-445d-8a83-f62c7c07be77&successUrl=http%3A%2F%2Ftest.ru%2F
?>

Реализуйте на вашем сайте перенаправление пользователя на платежную форму по ссылке, полученной в ответе на запрос выставления счёта в параметре payUrl или по ссылке с дополнительными параметрами, сформированной на шаге 5.

Добавьте реферальные ссылки для платежей с сайта. Полная ссылка подтвердит его реальность и позволит избежать проблем с блокировкой кошелька.

Пример передачи реферальной ссылки

<?php header("Referrer-Policy: no-referrer-when-downgrade"); ?>

Для того, чтобы в новых версиях браузеров передавался полный referer при переходе, необходимо выставить дополнительный заголовок Referrer-Policy в ответе сервера. Это можно сделать для всего сайта или отдельно на той странице, где отрисовывается ссылка на форму оплаты. Значение заголовка должно быть no-referrer-when-downgrade.

Шаг 7. Получение серверных уведомлений об оплате счетов или опрос статуса счета - что выбрать?

Сервис уведомлений позволяет понять, когда и по какому счету произошла оплата. Вам не нужно каждый раз отправлять запросы в QIWI, можно подключить сервис и получать уведомления автоматически. Но стоит обратить внимание на то, что уведомление может быть отправлено несколько раз даже в случае успешного ответа от вашего сервиса, поэтому это необходимо учитывать при разработке бизнес-логики отгрузки товара или услуги на вашей стороне.

Формат уведомлений описан в документации.

Данные приходят в теле запроса (body). Данные запроса хранятся в формате JSON.

Так как для отладки уведомлений тестовый контур не предусмотрен, рекомендуем выставлять счета на 1 рубль и оплачивать их самостоятельно.

Сервис уведомлений не является обязательным для интеграции, вы можете реализовать более простой вариант с опросом статуса счета. В этом случае перейдите сразу к шагу 11.

Условия интеграции с API уведомлений

Если же вы пока не можете определиться, тогда ознакомьтесь с условиями обслуживания интеграции с API уведомлений:

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

Шаг 8*. Настройка серверных уведомлений

Пример уведомления

POST /qiwi-notify.php HTTP/1.1
Accept: application/json
Content-type: application/json
X-Api-Signature-SHA256: J4WNfNZd***V5mv2w=
Host: server.ru

{ "bill":
  {  
     "siteId":"23044",
     "billId":"1519892138404fhr7i272a2",
     "amount":{  
        "value":"100",
        "currency":"RUB"
     },
     "status":{  
        "value":"PAID",
        "datetime":"2018-03-01T11:16:12"
     },
     "customer":{},
     "customFields":{},
     "creationDateTime":"2018-03-01T11:15:39",
     "expirationDateTime":"2018-04-01T11:15:39+03:00"
   },
  "version":"1"
}

Пример получения уведомления

<?php
    $log_file = fopen(__DIR__ . '/qiwi.txt', 'a+');
    fwrite($log_file, print_r(json_decode(file_get_contents('php://input')), true).PHP_EOL);
    fwrite($log_file, print_r(getallheaders(), true).PHP_EOL);
    fclose($log_file);
?>

Уведомление представляет собой входящий POST-запрос.

Тело запроса содержит JSON-сериализованные данные счета (кодировка UTF-8).

Если не приходят уведомления по счету:

  1. Проверьте заголовки. По стандарту они регистронезависимы и ваш клиент может их изменить – смотрите документацию вашего клиента.
  2. Попробуйте отправить себе уведомление, заменив в примере https://test.com/notif.php на URL, который вы указали при создании ключей для получения уведомлений.

    Пример:

    curl --location --request POST 'https://test.com/notif.php' --header 'Accept: application/json' --header 'Content-type: application/json' --header 'Cookie: laravel_session=qePlTipWuv7zuRn0WTp9StDVFv2nAREe30gte7zk' --data-raw '{"bill":{"siteId":"2304","billId":"151989213804fhr7i272a2","amount":{"value":"1","currency":"RUB"},"status":{"value":"PAID","datetime":"2020-07-28T11:16:12"},"customer":{},"customFields":{},"creationDateTime":"2020-07-28T11:15:39","expirationDateTime":"2020-08-28T11:15:39+03:00"},"version":"1"}'

  3. Если вы используете сторонние сервисы, создающие готовые эндпоинты для приема запросов по https (например, Google Apps Scripts), убедитесь, что можно отправлять запросы в ваш сервис без дополнительной авторизации (в том числе анонимным пользователям).
  4. Если вы не используете облачные сервисы для приема уведомлений вроде amazon или heroku, а настраивали свой вебсервер и ssl в нем самостоятельно, проверьте ssl сертификат.

    Если ssl сертификат для установления соединения по https выпущен не общеизвестным доверенным центром сертификации (например, Comodo, Verisign, Thawte и т.п.), проверьте, что ваш сервер при установке соединения отправляет полную цепочку сертификатов, включая доверенный корневой центр сертификации в начале цепочки.

    Убедиться в том, что сервер присылает полную цепочку сертификатов, можно при помощи утилиты командной строки openssl, пример есть здесь.

    Полную цепочку сертификатов вы можете загрузить на сайте центра сертификации, выпустившего ваш сертификат.

  5. Если не получается разобраться самостоятельно – отправьте нам ссылку на счет или номер счета в Telegram-бот.

Шаг 9*. Проверка подписи уведомлений

Настоятельно рекомендуем проверять уведомления на подлинность, т.к. мы не несем ответственность, если будут приходить поддельные уведомления от мошенников.

Формат уведомлений описан в документации.

Данные приходят в теле запроса (body). Данные запроса хранятся в формате JSON.

Для проверки подлинности используется механизм цифровой подписи. Подпись уведомления отправляется в HTTP-заголовке X-Api-Signature-SHA256. Для формирования подписи используется механизм проверки целостности HMAC с хэш-функцией SHA256.

Пример

const validSignatureFromNotificationServer =
      '07e0ebb10916d97760c196034105d010607a6c6b7d72bfa1c3451448ac484a3b';

const notificationData = {
    bill: {
        siteId: '270304',
        billId: 'cc961e8d-d4d6-4f02-b737-2297e51fb48e',
        amount: {value: 1, currency: 'RUB'},
        status: {value: 'PAID'}
    },
    version: '3'
};

const merchantSecret = 'eyJ2ZXJzaW9uIjoicmVzdF92MyIsImRhdGEiOnsibWVyY2hhbnRfaWQiOjUyNjgxMiwiYXBpX3VzZXJfaWQiOjcxNjI2MTk3LCJzZWNyZXQiOiJmZjBiZmJiM2UxYzc0MjY3YjIyZDIzOGYzMDBkNDhlYjhiNTnONPININONPN090MTg5Z**********************';

qiwiApi.checkNotificationSignature(
    validSignatureFromNotificationServer, notificationData, merchantSecret
); // true
<?php

$validSignatureFromNotificationServer = '07e0ebb10916d97760c196034105d010607a6c6b7d72bfa1c3451448ac484a3b';
$notificationData = [
  'bill' => [
    'siteId' => '270304',
    'billId' => 'cc961e8d-d4d6-4f02-b737-2297e51fb48e',
    'amount' => ['value' => 1, 'currency' => 'RUB'],
    'status' => ['value' => 'PAID']
  ],
  'version' => '3'
];
$merchantSecret = 'eyJ2ZXJzaW9uIjoicmVzdF92MyIsImRhdGEiOnsibWVyY2hhbnRfaWQiOjUyNjgxMiwiYXBpX3VzZXJfaWQiOjcxNjI2MTk3LCJzZWNyZXQiOiJmZjBiZmJiM2UxYzc0MjY3YjIyZDIzOGYzMDBkNDhlYjhiNTnONPININONPN090MTg5Z**********************';

/** @var \Qiwi\Api\BillPayments $billPayments */
$billPayments->checkNotificationSignature(
  $validSignatureFromNotificationServer, $notificationData, $merchantSecret
); // true

?>
String merchantSecret = "eyJ2ZXJzaW9uIjoicmVzdF92MyIsImRhdGEiOnsibWVyY2hhbnRfaWQiOjUyNjgxMiwiYXBpX3VzZXJfaWQiOjcxNjI2MTk3LCJzZWNyZXQiOiJmZjBiZmJiM2UxYzc0MjY3YjIyZDIzOGYzMDBkNDhlYjhiNTnONPININONPN090MTg5Z**********************";
Notification notification = new Notification(
        new Bill(
                "270304",
                "cc961e8d-d4d6-4f02-b737-2297e51fb48e",
                new MoneyAmount(
                        BigDecimal.ONE,
                        Currency.getInstance("RUB")
                ),
                BillStatus.PAID
        ),
        "3"
);
String validSignature = "07e0ebb10916d97760c196034105d010607a6c6b7d72bfa1c3451448ac484a3b";

BillPaymentsUtils.checkNotificationSignature(validSignature, notification, merchantSecret); //true
Assert.IsTrue(
    condition: BillPaymentsUtils.CheckNotificationSignature(
        validSignature: "07e0ebb10916d97760c196034105d010607a6c6b7d72bfa1c3451448ac484a3b",
        notification: new Notification
        {
            Bill = new Bill
            {
                SiteId = "270304",
                BillId = "cc961e8d-d4d6-4f02-b737-2297e51fb48e",
                Amount = new MoneyAmount
                {
                    ValueDecimal = 1m,
                    CurrencyEnum = CurrencyEnum.Rub
                },
                Status = new BillStatus
                {
                    ValueEnum = BillStatusEnum.Paid
                }
            ),
            Version = "1"
        },
        merchantSecret: "eyJ2ZXJzaW9uIjoicmVzdF92MyIsImRhdGEiOnsibWVyY2hhbnRfaWQiOjUyNjgxMiwiYXBpX3VzZXJfaWQiOjcxNjI2MTk3LCJzZWNyZXQiOiJmZjBiZmJiM2UxYzc0MjY3YjIyZDIzOGYzMDBkNDhlYjhiNTnONPININONPN090MTg5Z**********************"
    )
);

Алгоритм проверки подписи:

  1. Объединить значения следующих параметров уведомления в одну строку с разделителем |:

    invoice_parameters = {amount.currency}|{amount.value}|{billId}|{siteId}|{status.value}

    где {*} – значение параметра. Все значения при проверке подписи должны трактоваться как строки.

  2. Вычислить HMAC-хэш c алгоритмом хэширования SHA256:

    hash = HMAС(SHA256, invoice_parameters, secret_key)

    где: secret_key – секретный ключ, при помощи которого был выставлен счёт; invoice_parameters – строка из п.1.

  3. Сравнить значение заголовка X-Api-Signature-SHA256 с результатом из п.2.

В разрабатываемом коде заведите константу merchantSecret и присвойте ей значение секретного ключа, который выпустили в личном кабинете. Значение должно быть то же самое, что в константе SECRET_KEY на шаге авторизации.

Проверьте, что ключ скопирован полностью, в конце должен быть знак "равно" =.

Шаг 10*. Обработка уведомлений - отправка 200 OK

HTTP/1.1 200 OK
Content-Type: application/json

{
 "error":"0"
}

После проверки уведомлений на подлинность отправьте QIWI ответ на уведомление успешным статусом.

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

Шаг 11*. Проверка статуса перевода по счету

Пример

const billId = 'cc961e8d-d4d6-4f02-b737-2297e51fb48e';

qiwiApi.getBillInfo(billId).then( data => {
    //do with data
});
<?php

$billId = '4fa5cb2a-942e-4e67-b552-ff10c71d6f8d';

/** @var \Qiwi\Api\BillPayments $billPayments */
$response = $billPayments->getBillInfo($billId);

print_r($response);

?>
String billId = "fcb40a23-6733-4cf3-bacf-8e425fd1fc71";
BillResponse response = client.getBillInfo(billId);
client.GetBillInfo(
    billId: "fcb40a23-6733-4cf3-bacf-8e425fd1fc71"
);
curl --location --request GET 'https://api.qiwi.com/partner/bill/v1/bills/cc961e8d-d4d6-4f02-b737-2297e51fb48e' \
--header 'accept: application/json' \
--header 'Authorization: Bearer eyJ2ZXJzaW9uIjoicmVzdF92MyIsImRhdGEiOnsibWVyY2hhbnRfaWQiOjIwNDIsImFwaV91c2VyX2lkIjo1NjYwMzk3Miwic2VjcmV0IjoiQjIwODlDNkI5Q0NDNTdCNDQzNGHJK43JFJDK595FJFJMjlCRkFFRDM5OE***********************'

Ответ

{
  "siteId": "270305",
  "billId": "cc961e8d-d4d6-4f02-b737-2297e51fb48e",
  "amount": {
    "currency": "RUB",
    "value": "200.34"
  },
  "status": {
    "value": "WAITING",
    "changedDateTime": "2020-07-29T19:31:06.846+03:00"
  },
  "comment": "test",
  "creationDateTime": "2020-07-28T19:31:06.846+03:00",
  "expirationDateTime": "2020-08-8T19:31:06.846+03:00",
  "payUrl": "https://oplata.qiwi.com/form/?invoice_uid=ee3ad91d-cfb8-4dbf-8449-b6859fdfec3c"
}
Array
(
    [siteId] => 270305
    [billId] => 4fa5cb2a-942e-4e67-b552-ff10c71d6f8d
    [amount] => Array
        (
            [currency] => RUB
            [value] => 200.34
        )

    [status] => Array
        (
            [value] => WAITING
            [changedDateTime] => 2018-07-12T10:31:06.846+03:00
        )

    [comment] => test
    [creationDateTime] => 2020-07-28T19:31:06.846+03:00
    [expirationDateTime] => 2020-08-28T19:31:06.846+03:00
    [payUrl] => https://oplata.qiwi.com/form/?invoice_uid=ee3ad91d-cfb8-4dbf-8449-b6859fdfec3c
)
{
  "siteId": "270304",
  "billId": "fcb40a23-6733-4cf3-bacf-8e425fd1fc71",
  "amount": {
    "value": "199.90",
    "currency": "RUB"
  },
  "status": {
    "value": "WAITING",
    "changedDateTime": "2020-07-28T16:03:09.062Z"
  },
  "comment": "test",
  "customer": {
    "email": "example@mail.org",
    "account": "349d5978-bccc-4e10-be7e-3ca0808237b7",
    "phone": "79123456789"
  },
  "creationDateTime": "2020-07-28T16:03:09.062Z",
  "expirationDateTime": "2020-08-28T16:03:08.668Z",
  "payUrl": "https://oplata.qiwi.com/form/?invoice_uid=b77618b4-746c-485f-8bb8-fff43ddef114",
  "customFields": {
    "apiClient": "java_sdk",
    "apiClientVersion": "1.0.0"
  }
}
new BillResponse
{
    SiteId = "270304",
    BillId = "fcb40a23-6733-4cf3-bacf-8e425fd1fc71",
    Amount = new MoneyAmount
    {
        ValueString = "199.90",
        CurrencyString = "RUB"
    },
    Status = new ResponseStatus
    {
        ValueString: "WAITING",
        ChangedDateTime: BillPaymentsUtils.ParseDate("2020-07-28T16:03:09+03:00")
    },
    Comment = "test",
    Customer = new Customer
    {
        Email = "example@mail.org",
        Account = "349d5978-bccc-4e10-be7e-3ca0808237b7",
        Phone = "79123456789"
    },
    CreationDateTime = BillPaymentsUtils.ParseDate("2020-07-28T16:03:09+03:00"),
    ExpirationDateTime = BillPaymentsUtils.ParseDate("2020-08-28T16:03:08+03:00"),
    PayUrl = new Uri("https://oplata.qiwi.com/form/?invoice_uid=b77618b4-746c-485f-8bb8-fff43ddef114"),
    CustomFields = new CustomFields
    {
        ApiClient = "dotnet_sdk",
        ApiClientVersion = "0.1.0"
    }
};
{
    "siteId": "9hh4jb-00",
    "billId": "cc961e8d-d4d6-4f02-b737-2297e51fb48e",
    "amount": {
        "currency": "RUB",
        "value": "1.00"
    },
    "status": {
        "value": "WAITING",
        "changedDateTime": "2021-01-18T14:22:56.672+03:00"
    },
    "customer": {
        "email": "test@tester.com",
        "phone": "78710009999",
        "account": "454678"
    },
    "customFields": {
        "paySourcesFilter": "qw",
        "themeCode": "Yvan-YKaSh",
        "yourParam1": "64728940",
        "yourParam2": "order 678"
    },
    "comment": "Text comment",
    "creationDateTime": "2021-01-18T14:22:56.672+03:00",
    "expirationDateTime": "2025-12-10T09:02:00+03:00",
    "payUrl": "https://oplata.qiwi.com/form/?invoice_uid=aa0fa2bb-5452-47ca-9190-cd9c1a73718f"
}

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

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

Раздел документации с примерами проверки статуса оплаты счета находится здесь.

Реализуйте вызов метода getBillInfo. В параметрах необходимо передать идентификатор счета в вашей системе billId, в результате будет получен ответ со статусом счета.

Шаг 12. Бизнес-логика

Счет в своем жизненном цикле проходит следующие статусы оплаты:

Статус Описание Комментарий
WAITING Счет выставлен, ожидает оплаты Нефинальный, ожидание оплаты или истечения срока действия
PAID Счет оплачен Финальный (измениться не может)
REJECTED Счет отклонен Финальный (измениться не может)
EXPIRED Время жизни счета истекло. Счет не оплачен Финальный (измениться не может)

Опираясь на статус счета, полученный в уведомлении или при помощи поллинга статуса, доработайте бизнес-логику вашего сайта.

Например:

Поздравляем, интеграция с QIWI для получения платежей закончена!

Дополнительно. Шаг 13. Отмена неоплаченных счетов

Пример

const billId = '60418b7e-1e95-4ac0-936e-0b98d7a7fdae';

qiwiApi.cancelBill(billId).then( data => {
    //do with data
});
<?php

$billId = '60418b7e-1e95-4ac0-936e-0b98d7a7fdae';

/** @var \Qiwi\Api\BillPayments $billPayments */
$response = $billPayments->cancelBill($billId);

print_r($response);

?>
String billId = "fcb40a23-6733-4cf3-bacf-8e425fd1fc71";
BillResponse response = client.cancelBill(billId);
client.CancelBill(
    billId: "fcb40a23-6733-4cf3-bacf-8e425fd1fc71"
);
curl --location --request POST 'https://api.qiwi.com/partner/bill/v1/bills/cc961e8d-d4d6-4f02-b737-2297e51fb48e/reject' \
--header 'content-type: application/json' \
--header 'accept: application/json' \
--header 'Authorization: Bearer eyJ2ZXJzaW9uIjoicmVzdF92MyIsImRhdGEiOnsibWVyY2hhbnRfaWQiOjIwNDIsImFwaV91c2VyX2lkIjo1NjYwMzk3Miwic2VjcmV0IjoiQjIwODlDNkI5Q0NDNTdCNDQzNGHJK43JFJDK595FJFJMjlCRkFFRDM5OE***********************' \
--data-raw ''

Ответ

{
  "siteId": "270305",
  "billId": "60418b7e-1e95-4ac0-936e-0b98d7a7fdae",
  "amount": {
    "currency": "RUB",
    "value": "200.34"
  },
  "status": {
    "value": "REJECTED",
    "changedDateTime": "2018-07-12T10:32:17.595+03:00"
  },
  "comment": "test",
  "creationDateTime": "2018-07-12T10:32:17.481+03:00",
  "expirationDateTime": "2018-08-26T10:32:17.481+03:00",
  "payUrl": "https://oplata.qiwi.com/form/?invoice_uid=a3fe62b2-9962-4d9d-9025-0766fb492546"
}
Array
(
    [siteId] => 270305
    [billId] => 60418b7e-1e95-4ac0-936e-0b98d7a7fdae
    [amount] => Array
        (
            [currency] => RUB
            [value] => 200.34
        )

    [status] => Array
        (
            [value] => REJECTED
            [changedDateTime] => 2018-07-12T10:32:17.595+03:00
        )

    [comment] => test
    [creationDateTime] => 2018-07-12T10:32:17.481+03:00
    [expirationDateTime] => 2018-08-26T10:32:17.481+03:00
    [payUrl] => https://oplata.qiwi.com/form/?invoice_uid=a3fe62b2-9962-4d9d-9025-0766fb492546
)
{
  "siteId": "270304",
  "billId": "fcb40a23-6733-4cf3-bacf-8e425fd1fc71",
  "amount": {
    "value": "199.90",
    "currency": "RUB"
  },
  "status": {
    "value": "REJECTED",
    "changedDateTime": "2018-11-03T16:03:09.062Z"
  },
  "comment": "test",
  "customer": {
    "email": "example@mail.org",
    "account": "349d5978-bccc-4e10-be7e-3ca0808237b7",
    "phone": "79123456789"
  },
  "creationDateTime": "2018-11-03T16:03:09.062Z",
  "expirationDateTime": "2018-12-18T16:03:08.668Z",
  "payUrl": "https://oplata.qiwi.com/form/?invoice_uid=b77618b4-746c-485f-8bb8-fff43ddef114",
  "customFields": {
    "apiClient": "java_sdk",
    "apiClientVersion": "1.0.0"
  }
}
new BillResponse
{
    SiteId = "270304",
    BillId = "fcb40a23-6733-4cf3-bacf-8e425fd1fc71",
    Amount = new MoneyAmount
    {
        ValueString = "199.90",
        CurrencyString = "RUB"
    },
    Status = new ResponseStatus
    {
        ValueString: "REJECTED",
        ChangedDateTime: BillPaymentsUtils.ParseDate("2018-11-03T16:03:09+03:00")
    },
    Comment = "test",
    Customer = new Customer
    {
        Email = "example@mail.org",
        Account = "349d5978-bccc-4e10-be7e-3ca0808237b7",
        Phone = "79123456789"
    },
    CreationDateTime = BillPaymentsUtils.ParseDate("2018-11-03T16:03:09+03:00"),
    ExpirationDateTime = BillPaymentsUtils.ParseDate("2018-12-18T16:03:08+03:00"),
    PayUrl = new Uri("https://oplata.qiwi.com/form/?invoice_uid=b77618b4-746c-485f-8bb8-fff43ddef114"),
    CustomFields = new CustomFields
    {
        ApiClient = "dotnet_sdk",
        ApiClientVersion = "0.1.0"
    }
};
{
    "siteId": "9hh4jb-00",
    "billId": "cc961e8d-d4d6-4f02-b737-2297e51fb48e",
    "amount": {
        "currency": "RUB",
        "value": "1.00"
    },
    "status": {
        "value": "REJECTED",
        "changedDateTime": "2021-01-18T14:36:17.65+03:00"
    },
    "customer": {
        "email": "test@tester.com",
        "phone": "78710009999",
        "account": "454678"
    },
    "customFields": {
        "paySourcesFilter": "qw",
        "themeCode": "Yvan-YKaSh",
        "yourParam1": "64728940",
        "yourParam2": "order 678"
    },
    "comment": "Text comment",
    "creationDateTime": "2021-01-18T14:22:56.672+03:00",
    "expirationDateTime": "2025-12-10T09:02:00+03:00",
    "payUrl": "https://oplata.qiwi.com/form/?invoice_uid=aa0fa2bb-5452-47ca-9190-cd9c1a73718f"
}

Вы можете отменять неоплаченные счета самостоятельно, используя метод cancelBill.

Раздел документации с примерами запросов для отмены неоплаченных счетов находится здесь.