Оплата за допомогою додатку "Термінал"
З питань отримання ідентифікаторів зовнішніх сервісів, ключів для підпису, та адреси сервісу перевірки платежів звертатися:
Галушкін Максим Сергійович
E-mail: maksim.galushkin@privatbank.ua
1.Підготовка параметрів та підпис даних запитів
Для правильного формування запиту на любой з сервісів ( token.php чи check.php) потрібно до скрипта додвати параметри clid, signed, signature
url = {https://dio.privatbank.ua}
* - запит token/check
POST {url}/api/nfcpos/integrators/*.php?clid=test&signed=1476193110
&signature=2b3a694f0fe2574bd85edb0f5e723af013c089d9
Атрибут | Опис |
---|---|
clid | ідентифікатор зовнішнього сервісу, попередньо узгоджується і видається банком. Додається до адреси запиту. |
secret | ключ для підпису, видається разом з ідентифікатором зовнішнього сервісу |
signed | час відправлення запиту (кількість секунд, що минув з 1 січня 1970р 00: 00:00 GMT до моменту відправки запиту). Додається до адреси запиту |
signature | підпис сформований на основі параметтрів sercet, signed, data. Додається до адреси запиту. |
data | тіло запиту |
Параметр signature розраховується за формулою:
sha1( signed + secret + data + secret )
де:
secret - ключ для підпису, видається разом з ідентифікатором зовнішнього сервісу data - вміст тіла запиту
Параметри clid, signed, signature завжди передаються всередині url.
Приклад запиту
clid = test
secret = test
signed = 1697051765 (Wed Oct 11 2023 19:16:05 GMT+0000)
data = {"operation" : "pay" ,"amount":1.0, "purpose" : "test"}
POST https://dio.privatbank.ua/api/nfcpos/integrators/token.php?clid=test
&signed=1697051765&signature=0c19f9efae8ce89efb542bd52c88954a99496126
Content-Type: application/json
тіло запиту
{"operation" : "pay" ,"amount":1.0, "purpose" : "test"}
PHP приклад формування і підпісу праметрів запіту отрімання токену для операції Оплата
$clid = 'test';
$secret = 'abcdef';
//для тестування та перевірки
//в реальных запросах должно быть текущее в время серверв UTC в секундах
$signed = '1624023225'; // (для UTC 2021-06-18 13:33:45 +0000)
/***
Pay
Під час формування підпису в $data необхідно враховувати саме той набір
параметрів, який буде передано в тілі запиту. Тобто, якщо запит містить
необов'язкові поля, під час формування підпису потрібно використовувати
всі поля, які фактично присутні в запиті.
*/
$params = array(
'operation' => 'pay',
'amount' => 3.33,
'purpose' => 'Test'
);
$data = json_encode($params);
//формирование подписи sha1( signed + secret + data + secret )
$signature = sha1( $signed . $secret . $data . $secret );
//значення після обчислення для перевірки
// signature=896e7808ed56bde0e3966b46b30688e0715bb439
$url = 'https://dio.privatbank.ua/api/nfcpos/integrators/token.php?clid='
.$clid . '&signed=' . $signed . '&signature=' . $signature;
$options = array( CURLOPT_HTTPHEADER => array( 'Content-Type' => 'application/json' ));
2.Сервіс токенізації операцій
Для взаємодії з платіжним застосунок Термінал та виконання фінансових операцій оплата/повернення необхідно використовувати API для отримання токенів. Залежно від типу виконуваної операції необхідно підготувати та передати у запиті відповідні параметри.
Коли клієнт надає агрегатору токен, то агрегатор має додати до тіла запита ще один параметр, під назвою "client_token".
Якщо в запиті на токенізацію вказано phone та retailer_id, і цей термінал доступний у застосунку, то термінал буде обрано автоматично.
Запит на отримання токену:
POST https://dio.privatbank.ua/api/nfcpos/integrators/token.php? clid= {ID компанії яка створює токен}&signed={ключ}&signature={значення хешу}
Параметри тіла запитів:
Оплата
{
"operation": "pay",
" amount": 3.33,
"purpose": "Test",
"client_token": "zgvIgAQ5jbXIsvDrAahW7MVKNXk7Tq1114SnG9UKYtyXTNZJD437xwmAnk4IYUyN"
}
Повернення
{
"operation": "refund",
" amount": 3.33,
"transaction_id": "Test",
"client_token": "zgvIgAQ5jbXIsvDrAahW7MVKNXk7Tq1114SnG9UKYtyXTNZJD437xwmAnk4IYUyN"
}
Формат вхідних параметрів
Параметр | Опис | Формат даних |
---|---|---|
operation | Операція (pay/refund). Поле обов'язкове.' |
String |
amount | Сума платежу/повернення (мінімальна сума для сплати 1.00 грн). Поле обов'язкове. |
Double |
purpose | Призначення платежу (заборонені сурогатні та “Other Symbol”) Поле для операції pay. Значення параметра «призначення» повинно бути текстовим і не містити спеціальних символів, емодзі та знаків пунктуації. Поле не обов'язкове. |
String |
transaction_id | Ідентифікатор оригінальної платіжної транзакціїю Обов'язкове поле для операції refund. Поле не обов'язкове. |
String |
client_token | Токен клієнта для якого потрібно створити токен для проведення операцій (pay або refund ). Якщо параметр не вказується то операційний токен (jwt) створюється для інтегратора, компанії, яка ініціює запит. Поле не обов'язкове. |
Stirng(64) |
phone | Номер телефону касира (в форматі “+380 ** * ** **”). Обов'язковий, якщо вказати retailer_id. Поле не обов'язкове. |
String |
retailer_id | Ідентифікатор магазину. Обов'язковий, якщо вказати phone. Поле не обов'язкове. |
String |
Успішна відповідь
{
"success": true,
"rid": "b3e195e0eba6d921a95231cd78937d6a",
"jwt": "ey******kzMzZkOVGVzdCJ9.x-qLonr823cU2NK0ETJ1gaaUpmJ-WXov0",
"status": 200
}
Опис Вихідних параметрів
Параметр | Опис | Формат даних |
---|---|---|
success | признак успішної операції | boolean |
rid | ідентифікатор запита | string |
jwt | токен сформовааний для певної операції | sting( BASE64) |
status | код HTTP відповіді | int |
3.Виклик додатку "Термінал" для здійснення оплати (Android)
Після успішного отримання токена для фінансової операції.
Приклад виклику та передачі параметрів
val jwtToken:String = "*****" //JWT токен операциії (П. 1)
val callback = "https://******" //callback
startTerminalApp(jwtToken: String, callback:String)
Формат параметрів
Параметр | Опис | Формат даних | Обов'язковий |
---|---|---|---|
jwtToken | JWT токен операциії (П. 1) | String | Так |
callback | callback зовнішньої інтеграційної системи для передачі події (успішного/неуспішного) завершення операції | String | Ні |
Функція виклику додатку
const val DEEP_LINK_URL = "nfcterminal://executor"
private fun startTerminalApp(jwtToken: String, callback:String) {
val launchIntent =
packageManager.getLaunchIntentForPackage("ua.privatbank.pterminal")
if (launchIntent != null) {
val intent = Intent(Intent.ACTION_VIEW)
val jwtTokenEncode = URLEncoder.encode(jwtToken, "utf-8")
intent.data = Uri.parse(DEEP_LINK_URL+"?token=$jwtTokenEncode&callback=$callback")
try {
startTerminalForResult.launch(intent)
} catch (e: Exception) {
e.printStackTrace()
}
} else {
try {
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse("market://details?id=ua.privatbank.pterminal")
)
)
} catch (e: android.content.ActivityNotFoundException) {
try {
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse("https://play.google.com/store/apps/details?id=ua.privatbank.pterminal")
)
)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
Отримання та обробка результату
private val startTerminalForResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult ->
if (result.resultCode == AppCompatActivity.RESULT_OK) {
val intent = result.data
if (intent != null) {
val tresult = intent.getStringExtra("result") //результат виконання операції
Log.d(TAG,"Intent Transaction result = $tresult")
binding.edResult.setText(tresult)
} else {
Log.d(TAG,"intent == NULL")
}
} else {
Log.d(TAG, "result != RESULT_OK")
}
}
Результат виконання операції повертається у форматі JSON
Формат відповіді
Атрибут | Опис | Формат даних |
---|---|---|
result | результат успішна / нi | Boolean (true/false) |
token | інтеграційний JWT токен | String |
operation_id | ідентифікатор операції | String |
date | дата та час проведення | String |
error | опис помилки | String |
{
"token": "eyJ0eXAiOiJKV1QiLCJhbG*******",
"date": "2022-07-13 16:30:50",
"error": "",
"operation_id": "PAX62cec9140b7052.60786725",
"result": true
}
4.Виклик додатку "Термінал" для здійснення оплати (iOS)
Після успішного отримання токена для фінансової операції.
Приклад виклику та передачі параметрів:
let jwtToken = "*****" // JWT токен операциії (П. 1)
let callback = "https://******/?id=unique_identifier" // буде виклакано по завершеню операції, id=unique_identifier як приклад ідентифікації операції
let terminalUrlScheme = "nfcterminal://executor"
let urlString = terminalUrlScheme + "?token=\(jwtToken)&callback=\(callbackUrl)"
if let url = URL(string: urlString) {
UIApplication.shared.open(url)
}
Формат параметрів
Параметр | Опис | Формат даних | Обов'язковий |
---|---|---|---|
jwtToken | JWT токен операциії (П. 1) | String | Так |
callback | callback зовнішньої інтеграційної системи для передачі події завершення операції | String | Так |
Для обробки виклику callback, застосунок може бути налаштовано одним із способів:
- universal links, наприклад "https://my.app.site/callback/result/?id=unique_identifier" Apple документація
- url scheme, наприклад "myappcallback://result?id=unique_identifier" Apple документація
Отримання та обробка результату відбуваєтся через Сервіс отримання інформації щодо операції
5.Сервіс отримання інформації щодо операції
Використовується для отримання результату операції, зробленої за допомогою додатку "Термінал"
POST [https://dio.privatbank.ua/api/nfcpos/integrators/check.php?**clid=**{ID клієнта}&signed={ключ}&signature={значення хешу}
Параметри операції
*jwt *- токен, отриманий для виконання операції
{
"jwt": "ey******kzMzZkOVGVzdCJ9.x-qLonr823cU2NK0ETJ1gaaUpmJ-WXov0"
}
Успішна відповідь для операції Оплата
{
"success": true,
"rid": "addc2a61a4d0d23abbdf09bf24b46bdd",
"pay": {
"code": "iso00_Approved",
"user_message": "Успішно",
"merchant": "M11302GG",
"traceId": "0471edb9526efc43ad9e680c2dec0ee5",
"approval_code": "131192",
"processing_code": "000000",
"response_code": "00",
"rrn": "014722766522",
"batch_id": 0,
"discount_amount": 0,
"discount_percent": 0,
"discount_type": "no_discount",
"amount_full": 3.33,
"payment_system": "Visa",
"masked_pan": "4149********1451",
"qr_code": "",
"receipt": "HTML чек ",
"receipt_id": 0,
"date": "20230705 08:20:09 +0000",
"stan": "082597",
"transaction_id": "PAX-TEST-64a527b82b7479.87095729"
},
"status": 200
}
Успішна відповідь для операції Повернення
{
"success": true,
"rid": "a60a7953e5678664398f15755b12410f",
"pay": {
"code": "iso00_Approved",
"user_message": "Успішно",
"merchant": "M11302GG",
"traceId": "0471edb9526efc43ad9e680c2dec0ee5",
"approval_code": "131192",
"processing_code": "000000",
"response_code": "00",
"rrn": "014722766522",
"batch_id": 0,
"discount_amount": 0,
"discount_percent": 0,
"discount_type": "no_discount",
"amount_full": 3.33,
"payment_system": "Visa",
"masked_pan": "4149********1451",
"qr_code": "",
"receipt": "HTML чек",
"receipt_id": 0,
"date": "20230705 08:20:09 +0000",
"stan": "082597",
"transaction_id": "PAX-TEST-64a527b82b7479.87095729"
},
"refunds": [
{
"amount": 3.33,
"state": 1,
"date": "2023-07-05T11:27:56.522626"
}
],
"status": 200
}
Успішна відповідь для операції Реверс
{
"success": true,
"rid": "63f86ba5fd078c104afd9a86ba29df96",
"pay": {
"code": "iso00_Approved",
"user_message": "Успішно",
"merchant": "M11302EP",
"approval_code": "900060",
"processing_code": "000000",
"response_code": "00",
"rrn": "014724824026",
"amount_full": 100,
"payment_system": "Visa",
"masked_pan": "4731********1548",
"receipt": " <div class=\"pb-receipt receipt\">\n <div class=\"pb-logo\"> </div>\n <div class=\"r-header\">\n <p>Silpo Тестовий мерчант (M11302EP)</p>\n <p>область Дніпропетровська,район Дніпровський,місто Дніпро,вулиця Архітектора Заболотного,будинок 1</p>\n <p>ЄДРПОУ/ІПН 31435622</p>\n <p>'TEST TEST MCB'</p>\n </div>\n <div class=\"font-xl font-bold hl\">Оплата</div>\n\n <div class=\"block i-block\">\n <div class=\"flex-line \">\n <p>Телефон підтримки</p>\n <p>3700</p>\n </div>\n <div class=\"flex-line \">\n <p>Сайт АТ КБ ПриватБанк</p>\n <p>www.privatbank.ua</p>\n </div>\n </div> <hr class=\"dot-line\">\n\n <div class=\"block main-block\">\n <div class=\"flex-line \">\n <p>VISA</p>\n <p>4731********1548</p>\n </div>\n <div class=\"flex-line font-n font-bold\">\n <p>СУМА</p>\n <p>100,00 грн</p>\n </div>\n </div> <hr class=\"dot-line\">\n <div class=\"block i-block\">\n <p>Підпис клієнта не потрібен</p>\n <p>Мерчант: M11302EP</p>\n <p>Код авторизації: 900060</p>\n <p>AID: A0000000031010</p>\n <p>RRN: 014724824026</p>\n <p>27.01.2025 16:39:11</p>\n </div>\n </div> ",
"date": "20250127 14:39:11 +0000",
"stan": "098801",
"batch_id": 0,
"discount_amount": 0,
"discount_percent": 0,
"discount_type": "no_discount",
"qr_code": "",
"receipt_id": 0,
"transaction_id": "PAX-TEST-67979a8e722d30.66656501"
},
"reverses": [
{
"amount": 100,
"id": 1901,
"created": "2025-01-27 16:39:57",
"updated": "2025-01-27 16:39:58",
"reversed": null,
"state": 0,
"state_description": "InProgress"
},
{
"amount": 100,
"id": 1903,
"created": "2025-01-28 11:31:24",
"updated": "2025-01-28 11:31:24",
"reversed": null,
"state": 0,
"state_description": "InProgress"
},
{
"amount": 100,
"id": 1939,
"created": "2025-01-31 15:29:39",
"updated": "2025-01-31 15:29:39",
"reversed": null,
"state": 2,
"state_description": "Failed"
}
],
"status": 200
Опис вихідних параметрів
Атрибут | Опис | Формат даних |
---|---|---|
Блок pay ( інформація про оригінальну транзакцію) | ||
transaction_id | Ідентифікатор транзакції | String |
code | Код відповіді у процесінгу | String |
merchant | Мерчант під яким робиласть транзакція | String |
user_message | Відповідь операції продажу процесінга | String |
traceId | Ідентифікатор для відстеження | String |
approval_code | Містить ідентифікаційний код відповіді , назначений авторизуючим інститутом | String |
responce_code | Код відповіді авторизатора | String |
rrn | RRN | String |
batch_id | Ідентифікатор батча транзакції | String |
discount_amount | Сума знижки | float |
discount_percent | Процент знижки | float |
discount_type | Тип знижки | String |
amount_full | Повна сума транзакції (грн) | float |
payment_system | Платіжна система | String |
masked_pan | Маска платіжної картки | String |
qr_code | QR коду | String |
receipt | Чек в формате HTML | String |
receipt_id | Ідентифікатор чека | String |
date | Дата проведення транзакції | String |
stan | Це не унікальне числове значення транзакції | String |
Блок refuns (заявки на повернення по платежу) | ||
date | Дата створення запиту на повернення | String |
amount | Сума заявки на повернення у грн | float |
state | Статус заявки ( 1-Запит обробляється, 2- Виконано, 3 - Відмова ) ) | int |
Блок reverses (заявки на реверси по платежу) | ||
id | Ідентифікатор заявки на реверс | int |
amount | Сума заявки на повернення у грн | float |
created | Дата створення заявки на реверс | string |
updated | Дата останнього оновлення заявки на реверс | string |
reversed | Дата реверсу в процессінгу | string |
state | Статус заявки (0 = InProgress, 1 = Reversed, 2 = Failed) |
int |
state_description | Опис статусу (0 = InProgress, 1 = Reversed, 2 = Failed) |
string |
status | код стану http запиту | int |
6.Опис реверсу
Використовується для для формування реверсу операції, яка буде передана у запиті.
POST [https://dio.privatbank.ua/api/nfcpos/integrators/reverse.php?clid={ID клієнта}&signed={ключ}&signature={значення хешу} .
Параметри операції:
transaction_id - ідентифікатор транзакції по якій намагаємось провести реверс. Приклад:
{
"transaction_id": "PAX-TEST-67977ccf9d76d8.61511107"
}
Відповідь:
id - Ідентифікатор заявки на реверс , int
result - Результат виконання операції, string (TransactionResult) (Enum: "ok" "error" "retry")
code - Код виконання операції реверсу, string,
user_message - Текстове повідомлення клієнту при помилці
merchant - Мерчант користувача
response_code - Код відповіді авторизацій ПЦ
date - Дата виконання транзакції у форматі 20231103 17:40:50 +0000
status - статус відповіді 200 - ОК
{
"success": true,
"rid": "ebb621d7a87dfbe9524a0cb3b158aee4",
"id": 1944,
"result": "ok",
"code": "guaranteeOffline",
"user_message": null,
"merchant": "M123456",
"response_code": "00",
"date": "20250206 20:32:05 +0000",
"status": 200
}
Таблиця з результатами та кодами виконання операції
Числове представлення | Текстове представлення | result | user_message | Опис |
---|---|---|---|---|
1 | sentOnline | ok | Відправлено на ПЦ одразу та отримано успішну відповідь | |
2 | alreadySavedRevers | ok | Реверсал знаходиться в обробці | Вже збережено реверсал за цим trans_id |
3 | requestIsNotValid | error | Передана не валідна операція (або опис помилки валідації) |
Переданий параметр oper != reversal або не пройшла загальна валідація вхідних параметрів |
4 | cannotSaveReversal | retry | - | Помилка збереження реверсу до бази |
5 | guaranteeOffline | ok | - | Реверс збережено для подальних спроб відправки до ПЦ. Можна вважати обробленим. |
6 | incorrectDateForReversal | ok | - | Закінчився час подачі автоматичного реверсу. Назаразі діє обмеження: 24 години від оригінальної операції (якщо без чайових) АБО той же каледарний день (якщо операція із чайовими) |
7.Коди відповідей
HTTP code | Опис |
---|---|
200 | Успішна обробка |
400 | Неправильний запит |
401 | Неправильно сформовано підпис |
418 | Час який використовувася у параметрі signed більший на 60 секунд ніж час обробки запиту |
500 | Внутрішня помилка сервісу |
Приклад відповіді з помилкою
{
"success": false,
"rid": "ce2f4a3454c35a6429adfd7a67f35ddc",
"status": 400,
"message" : "Невалідні дані запиту.",
"error" : "IE_01"
}