Pay-On-Delivery Payments
Last update: 2018-07-03
This API is an extension of the Pull Payments API to be implemented by merchant (an online store or platform / marketplace) that sells products) to support QIWI Pull Payments with postponed payments. Postponed payment allows users to buy items and make payment later on delivery via QIWI.
Pay-On-Delivery REST API
Last update: 2018-06-27
Invoicing Operation Flow
-
User submits an order on the merchant’s website.
-
Merchant service issues invoice.
-
Merchant redirects the user to QIWI Pay-On-Delivery checkout page to pay for the invoice.
-
If the merchant enables notifications, then its service receives a notification from QIWI Wallet system once invoice is paid or cancelled by the user. Authorization on the merchant's side is required for notifications.
-
In any case, merchant can request current status of the invoice, or cancel invoice (provided that the user has not initiated payment yet).
-
When the invoice payment is confirmed, merchant delivers ordered services/goods.
Authorization
Pay-On-Delivery REST API requests are authorized through HTTP Basic-authorization with API ID and API password. Header is Authorization
string and its value is Basic Base64(API_ID:API_PASSWORD)
.
user@server:~$ curl "server_URL"
--header "Authorization: Basic MjMyNDQxMjM6NDUzRmRnZDQ0Mw=="
Authorization and form data
Data can be obtained on ishop.qiwi.com
Parameter | Description | Type | Required |
---|---|---|---|
API_ID | Provider API identifier for authorization | Integer | + |
API_PASSWORD | API password for authorization | String | + |
Shop ID | Numeric identifier of the provider's service | Integer | + |
Issuing Invoice
Creates new invoice to the specified phone number (wallet ID in QIWI Wallet).
Request → PUT
user@server:~$ curl "https://w.qiwi.com/api/v2/prv/373712/bills/BILL_1"
-X PUT --header "Accept: text/json" --header "Authorization: Basic ***"
-d "user=tel%3A%2B79161234567&amount=10.00&ccy=RUB&comment=test&lifetime=2016-09-25T15:00:00&pay_source=cod&extras%5Border_id%5D=abcde12345"
URL https://w.qiwi.com/api/v2/prv/prv_id/bills/bill_id
-
Parameters are in the PUT-request URL pathname:
- prv_id - merchant’s Shop ID (numeric value, as displayed in "Shop ID" parameter of "Protocols Settings" section of ishop.qiwi.com web site)
- bill_id - unique invoice identifier generated by the merchant (non-empty string of up to 200 characters). Uniqueness means that the identifier must not coincide with any of previously issued invoices of the merchant. Regular expression for the identifier: ^[_0-9a-zA-Z]{1,200}$
HEADERS
- Accept: text/json or Accept: application/json - JSON response
- Accept: text/xml or Accept: application/xml - XML response
- Content-type: application/x-www-form-urlencoded; charset=utf-8
- Authorization: Basic ***
Parameters
Parameters are sent in the request body as formdata.
Parameter | Description | Type | Required |
---|---|---|---|
user | The QIWI Wallet user’s ID, to whom the invoice is issued. It is the user’s phone number with tel: prefix |
String(20) | Y |
amount | The invoice amount. The number is rounded down with two decimal places | Number(6.2) | Y |
ccy | Invoice currency identifier (Alpha-3 ISO 4217 code). Depends on currencies allowed for the merchant. The following values are supported: RUB, EUR, USD, KZT | String(3) | Y |
comment | Comment to the invoice | String(255) | Y |
lifetime | Date and time up to which the invoice is available for payment. If the invoice is not paid by this date it will become void and will be assigned a final status. Important! Invoice will be automatically expired when 45 days is passed after the invoicing date |
YYYY-MM-DDThh:mm:ss URL-encoded |
Y |
pay_source | If the value is mobile the user’s MNO balance will be used as a funding source. If the value is qw , any other funding source is used available in QIWI Wallet system for the user. If parameter isn’t present, value qw is assumed |
cod string |
Y |
prv_name | Merchant’s name | String(100) | N |
extras[order_id] | Extra-parameter of the request - Order ID in the merchant's information system for the invoice. | ^.{1,255}$ String |
Y |
Response ←
HTTP/1.1 200 OK
Content-Type: text/json
{
"response": {
"result_code": 0,
"bill": {
"bill_id": "BILL_1",
"amount": "10.00",
"ccy": "RUB",
"status": "waiting",
"error": 0,
"user": "tel:+79031234567",
"comment": "test"
}
}
}
HTTP/1.1 401 Unauthorized
Content-Type: text/json
{
"response": {
"result_code": 150,
"description": "Authorization failed"
}
}
HTTP/1.1 200 OK
Content-Type: text/xml
<response>
<result_code>0</result_code>
<bill>
<bill_id>BILL-1</bill_id>
<amount>10.00</amount>
<originAmount>10.00</originAmount>
<ccy>RUB</ccy>
<originCcy>RUB</originCcy>
<status>rejected<status>
<error>0</error>
<user>tel:+79161234567</user>
<comment>test</comment>
</bill>
</response>
HTTP/1.1 401 Unauthorized
Content-Type: text/xml
<response>
<result_code>341</result_code>
<description>Authorization is failed</description>
</response>
Response format depends on Accept
header in the request:
HEADERS
- Accept: text/json or Accept: application/json - response in JSON
- Accept: text/xml or Accept: application/xml - response in XML
Parameters
Parameter | Type | Description |
---|---|---|
result_code | Integer | Error code |
description | String | Error description. Returned when result_code is non-zero. |
bill | Object | Bill data. Returned when result_code is zero (successful operation). Parameters: |
bill.bill_id | String | Unique invoice identifier generated by the merchant |
bill.amount | String | The invoice amount. The number is rounded down with two decimal places. |
bill.ccy | String | Currency identifier of the invoice (Alpha-3 ISO 4217 code) |
bill.status | String | Current invoice status |
bill.error | Integer | Always 0 , means successful operation |
bill.user | String | The QIWI Wallet user’s ID, to whom the invoice is issued. It is the user’s phone number with tel: prefix. |
bill.comment | String | Comment to the invoice |
Checking Invoice Status
Get payment status of the invoice.
user@server:~$ curl "https://w.qiwi.com/api/v2/prv/373712/bills/sdf23452435"
--header "Authorization: Basic ***" --header "Accept: text/json"
Request → GET
URL https://w.qiwi.com/api/v2/prv/prv_id/bills/bill_id
-
Parameters are in the GET-request URL pathname:
- prv_id - merchant’s Shop ID (numeric value, as displayed in "Shop ID" parameter of "Protocols Settings" section of ishop.qiwi.com web site)
- bill_id - invoice identifier
HEADERS
- Accept: text/json or Accept: application/json - JSON response
- Accept: text/xml or Accept: application/xml - XML response
- Authorization: Basic ***
Response ←
HTTP/1.1 200 OK
Content-Type: text/json
{
"response": {
"result_code": 0,
"bill": {
"bill_id": "BILL_1",
"amount": "10.00",
"originAmount": "10.00",
"ccy": "RUB",
"originCcy": "RUB",
"status": "waiting",
"error": 0,
"user": "tel:+79031234567",
"comment": "test"
}
}
}
HTTP/1.1 401 Unauthorized
Content-Type: text/json
{
"response": {
"result_code": 150,
"description": "Authorization failed"
}
}
HTTP/1.1 200 OK
Content-Type: text/xml
<response>
<result_code>0</result_code>
<bill>
<bill_id>BILL_1</bill_id>
<amount>10.00</amount>
<originAmount>10.00</originAmount>
<ccy>RUB</ccy>
<originCcy>RUB</originCcy>
<status>rejected<status>
<error>0</error>
<user>tel:+79161234567</user>
<comment>test</comment>
</bill>
</response>
HTTP/1.1 401 Unauthorized
Content-Type: text/xml
<response>
<result_code>341</result_code>
<description>Authorization is failed</description>
</response>
Response format depends on Accept
header in the request:
HEADERS
- Accept: text/json or Accept: application/json - response in JSON
- Accept: text/xml or Accept: application/xml - response in XML
Parameters
Parameter | Type | Description |
---|---|---|
result_code | Integer | Error code |
description | String | Error description. Returned when result_code is non-zero. |
bill | Object | Bill data. Returned when result_code is zero (successful operation). Parameters: |
bill.bill_id | String | Unique invoice identifier generated by the merchant |
bill.amount | String | The invoice amount. The number is rounded down with two decimal places. |
bill.originAmount | String | The amount taken from the balance when the invoice get paid (see originCcy parameter). The number is rounded down with two decimal places. Returns for invoices when the user initiates payment. |
bill.ccy | String | Currency identifier of the invoice (Alpha-3 ISO 4217 code) |
bill.originCcy | String | Currency identifier of the balance from which the invoice is paid (Alpha-3 ISO 4217 code). Returns for invoices when the user initiates payment. |
bill.status | String | Current invoice status |
bill.error | Integer | Always 0 , means successful operation |
bill.user | String | The QIWI Wallet user’s ID, to whom the invoice is issued. It is the user’s phone number with tel: prefix. |
bill.comment | String | Comment to the invoice |
Cancelling Unpaid Invoice
Сancels unpaid invoice provided that its lifetime has not expired yet.
user@server:~$ curl -X PATCH
--header "Authorization: Basic ***" --header "Accept: text/json"
"https://w.qiwi.com/api/v2/prv/373712/bills/BILL_1"
-d "status=rejected"
Request → PATCH
URL https://w.qiwi.com/api/v2/prv/prv_id/bills/bill_id
-
Parameters are in the PATCH-request URL pathname:
- prv_id - merchant’s Shop ID (numeric value, as displayed in "Shop ID" parameter of "Protocols Settings" section of ishop.qiwi.com web site)
- bill_id - invoice identifier
-
Parameter is in the request body.
- status - rejected (cancelling status).
HEADERS
- Accept: text/json or Accept: application/json - JSON response
- Accept: text/xml or Accept: application/xml - XML response
- Content-type: application/x-www-form-urlencoded; charset=utf-8
- Authorization: Basic ***
Response ←
HTTP/1.1 200 OK
Content-Type: text/json
{
"response": {
"result_code": 0,
"bill": {
"bill_id": "BILL_1",
"amount": "10.00",
"ccy": "RUB",
"status": "rejected",
"error": 0,
"user": "tel:+79031234567",
"comment": "test"
}
}
}
HTTP/1.1 401 Unauthorized
Content-Type: text/json
{
"response": {
"result_code": 150,
"description": "Authorization failed"
}
}
HTTP/1.1 200 OK
Content-Type: text/xml
<response>
<result_code>0</result_code>
<bill>
<bill_id>BILL_1</bill_id>
<amount>10.00</amount>
<ccy>RUB</ccy>
<status>rejected<status>
<error>0</error>
<user>tel:+79161234567</user>
<comment>test</comment>
</bill>
</response>
HTTP/1.1 401 Unauthorized
Content-Type: text/xml
<response>
<result_code>341</result_code>
<description>Authorization is failed</description>
</response>
Response format depends on Accept
header in the request:
HEADERS
- Accept: text/json or Accept: application/json - response in JSON
- Accept: text/xml or Accept: application/xml - response in XML
Parameters
Parameter | Type | Description |
---|---|---|
result_code | Integer | Error code |
description | String | Error description. Returned when result_code is non-zero. |
bill | Object | Invoice data. Returned when result_code is zero (successful operation). Parameters: |
bill.bill_id | String | Unique invoice identifier generated by the merchant |
bill.amount | String | The invoice amount. The number is rounded down with two decimal places. |
bill.ccy | String | Currency identifier of the invoice (Alpha-3 ISO 4217 code) |
bill.status | String | Rejected invoice status |
bill.error | Integer | Always 0 , means successful operation |
bill.user | String | The QIWI Wallet user’s ID, to whom the invoice is issued. It is the user’s phone number with tel: prefix. |
bill.comment | String | Comment to the invoice |
Pay-On-Delivery Purchase Cancelling
Merchant can process a full refund of a purchase cancelled by user before delivering. Refund processes to QIWI using the PUT-request described below. This request creates a reversed transaction for the initial one.
Operation Flow
- To cancel the undelivered purchase amount, merchant has to send a request for purchase cancel before delivery to QIWI server.
- To make sure that the purchase cancel operation has been successfully processed merchant can periodically request the purchase cancel operation status until the final status is received.
Request → PUT
user@server:~$ curl "https://w.qiwi.com/api/v2/prv/373712/bills/BILL_1/refund/REF1"
-v -w "%{http_code}"
-X PUT --header "Accept: text/json"
--header "Authorization: Basic ***"
--header "Content-type: application/x-www-form-urlencoded; charset=utf-8"
-d "amount=5.0"
URL https://w.qiwi.com/api/v2/prv/prv_id/bills/bill_id/refund/refund_id
-
Parameters are in the URL pathname:
- prv_id - merchant’s Shop ID (numeric value, as displayed in "Shop ID" parameter of "Protocols Settings" section of ishop.qiwi.com web site)
- bill_id - identifier of the invoice to be cancelled before purchase
- refund_id - the purchase cancel operation identifier for the invoice {bill_id} (string of 1 to 9 symbols – any 0-9 digits and upper/lower Latin letters)
-
Parameter is in the request body:
- amount - the purchase cancel operation amount. It should be equal to the amount of the initial transaction.
HEADERS
- Accept: text/json or Accept: application/json - JSON response
- Accept: text/xml or Accept: application/xml - XML response
- Content-type: application/x-www-form-urlencoded; charset=utf-8
- Authorization: Basic ***
Response ←
HTTP/1.1 200 OK
Content-Type: text/json
{
"response": {
"result_code": 0,
"refund": {
"refund_id": "REF1",
"amount": "5.00",
"status": "success",
"error": 0
}
}
}
HTTP/1.1 401 Unauthorized
Content-Type: text/json
{
"response": {
"result_code": 150,
"description": "Authorization failed"
}
}
HTTP/1.1 200 OK
Content-Type: text/xml
<response>
<result_code>0</result_code>
<refund>
<refund_id>REF1</refund_id>
<amount>5.0</amount>
<status>success<status>
<error>0</error>
</refund>
</response>
HTTP/1.1 401 Unauthorized
Content-Type: text/xml
<response>
<result_code>341</result_code>
<description>Authorization is failed</description>
</response>
HEADERS
- Accept: text/json or Accept: application/json - response in JSON
- Accept: text/xml or Accept: application/xml - response in XML
Parameters
Parameter | Type | Description |
---|---|---|
result_code | Integer | Error code |
description | String | Error description. Returned when result_code is non-zero. |
refund | Object | Refund data. Returned when result_code is zero (successful operation). Parameters: |
refund.refund_id | String | The purchase cancel operation identifier, unique number in a series of refunds processed for a particular invoice |
refund.amount | String | The actual amount of the purchase cancel operation. The positive number that is rounded down with two decimal places. |
refund.status | String | Current refund status |
refund.error | Integer | Error code. Important! When the amount of purchase cancel operation exceeds the initial invoice amount, error code 242 is returned. |
Pay-On-Delivery Purchase Cancelling Status Verification
Merchant can verify status of the purchase cancel operation by this method. It returns current status of the purchase cancel operation.
Request → GET
user@server:~$ curl "https://w.qiwi.com/api/v2/prv/373712/bills/BILL_1/refund/REF1"
-v -w "%{http_code}"
--header "Accept: text/json" --header "Authorization: Basic ***"
URL https://w.qiwi.com/api/v2/prv/prv_id/bills/bill_id/refund/refund_id
-
Parameters are in the URL pathname:
- prv_id - merchant’s Shop ID (numeric value, as displayed in Shop ID parameter of Protocols details section of ishop.qiwi.com web site)
- bill_id - invoice identifier
- refund_id - refund identifier, a number specific to a series of refunds for the invoice {bill_id} (string of 1 to 9 symbols – any 0-9 digits and upper/lower Latin letters)
HEADERS
- Accept: text/json or Accept: application/json - JSON response
- Accept: text/xml or Accept: application/xml - XML response
- Authorization: Basic ***
Response ←
HTTP/1.1 200 OK
Content-Type: text/json
{
"response": {
"result_code": 0,
"refund": {
"refund_id": "REF1",
"amount": "5.00",
"status": "success",
"error": 0
}
}
}
HTTP/1.1 401 Unauthorized
Content-Type: text/json
{
"response": {
"result_code": 150,
"description": "Authorization failed"
}
}
HTTP/1.1 200 OK
Content-Type: text/xml
<response>
<result_code>0</result_code>
<refund>
<refund_id>REF1</refund_id>
<amount>5.0</amount>
<status>success<status>
<error>0</error>
</refund>
</response>
HTTP/1.1 401 Unauthorized
Content-Type: text/xml
<response>
<result_code>341</result_code>
<description>Authorization is failed</description>
</response>
HEADERS
- Accept: text/json or Accept: application/json - response in JSON
- Accept: text/xml or Accept: application/xml - response in XML
Parameters
Parameter | Type | Description |
---|---|---|
result_code | Integer | Error code |
description | String | Error description. Returned when result_code is non-zero. |
refund | Object | Refund data. Returned when result_code is zero (successful operation). Parameters: |
refund.refund_id | String | The purchase cancel operation identifier |
refund.amount | String | The actual amount of the purchase cancel operation. The positive number that is rounded down with two decimal places. |
refund.status | String | Current purchase cancel operation status |
refund.error | Integer | Error code. Important! When the amount of purchase cancel operation exceeds the initial invoice amount, error code 242 is returned. |
Operation Statuses
Last update: 2018-06-27
Invoice Status
Status | Description | Final |
---|---|---|
waiting | Invoice issued, pending payment | N |
paid | Invoice has been paid | Y |
rejected | Invoice has been rejected | Y |
unpaid | Payment processing error. Invoice has not been paid | Y |
expired | Invoice expired. Invoice has not been paid | Y |
Purchase Cancel Operation Status
Status | Description | Final |
---|---|---|
processing | Payment refund is pending | N |
success | Payment refund is successful | Y |
fail | Payment refund is unsuccessful | Y |
Error Codes
Last update: 2018-06-27
Code | Description | Fatal |
---|---|---|
0 | Success | Unrelated |
5 | Incorrect data in the request parameters | Y |
13 | Server is busy, try again later | N |
78 | Operation is forbidden | Y |
150 | Authorization error (e.g. invalid login/password) | Y |
152 | Protocol is not enabled or protocol is disabled | N |
155 | This merchant’s identifier (API ID) is blocked | Y |
210 | Invoice not found | Y |
215 | Invoice with this bill_id already exists |
Y |
241 | Invoice amount is less than allowed | Y |
242 | Invoice amount is greater than allowed. Also returns to purchase cancel operation request when the amount of refund exceeds the initial invoice amount | Y |
298 | User not registered | Y |
300 | Technical error | N |
303 | Wrong phone number | Y |
316 | Authorization from the blocked merchant | N |
319 | No rights for the operation | N |
339 | IP-addresses blocked | Y |
341 | Required parameter is incorrectly specified or absent in the request | Y |
700 | Monthly limit on operations is exceeded | Y |
774 | QIWI Wallet user account temporarily blocked | Y |
1001 | Currency is not allowed for the merchant | Y |
1003 | No convert rate for these currencies | N |
1019 | Unable to determine wireless operator for MNO balance payment | Y |
1419 | Invoice was already payed | Y |
Pay-On-Delivery Checkout Page
Last update: 2018-06-27
To use Pay-On-Delivery scenario, merchant redirects QIWI user to Pay-On-Delivery checkout page. To redirect, HTTP GET-request is used to the URL https://payondelivery.qiwi.com/.
QIWI Pay-On-Delivery Checkout page
GET /?shop_id=2042&transaction=Bill_1&order_id=abcde12345& phone=79161111111&sub_id=Max198353& success_url=http%3A%2F%2Fgoogle.com&fail_url=http%3A%2F%2Fwww.bing.com& sig=9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 HTTP/1.1
Host: payondelivery.qiwi.com
Request → REDIRECT
URL https://payondelivery.qiwi.com
Parameters
Parameter | Type & RegExp | Description | Required |
---|---|---|---|
shop_id | Integer, ^[0-9]{1,64}$ |
Merchant’s ID in Pay-On-Delivery system, provided upon merchant's integration. | Y |
transaction | string, ^[_0-9a-zA-Z]{1,200}$ |
Payment ID generated by the merchant, corresponds to bill_id parameter used to create the invoice. | Y |
order_id | string, ^.{1,255}$ |
Order ID in the merchant's information system for the invoice. | Y |
phone | string, ^[0-9]{10,11}$ |
The user’s phone number (without "+" symbol). | Y |
sub_id | string, ^.{1,255}$ |
Unique user ID on merchant’s side. | Y |
sig | string, ^[0-9a-z]{64}$ |
Signature of the request. It is calculated as SHA256 hash function for the string of concatenated parameter: phone +shop_id + order_id + transaction + key , where values of corresponding parameters are taken from the GET-request and key is a secret string. |
Y |
successUrl | URL-encoded string, (?i)^(http|https):\/\/.+$ |
The URL to which the payer will be redirected when invoice is paid | Y |
failUrl | URL-encoded string, (?i)^(http|https):\/\/.+$ |
The URL to which the payer will be redirected when invoice is not paid | Y |
Redirection to Merchant Site
After initiation of the payment, the user is automatically returned back to the merchant's site:
- When the invoice is successfully paid – to the hyperlink specified in
success_url
, - When the invoice payment error occurs – to the hyperlink specified in
fail_url
.
GET /ok.php?order_id=660&bill_id=test_5958&amount=746.47&ccy=RUB& checksum=6fde5fdcefe98569496c079b2fcb8373f92ad6755e2e941497f758fdeb8f7af5 HTTP/1.1
Host: merchant-shop.com
<?php
// Example of checksum generation
$hash_params = [
'amount' => '746.00',
'bill_id' => 'test_5958',
'ccy' => 'RUB',
'key' => 'secret string',
'order_id' => '660',
];
ksort($hash_params);
$checksum = hash('sha256', implode($hash_params));
?>
The following parameters are sent in the redirect URL:
Name | Type | Description |
---|---|---|
order_id | String | Order ID in the merchant's information system for the invoice |
bill_id | String | Invoice ID generated by the merchant, corresponds to bill_id parameter used to create the invoice. |
amount | A positive number rounded down to 2 decimal places after the comma | The invoice amount in rubles. The merchant has to send this amount to the logistic company as a sum of Pay-on-Delivery package |
ccy | String | Currency identifier (Alpha-3 ISO 4217) of the invoice |
checksum | String | Signature of the request. It is calculated as SHA256 hash function for the string of concatenated parameter sorted by their names: amount +bill_id + ccy +key +order_id where key is a secret key for the signature. |
Notifications
Last update: 2017-11-14
Notification is a POST-request (callback). The request's body contains all relevant data of the invoice serialized as HTTP-request parameters and encoded by UTF-8 plus parameter command=bill
.
Request → POST
Example
user@server:~$ curl "https://service.ru/qiwi-notify.php"
-v -w "%{http_code}"
-X POST --header "Accept: text/xml"
--header "Content-Type: application/x-www-form-urlencoded; charset=utf-8"
--Authorization: "Basic MjA0Mjp0ZXN0Cg=="
-d "bill_id=BILL-1%26status=paid%26amount=1.00%26user=tel%3A%2B79031811737%26prv_name=TEST%26ccy=RUB%26comment=test%26command=bill"
URL
HEADERS
- Authorization: Basic *** - for login/password authorization
- X-Api-Signature: *** - for digital signature authorization
- Accept: text/json
- Content-type: application/x-www-form-urlencoded
Parameters
Invoice parameters are in the request's body.
Parameter | Description | Type | Required |
---|---|---|---|
status | Current invoice status | String | Y |
amount | The invoice amount. The number is rounded down with two decimal places | Number(6.2) | Y |
user | The QIWI Wallet user’s ID, to whom the invoice is issued. It is the user’s phone number with "tel:" prefix | String | Y |
prv_name | Merchant’s site name specified on ishop.qiwi.com in "Settings"->"Contract/project details"->"Short name" section | String | Y |
ccy | Invoice currency identifier (Alpha-3 ISO 4217 code) | String(3) | Y |
comment | Comment to the invoice | String(255) | Y |
command | Always bill by default |
String | Y |
Response ←
HTTP/1.1 200 OK
Content-Type: text/xml
<?xml version="1.0"?>
<result>
<result_code>0</result_code>
</result>
Response must be in XML format.
HEADERS
- Content-type: text/xml
Parameters
XML Tag | Description |
---|---|
result | Grouping tag. Describes notification processing result. |
result_code | Notification result code (positive integer). We recommend that the result codes returned by the merchant be in accordance with Notification codes table. |
Authorization on Merchant's Server
Merchant's server should use basic-authorization or authorization by signature. Merchant may also use client SSL certificate verification (self-signed cerificates may be used as well). QIWI Wallet server certificate should be verified in HTTPS requests.
Basic authorization
POST /qiwi-notify.php HTTP/1.1
Accept: text/xml
Content-type: application/x-www-form-urlencoded
Authorization: Basic ***
Host: service.ru
command=bill&bill_id=BILL-1&status=paid&error=0&amount=1.00&user=tel%3A%2B79031811737&prv_name=Retail_Store&ccy=RUB&comment=test
The login is taken from Shop ID parameter. To obtain password, click on Change password button in Protocols details - REST-protocol section of QIWI partners web site.
Details
Authorization by signature
POST /qiwi-notify.php HTTP/1.1
Accept: text/xml
Content-type: application/x-www-form-urlencoded
X-Api-Signature: J4WNfNZd***V5mv2w=
Host: service.ru
command=bill&bill_id=LocalTest17&status=paid&error=0&amount=0.01&user=tel%3A%2B78000005122&prv_name=Test&ccy=RUB&comment=Some+Descriptor
<?php
function hexToStr($hex){
$string='';
for ($i=0; $i < strlen($hex)-1; $i+=2){
$string .= chr(hexdec($hex[$i].$hex[$i+1]));
}
return $string;
}
//Signature generation by key and string
function checkSign($key, $req){
$sign_hash = hash_hmac("sha1", $req, $key);
$sign_tr = hexToStr($sign_hash);
$sign = base64_encode($sign_tr);
return $sign;
}
//Sort POST-request parameters and return values
function getReqParams(){
$reqparams = "";
ksort($_POST);
foreach ($_POST as $param => $valuep) {
$reqparams = "$reqparams|$valuep";
}
return substr($reqparams,1);
}
//Take signature from the request
function getSign(){
$HEADERS = getallheaders();
foreach ($HEADERS as $header => $value) {
if ($header == 'X-Api-Signature') {
$SIGN_REQ = $value;
}
}
return $SIGN_REQ;
}
// Sort parameters
$Request = getReqParams();
// Notification password
$NOTIFY_PWD = "***";
// Get sign
$reqres = checkSign($NOTIFY_PWD, $Request);
// Get sign from the request
$SIGN_REQ = getSign();
if ($reqres == $SIGN_REQ) {
$error = 0;
}
else $error = 151;
//Response
header('Content-Type: text/xml');
$xmlres = <<<XML
<?xml version="1.0"?>
<result>
<result_code>$error</result_code>
</result>
XML;
echo $xmlres;
?>
The HTTP header X-Api-Signature
with signature is added to the POST-request. Signature is calculated as HMAC algorithm with SHA1-hash function.
- Parameters' separator is
|
. - Signed are all the parameters in the original invoice request.
- Parameters are in alphabetical order and UTF-8 byte-encoded.
- Secret key for signature is the password for notification basic-authorization.
Signature verification algorithm is as follows:
-
Prepare a string of all parameters values from the notification POST-request sorted in alphabetical order and separated by
|
:{parameter1}|{parameter2}|…
where
{parameter1}
is the value of the notification parameter. All values should be treated as strings. - Transform obtained string and password for the notification basic-authorization into bytes encoded in UTF-8.
-
Apply HMAC-SHA1 function:
hash = HMAС(SHA1, Notification_password_bytes, Invoice_parameters_bytes)
Where:Notification_password_bytes
– secret key (bytecoded notification password);Invoice_parameters_bytes
– bytecoded POST-request body;hash
– hash-function result.
- Transform HMAC-hash value into bytes with UTF-8 and Base64-encode it.
- Compare
X-Api-Signature
header's value with the result of step 4.
PHP Implementation Example
The given PHP example implements notification authorization by signature verification. Open the PHP tab on the right.
Notification Codes
Code | Description |
---|---|
0 | Success |
5 | The format of the request parameters is incorrect |
13 | Database connection error |
150 | Incorrect password |
151 | Signature authorization failed |
300 | Server connection error |