P2P Invoices
Terms of Service
To enable p2p-transfer service for individuals on your site, you need a QIWI wallet with Basic or Professional identification status. If your wallet has Anonymous status, pass identification with any means suitable for you:
- To get Basic status, you need to enter your passport information.
- To get Professional status, you need to pass identification on-site.
We recommend to get Professional status, as it applies higher value of limits for remains on your balance, payments and transfers amount per month, and maximum amount of a single operation. See details of limits in the documentation.
Take a look at frequently asked questions on the service, and get an understanding on how to avoid blocking your wallet from the documentation.
Get access to the service
- Authorize on p2p.qiwi.com.
- Make sure you have access to invoice creation – on the invoicing form fill in Amount field and click Create invoice button. Below the link to the invoice and Copy link button would be displayed.
Congratulations! You can start service integration.
How to start working with the service
- Create public and secret keys.
- Implement API operations or invoicing payment form call. Use SDK or various CMS solutions.
- To get notifications after invoice payment, implement its processing and activate sending notifications.
- Start accepting payments from cards and QIWI wallets.
Invoicing Operations Flow
oplata.qiwi.com end alt Using Payment form rec->>user:Invoice issue on the form
oplata.qiwi.com end deactivate rec user->>p2p:Choose payment method / Paying for invoice deactivate user p2p->>p2p:Invoice payment end opt Additional opt Notifications (callback) activate p2p activate rec p2p->>rec:Invoice status notification rec->>p2p:Server response (OK) deactivate rec deactivate p2p end opt Invoice status check activate p2p activate rec rec->>p2p:Check invoice status p2p->>rec:Invoice data deactivate rec deactivate p2p end end
-
User submits an order on the merchant’s website.
-
Merchant redirects the user to Payment Form link. It automatically issues an invoice for the order. Or you may issue an invoice by API and redirect the user to the created Payment Form (link to the form is placed in the API response).
-
The user chooses a way to pay for the invoice on the Payment Form and confirm payment. By default, the optimal payment method is showed.
-
If merchant activates notification server, the merchant's service receives notification once the invoice is successfully paid by the user. Notifications are digitally signed, so you need to verify the signature on your notification server.
If required, via the API merchant can:
- request current status of the invoice,
- cancel invoice (if the user has not initiated payment yet).
SDK and libraries
- NODE JS SDK — Node JS package of ready-to-use solutions for server2server integration development.
- PHP SDK — PHP package of ready-to-use solutions for server2server integration development.
- Java SDK — Java package of ready-to-use solutions for server2server integration development.
- .Net SDK — C# .NET package of ready-to-use solutions for server2server integration development.
CMS solutions
- Online Leyka — Wordpress plugin for charity solutions
- 1С-Bitrix — plugin for work with orders
- Opencart — plugin for work with orders
- PrestaShop — plugin for work with orders
Authorization methods
New keys issue for authorization has been stopped. Sorry for the inconvenience.
const QiwiBillPaymentsAPI = require('@qiwi/bill-payments-node-js-sdk');
const SECRET_KEY = 'eyJ2ZXJzaW9uIjoicmVzdF92MyIsImRhdGEiOnsibWVyY2hhbnRfaWQiOjUyNjgxMiwiYXBpX3VzZXJfaWQiOjcxNjI2MTk3LCJzZWNyZXQiOiJmZjBiZmJiM2UxYzc0MjY3YjIyZDIzOGYzMDBkNDhlYjhiNTnONPININONPN090MTg5Z**********************';
const qiwiApi = new QiwiBillPaymentsAPI(SECRET_KEY);
--header "Authorization: Bearer MjMyNDQxMjM6NDUzRmRnZDQ0M*******"
<?php
const SECRET_KEY = 'eyJ2ZXJzaW9uIjoicmVzdF92MyIsImRhdGEiOnsibWVyY2hhbnRfaWQiOjUyNjgxMiwiYXBpX3VzZXJfaWQiOjcxNjI2MTk3LCJzZWNyZXQiOiJmZjBiZmJiM2UxYzc0MjY3YjIyZDIzOGYzMDBkNDhlYjhiNTnONPININONPN090MTg5Z**********************';
$billPayments = new Qiwi\Api\BillPayments(SECRET_KEY);
?>
String secretKey = "eyJ2ZXJzaW9uIjoicmVzdF92MyIsImRhdGEiOnsibWVyY2hhbnRfaWQiOjUyNjgxMiwiYXBpX3VzZXJfaWQiOjcxNjI2MTk3LCJzZWNyZXQiOiJmZjBiZmJiM2UxYzc0MjY3YjIyZDIzOGYzMDBkNDhlYjhiNTnONPININONPN090MTg5Z**********************";
BillPaymentClient client = BillPaymentClientFactory.createDefault(secretKey);
var secretKey = "eyJ2ZXJzaW9uIjoicmVzdF92MyIsImRhdGEiOnsibWVyY2hhbnRfaWQiOjUyNjgxMiwiYXBpX3VzZXJfaWQiOjcxNjI2MTk3LCJzZWNyZXQiOiJmZjBiZmJiM2UxYzc0MjY3YjIyZDIzOGYzMDBkNDhlYjhiNTnONPININONPN090MTg5Z**********************";
var client = BillPaymentClientFactory.createDefault(secretKey);
To authorize API requests, you need the keys:
- Secret key
<SECRET_KEY>
— for request authorization in P2P Invoicing API by OAuth 2.0 specification. Put the key into the HTTP-request headerAuthorization: Bearer <SECRET_KEY>
. - Public key
<PUBLIC_KEY>
— for authorization in invoicing by the payment form call.
To create a <SECRET_KEY>
and <PUBLIC_KEY>
pair of keys:
- Login to the personal account on https://p2p.qiwi.com/.
-
Open API tab and click Create a key pair and configure button. When you create a key pair for the first time, click Configure button.
-
Enter a name for the key pair and click Create button.
-
Save the secret key in a safe place — it won't be displayed in your personal account interface. But you can always copy public key from your personal account.
- Click on Next button. The key pair will be activated for use.
You can use the secret key for QIWI Wallet payment operations:
See details in the documentation.
Invoice Issue on Payment Form
It is the simplest way of integration. On opening Payment Form, client receives an invoice at the same time. The invoice data sends in URL explicitly. Client gets a Payment Form web page with multiple payment means.
When using this method, one cannot be sure that all invoices are issued by the merchant. API invoice creation mitigates this risk.
const publicKey = 'Fnzr1yTebUiQaBLDnebLMMxL8nc6FF5zfmGQnypc*******';
const params = {
publicKey,
amount: 42.24,
billId: 'cc961e8d-d4d6-4f02-b737-2297e51fb48e',
email: 'mail@example.com'
};
const link = qiwiApi.createPaymentForm(params);
curl https://oplata.qiwi.com/create?publicKey=Fnzr1yTebUiQaBLDnebLMMxL8nc6FF5zfmGQnypc*******&amount=100&email=mail@example.com&customFields[paySourcesFilter]=qw,card&lifetime=2020-12-01T0509
<?php
$publicKey = '2tbp1WQvsgQeziGY9vTLe9vDZNg7tmCymb4Lh6STQokqKrpCC6qrUUKEDZAJ7mvFnzr1yTebUiQaBLDnebLMMxL8nc6FF5zf******';
$params = [
'publicKey' => $publicKey,
'amount' => 200,
'billId' => 'cc961e8d-d4d6-4f02-b737-2297e51fb48e'
];
/** @var \Qiwi\Api\BillPayments $billPayments */
$link = $billPayments->createPaymentForm($params);
echo $link;
?>
String publicKey = "2tbp1WQvsgQeziGY9vTLe9vDZNg7tmCymb4Lh6STQokqKrpCC6qrUUKEDZAJ7mvFnzr1yTebUiQaBLDnebLMMxL8nc6FF5zfmGQnypdXCbQJqHEJW5RJmKfj8nvgc";
MoneyAmount amount = new MoneyAmount(
BigDecimal.valueOf(499.90),
Currency.getInstance("RUB")
);
String billId = UUID.randomUUID().toString();
String paymentUrl = client.createPaymentForm(new PaymentInfo(key, amount, billId, ""));
var publicKey = "2tbp1WQvsgQeziGY9vTLe9vDZNg7tmCymb4Lh6STQokqKrpCC6qrUUKEDZAJ7mvFnzr1yTebUiQaBLDnebLMMxL8nc6FF5zfmGQnypdXCbQJqHEJW5RJmKfj8nvgc";
var amount = new MoneyAmount
{
ValueDecimal = 499.9m,
CurrencyEnum = CurrencyEnum.Rub
};
var billId = Guid.NewGuid().ToString();
var paymentUrl = client.CreatePaymentForm(new PaymentInfo(key, amount, billId, ""));
GET →
URL https://oplata.qiwi.com/create
const publicKey = 'Fnzr1yTebUiQaBLDnebLMMxL8nc6FF5zfmGQnypc*******';
const params = {
publicKey,
amount: 42.24,
billId: 'cc961e8d-d4d6-4f02-b737-2297e51fb48e',
email: 'mail@example.com'
};
const link = qiwiApi.createPaymentForm(params);
curl https://oplata.qiwi.com/create?publicKey=Fnzr1yTebUiQaBLDnebLMMxL8nc6FF5zfmGQnypc*******&amount=100&email=mail@example.com&customFields[paySourcesFilter]=qw,card&lifetime=2020-12-01T0509
Parameters
Invoice data are put in Payment Form URL.
Parameter | Description | Type |
---|---|---|
publicKey | Required. Merchant's public key for the payment form obtained on p2p.qiwi.com | String |
billId | Unique invoice identifier in merchant's system | URL-Encoded String(200) |
amount | Amount of the invoice rounded down on two decimals | Number(6.2) |
phone | Phone number of the client to which the invoice is issuing (international format) | URL-Encoded String |
E-mail of the client where the invoice payment link will be sent | URL-Encoded String | |
account | Client identifier in merchant's system | URL-Encoded String |
comment | Invoice commentary | URL-Encoded String(255) |
customFields[] | Additional invoice data | URL-encoded String(255) |
customFields[paySourcesFilter] | Allow only the specified payment methods for the client on Payment Form, if they are available to the merchant. Possible values: qw - QIWI Wallet card - card payment |
URL-Encoded String(255) |
customFields[themeCode] | Personalization code for Payments Form | String(255) |
lifetime | Expiration date of the pay form link (invoice payment's due date). If the invoice is not paid after that date, the invoice assigns EXPIRED final status and it becomes void.Important! Invoice will be automatically expired when 45 days is passed after the invoicing date |
URL-Encoded StringYYYY-MM-DDThhmm |
P2P Invoices API. Creating an invoice
Only invoicing in ruble and tenge is supported.
API invoicing is the reliable method for integration. Parameters are sent by means of server2server requests with authorization.
Successful response contains payUrl
URL to redirect client on Payment Form. See the documentation for additional URL parameters supported.
There is also more simple way to invoicing — with direct calling payment form.
Request → PUT
const billId = 'cc961e8d-d4d6-4f02-b737-2297e51fb48e';
const fields = {
amount: 1.00,
currency: 'RUB',
comment: 'Hello world',
expirationDateTime: '2018-03-02T08:44:07'
};
qiwiApi.createBill( billId, fields ).then( data => {
//do smth with data
});
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 <SECRET_KEY>' \
--data-raw '{
"amount": {
"currency": "RUB",
"value": "1.00"
},
"comment": "Text comment",
"expirationDateTime": "2025-12-10T09:02:00+03:00",
"customer": {
"phone": "78710009999",
"email": "test@example.com",
"account": "454678"
},
"customFields" : {
"paySourcesFilter":"qw",
"themeCode": "Yvan-YKaSh",
"yourParam1": "64728940",
"yourParam2": "order 678"
}
}'
<?php
$billId = 'cc961e8d-d4d6-4f02-b737-2297e51fb48e';
$fields = [
'amount' => 1.00,
'currency' => 'RUB',
'comment' => 'test',
'expirationDateTime' => '2018-03-02T08:44:07',
'email' => 'mail@example.com',
'account' => 'client4563'
];
/** @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")
),
"comment",
ZonedDateTime.now().plusDays(45),
new Customer(
"mail@example.com",
UUID.randomUUID().toString(),
"79123456789"
),
""
);
BillResponse response = client.createBill(billInfo);
var billInfo = new CreateBillInfo
{
BillId = Guid.NewGuid().ToString(),
Amount = new MoneyAmount
{
ValueDecimal = 199.9m,
CurrencyEnum = CurrencyEnum.Rub
},
Comment = "comment",
ExpirationDateTime = DateTime.Now.AddDays(45),
Customer = new Customer
{
Email = "mail@example.com",
Account = Guid.NewGuid().ToString(),
Phone = "79123456789"
},
};
var response = client.createBill(billInfo);
URL https://api.qiwi.com/partner/bill/v1/bills/{billid}
- billId - unique invoice identifier generated by the merchant.
HEADERS
- Authorization: Bearer SECRET_KEY
- Accept: application/json
- Content-Type: application/json
Body parameter | Description | Type |
---|---|---|
billId | Required. Unique invoice identifier in merchant's system | String(200) |
amount | Required. Invoice amount information | Object |
amount. currency |
Required. Invoice amount currency code. RUB KZT |
Alpha-3 ISO 4217 code |
amount. value |
Required. Amount of the invoice rounded down to two decimals | Number(6.2) |
expirationDateTime | Required. Invoice due date. Time should be specified with time zone. If the date passed, the invoice is cancelled. | YYYY-MM-DDThhmm+\-hh:mm |
customer | Customer data of the invoice subject | Object |
customer. phone |
Phone number of the client to which the invoice is issuing (international format) | String |
customer. |
E-mail of the client where the invoice payment link will be sent | String |
customer. account |
Client identifier in merchant's system | String |
comment | Invoice commentary | String(255) |
customFields | Additional invoice data | Object |
customFields. paySourcesFilter |
Allow only these payment methods for the client on Payment Form. Possible values: qw - QIWI Wallet card - card payment |
Comma separated string |
customFields. themeCode |
Personalization for Payments Form | String(255) |
Response ←
Successful response body example
{
"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@example.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"
}
Error response body
{
"serviceName": "invoicing-api",
"errorCode": "http.message.conversion.failed",
"description": "Bad request",
"userMessage": "Bad request",
"dateTime": "2021-01-18T14:29:51.984+03:00",
"traceId": "8fa9cfe10c7f83d1"
}
HEADERS
- Content-Type: application/json
Field | Type | Description |
---|---|---|
billId | String | Unique invoice identifier in the merchant's system |
siteId | String | Merchant's site identifier in p2p.qiwi |
amount | Object | Information about the invoice amount |
amount. value |
String | The invoice amount. The number is rounded down to two decimals |
amount. currency |
String | Currency identifier of the invoice amount (Alpha-3 ISO 4217 code) |
status | Object | Data of the invoice current status |
status. value |
String | String representation of the status. Possible statuses |
status. changedDateTime |
String | Status refresh date. Date format:YYYY-MM-DDThh:mm:ss±hh |
customer | Object | Customer data of the invoice subject |
customer. phone |
String | The customer’s phone (if specified in the invoice) |
customer. |
String | The customer's e-mail (if specified in the invoice) |
customer. account |
String | The customer's identifier in the merchant's system (if specified in the invoice) |
customFields | Object | Additional invoice data provided by the merchant |
comment | String | Comment to the invoice |
creationDateTime | String | System date of the invoice creation. Date format:YYYY-MM-DDThh:mm:ss±hh |
payUrl | String | Pay form URL |
expirationDateTime | String | Expiration date of the payment form URL (invoice payment's due date). Redirect the customer to the URL link for invoice payment, or use Popup JavaScript library, to open the form in the popup window. Date format:YYYY-MM-DDThh:mm:ss±hh |
P2P Invoices API. Checking the Invoice Status
We recommend using the method after receiving the payment notification.
Request → GET
const billId = 'cc961e8d-d4d6-4f02-b737-2297e51fb48e';
qiwiApi.getBillInfo(billId).then( data => {
//do smth ith data
});
curl --location --request GET \
'https://api.qiwi.com/partner/bill/v1/bills/cc961e8d-d4d6-4f02-b737-2297e51fb48e' \
--header 'accept: application/json' \
--header 'Authorization: Bearer <SECRET_KEY>'
<?php
$billId = 'cc961e8d-d4d6-4f02-b737-2297e51fb48e';
/** @var \Qiwi\Api\BillPayments $billPayments */
$response = $billPayments->getBillInfo($billId);
print_r($response);
?>
String billId = "fcb40a23-6733-4cf3-bacf-8e425fd1fc71";
BillResponse response = client.getBillInfo(billId);
var billId = "fcb40a23-6733-4cf3-bacf-8e425fd1fc71";
var response = client.getBillInfo(billId);
URL https://api.qiwi.com/partner/bill/v1/bills/{billid}
- billId - unique invoice identifier generated by the merchant.
HEADERS
- Authorization: Bearer SECRET_KEY
- Accept: application/json
Response ←
Successful response body example
{
"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@example.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"
}
Error response body example
{
"serviceName": "invoicing-api",
"errorCode": "api.invoice.not.found",
"description": "Invoice not found",
"userMessage": "Invoice not found",
"dateTime": "2021-01-18T14:34:40.865+03:00",
"traceId": "b3d41cafa0c6d088"
}
HEADERS
- Content-Type: application/json
Field | Type | Description |
---|---|---|
billId | String | Unique invoice identifier in the merchant's system |
siteId | String | Merchant's site identifier in p2p.qiwi |
amount | Object | Information about the invoice amount |
amount. value |
Number | The invoice amount. The number is rounded down to two decimals |
amount. currency |
String | Currency identifier of the invoice amount (Alpha-3 ISO 4217 code) |
status | Object | Invoice status data |
status. value |
String | Current invoice status |
status. changedDateTime |
String | Status refresh date |
customFields | Object | Additional invoice data provided by the merchant |
customer | Object | Customer data of the invoice subject |
customer. phone |
String | The customer’s phone (if specified in the invoice) |
customer. |
String | The customer's e-mail (if specified in the invoice) |
customer. account |
String | The customer's identifier in the merchant's system (if specified in the invoice) |
comment | String | Comment to the invoice |
creationDateTime | String | System date of the invoice creation. Date format:YYYY-MM-DDThh:mm:ss |
payUrl | String | Payment form URL for customer redirect |
expirationDateTime | String | Expiration date of the pay form link (invoice payment's due date). Date format:YYYY-MM-DDThh:mm:ss |
P2P Invoices API. Cancelling the Invoice
Use this method to cancel unpaid invoice.
Request → POST
const bill_id = 'cc961e8d-d4d6-4f02-b737-2297e51fb48e';
qiwiApi.cancelBill(billId).then( data => {
//do smth with data
});
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 <SECRET_KEY>' \
--data-raw ''
<?php
$billId = 'cc961e8d-d4d6-4f02-b737-2297e51fb48e';
/** @var \Qiwi\Api\BillPayments $billPayments */
$response = $billPayments->cancelBill($billId);
print_r($response);
?>
String billId = "fcb40a23-6733-4cf3-bacf-8e425fd1fc71";
BillResponse response = client.cancelBill(billId);
var billId = "fcb40a23-6733-4cf3-bacf-8e425fd1fc71";
var response = client.cancelBill(billId);
URL https://api.qiwi.com/partner/bill/v1/bills/{billId}/reject
-
Parameters:
- billId - unique invoice identifier generated by the merchant.
HEADERS
- Authorization: Bearer SECRET_KEY
- Content-Type: application/json
- Accept: application/json
Response ←
Successful response body example
{
"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@example.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"
}
Error response body example
{
"serviceName": "invoicing-api",
"errorCode": "api.invoice.not.found",
"description": "Invoice not found",
"userMessage": "Invoice not found",
"dateTime": "2021-01-18T14:39:54.265+03:00",
"traceId": "bc6bb6e7c5cf5beb"
}
HEADERS
- Content-Type: application/json
Field | Type | Description |
---|---|---|
billId | String | Unique invoice identifier in the merchant's system |
siteId | String | Merchant's site identifier in p2p.qiwi |
amount | Object | Information about the invoice amount |
amount. value |
Number | The invoice amount. The number is rounded down to two decimals |
amount. currency |
String | Currency identifier of the invoice amount (Alpha-3 ISO 4217 code) |
status | Object | Invoice status data |
status. value |
String | Current invoice status |
status. changedDateTime |
String | Status refresh date |
customFields | Object | Additional invoice data provided by the merchant |
customer | Object | Customer data of the invoice subject |
customer. phone |
String | The customer’s phone (if specified in the invoice) |
customer. |
String | The customer's e-mail (if specified in the invoice) |
customer. account |
String | The customer's identifier in the merchant's system (if specified in the invoice) |
comment | String | Comment to the invoice |
creationDateTime | String | System date of the invoice creation. Date format:YYYY-MM-DDThh:mm:ss |
payUrl | String | Payment form URL |
expirationDateTime | String | Expiration date of the pay form link (invoice payment's due date). Date format:YYYY-MM-DDThh:mm:ss |
P2P Invoices API. Invoice Payment Statuses
Status | Description | Final |
---|---|---|
WAITING | Invoice issued awaiting for payment | - |
PAID | Invoice paid | + |
REJECTED | Invoice rejected by customer | + |
EXPIRED | Invoice expired. Invoice not paid | + |
Invoice payment notifications
Before working with the notification service, consider the Notification API Integration Terms.
Pools of IP-addresses from which QIWI service sends notifications:
- 79.142.16.0/20
- 195.189.100.0/22
- 91.232.230.0/23
- 91.213.51.0/24
If your web service works behinds the firewall, you need to add these IP-addresses to the list of allowed addresses for incoming TCP packets.
Notification (callback) is an incoming HTTP POST-request.
Request ← POST
Notification example
POST /qiwi-notify.php HTTP/1.1
Accept: application/json
Content-type: application/json
X-Api-Signature-SHA256: J4WNfNZd***V5mv2w=
Host: example.com
{
"bill": {
"siteId": "9hh4jb-00",
"billId": "cc961e8d-d4d6-4f02-b737-2297e51fb48e",
"amount": {
"value": "1.00",
"currency": "RUB"
},
"status": {
"value": "PAID",
"changedDateTime": "2021-01-18T15:25:18+03"
},
"customer": {
"phone": "78710009999",
"email": "test@example.com",
"account": "454678"
},
"customFields": {
"paySourcesFilter": "qw",
"themeCode": "Yvan-YKaSh",
"yourParam1": "64728940",
"yourParam2": "order 678"
},
"comment": "Text comment",
"creationDateTime": "2021-01-18T15:24:53+03",
"expirationDateTime": "2025-12-10T09:02:00+03"
},
"version": "1"
}
The request's body contains JSON-serialized invoice data encoded by UTF-8 codepage.
HEADERS
- X-Api-Signature-SHA256: XXX
- Accept: application/json
- Content-type: application/json
Notification server registration
New keys issue for notification has been stopped. Sorry for the inconvenience.
URL address of notification processing server is configured in the personal account profile. A new key pair is issued simultaneously. Only one key pair can be supported for the notification server — the old key pair is disabled once the new is isssued.
- Login to your personal account.
-
Open API tab and click Create key pair and configure button. When you configure the server address along with creating a key pair for the first time, click Configure button.
-
Enter name for the new key pair.
-
Select Use this key pair for notifications about invoice status changes field.
- In URL notification server specify your notification service URL. The service URL must be accessible from the Internet.
-
Click Create button.
- Change QIWI P2P keys in your application settings to the new one.
How to verify notification authenticity
Upon receiving incoming notification you need to verify its digital signature. The notification signature is placed in X-Api-Signature-SHA256
HTTP header. Signature mechanism uses HMAC algorithm integrity check with SHA256-hash function.
Signature verification algorithm is as follows:
-
Prepare a string of the following notification's parameters separated by
|
:invoice_parameters = {amount.currency}|{amount.value}|{billId}|{siteId}|{status.value}
where
{*}
is the value of the parameter. All values should be treated as strings. -
Apply HMAC-SHA256 function:
hash = HMAС(SHA256, invoice_parameters, <SECRET_KEY>)
where:
<SECRET_KEY>
– secret key used for the invoice creation;invoice_parameters
– string from step 1.
-
Compare
X-Api-Signature-SHA256
header's value with the result of step 2.
const validSignatureFromNotificationServer =
'07e0ebb10916d97760c196034105d010607a6c6b7d72bfa1c3451448ac484a3b';
const notificationData = {
bill: {
siteId: 'test',
billId: 'test_bill',
amount: { value: 1, currency: 'RUB' },
status: { value: 'PAID', datetime: '2018-03-01T11:16:12+03' },
customer: {},
customFields: {},
creationDateTime: '2018-03-01T11:15:39+03',
expirationDateTime: '2018-04-15T11:15:39+03'
},
version: '1'
};
const merchantSecret = 'test-merchant-secret-for-signature-check';
qiwiApi.checkNotificationSignature(
validSignatureFromNotificationServer, notificationData, merchantSecret
); // true
<?php
$validSignatureFromNotificationServer = '07e0ebb10916d97760c196034105d010607a6c6b7d72bfa1c3451448ac484a3b';
$notificationData = [
'bill' => [
'siteId' => 'test',
'billId' => 'test_bill',
'amount' => ['value' => 1, 'currency' => 'RUB'],
'status' => ['value' => 'PAID']
],
'version' => '3'
];
$merchantSecret = 'test-merchant-secret-for-signature-check';
/** @var \Qiwi\Api\BillPayments $billPayments */
$billPayments->checkNotificationSignature(
$validSignatureFromNotificationServer, $notificationData, $merchantSecret
); // true
?>
String merchantSecret = "test-merchant-secret-for-signature-check";
Notification notification = new Notification(
new Bill(
"test",
"test_bill",
new MoneyAmount(
BigDecimal.ONE,
Currency.getInstance("RUB")
),
BillStatus.PAID
),
"3"
);
String validSignature = "07e0ebb10916d97760c196034105d010607a6c6b7d72bfa1c3451448ac484a3b";
BillPaymentsUtils.checkNotificationSignature(validSignature, notification, merchantSecret); //true
String and key of the signature are encoded in UTF-8.
Data
Invoice data are in the notification's body.
Notification field | Description | Type |
---|---|---|
bill | Invoice data | Object |
billId | Invoice identifier in the merchant's system | String(200) |
siteId | Merchant's site identifier in p2p.qiwi | String |
amount | Information about the invoice amount | Object |
amount. value |
The invoice amount. The number is rounded down to two decimals | Number(6.2) |
amount. currency |
Currency identifier of the invoice amount (Alpha-3 ISO 4217 code) | String(3) |
status | Invoice status data | Object |
status. value |
Current invoice status | String |
status. changedDateTime |
Status refresh date. Date format:YYYY-MM-DDThh:mm:ssZ |
String |
customFields | Additional invoice data provided by the merchant | Object |
customer | Customer data of the invoice subject (if specified in the invoice) | Object |
customer. phone |
The customer’s phone (if specified in the invoice) | String |
customer. |
The customer's e-mail (if specified in the invoice) | String |
customer. account |
The customer's identifier in the merchant's system (if specified in the invoice) | String |
comment | Comment to the invoice | String(255) |
creationDateTime | System date of the invoice creation. Date format:YYYY-MM-DDThh:mm:ssZ |
String |
payUrl | Payment form URL | String |
expirationDateTime | Expiration date of the pay form link (invoice payment's due date). Date format:YYYY-MM-DDThh:mm:ssZ |
String |
version | Notification service version | String |
Response →
HTTP/1.1 200 OK
Content-Type: application/json
{
"error":"0"
}
HEADERS
- Content-type: application/json
After receiving incoming notification request, you should verify its signature and returns the JSON-response. The processing result code should be returned in response.
Invoice payment form
You can add parameters to URL from payUrl
field of the response to invoice request:
Invoice URL example
curl https://oplata.qiwi.com/form?invoiceUid=a8437e7e-dc48-44f7-9bdb-4d46ca8ef2e4&paySource=qw
Parameter | Description | Type |
---|---|---|
paySource | Pre-selected payment method for the client on Payment Form. Possible values: qw - QIWI Walletcard - card paymentmobile - payment from phone balanceWhen specified method is inaccessible, the page automatically selects recommended method for the user. |
String |
Add referal links for payments from your site. This confirms the site is real and will avoid the wallet blocking problems. Payments from any page without Refer header will result in wallet block. See details in the documentation.
Referal link example
<?php
header("Referrer-Policy: no-referrer-when-downgrade");
?>
To make sure the full referer is tranferred for the new version of browsers, set Referrer-Policy
in your server response with no-referrer-when-downgrade
value. It can be done for all pages of your site or only for the page with payment form link.
Personalization
Personalization allows you to create a payment form with your style, customizable logo, background and color of the buttons.
Example of a customized payment form:
To setup payment form appearance:
- Login to your personal account on p2p.qiwi.com.
-
Open Transfer acceptance form tab. Your code style for
themeCode
parameter (you need it for API and SDK requests) is marked bold in grey block. ValuecodeStyle
is different for different QIWI wallets. - Click Tune button and configure the form' parameters.
- Click Save button.
Invoice Issue on Payment Form
curl https://oplata.qiwi.com/create?publicKey=Fnzr1yTebUiQaBLDnebLMMxL8nc6FF5zfmGQnypc*******&amount=100&billId=cc961e8d-d4d6-4f02-b737-2297e51fb48e&customFields%5BthemeCode%5D=codeStyle
Invoice Issue by API
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 <SECRET_KEY>' \
--data-raw '{
"amount": {
"currency": "RUB",
"value": 100.00
},
"comment": "Text comment",
"expirationDateTime": "2025-04-13T14:30:00+03:00",
"customer": {},
"customFields": {"themeCode":"codeStyle"}
}'
const billId = 'cc961e8d-d4d6-4f02-b737-2297e51fb48e';
const fields = {
amount: 1.00,
currency: 'RUB',
comment: 'Hello world',
customFields: {themeCode: 'codeStyle'},
expirationDateTime: '2018-03-02T08:44:07+03:00'
};
qiwiApi.createBill( billId, fields ).then( data => {
//do with data
});
<?php
$billId = 'cc961e8d-d4d6-4f02-b737-2297e51fb48e';
$customFields = ['themeCode' => 'codeStyle'];
$fields = [
'amount' => 1.00,
'currency' => 'RUB',
'comment' => 'test',
'expirationDateTime' => '2018-03-02T08:44:07+03:00',
'email' => 'mail@example.org',
'account' => 'client4563',
'customFields' => $customFields
];
/** @var \Qiwi\Api\BillPayments $billPayments */
$response = $billPayments->createBill($billId, $fields);
print_r($response);
?>
client.CreateBill(
info: new CreateBillInfo
{
BillId = Guid.NewGuid().ToString(),
Amount = new MoneyAmount
{
ValueDecimal = 199.9m,
CurrencyEnum = CurrencyEnum.Rub
},
Comment = "comment",
ExpirationDateTime = DateTime.Now.AddDays(45),
Customer = new Customer
{
Email = "mail@example.org",
Account = Guid.NewGuid().ToString(),
Phone = "79123456789"
},
CustomFields: new CustomFields
{
ThemeCode = "codeStyle"
}
}
);
To apply the appearance to the payment form:
-
Add
customFields
object withthemeCode
field where your code is specified in the body of the invoice request or in the parameters of invoice creation method in the corresponding SDK module.For example,
"customFields": { "themeCode":"codeStyle"}
. -
Add
customFields
array element withthemeCode
field on calling the payment form and put your code there.For example,
customFields[themeCode]=кодСтиля
.
Checkout Popup library
The library methods open the payment form as a popup window over your site in browser.
Installation:
<script src='https://oplata.qiwi.com/popup/v1.js'></script>
The library has two methods:
- Open an existing invoice.
- Open your personal payform.
Open an existing invoice
Open an existing invoice
params = {
payUrl: 'https://oplata.qiwi.com/form?invoiceUid=06df838c-0f86-4be3-aced-a950c244b5b1'
}
QiwiCheckout.openInvoice(params)
.then(data => {
// ...
})
.catch(error => {
// ...
})
Call function QiwiCheckout.openInvoice
.
Parameter | Description | Type |
---|---|---|
payUrl | Required. Payment form URL | String |
Open personal payform
Call function QiwiCheckout.openPreorder
.
Open your custom payform
params = {
widgetAlias: 'https://my.qiwi.com/form/User-ABCDE1234-56'
}
QiwiCheckout.openPreorder(params)
.then(data => {
// ...
})
.catch(error => {
// ...
})
Parameter | Description | Type |
---|---|---|
widgetAlias | Required. URL of your payform | String |