Оплата за допомогою додатку "Термінал"

З питань отримання ідентифікаторів зовнішніх сервісів, ключів для підпису, та адреси сервісу перевірки платежів звертатися:

Галушкін Максим Сергійович

E-mail: maksim.galushkin@privatbank.ua

  1. Підготовка параметрів та підпис даних запитів

  2. Сервіс токенізації операцій

  3. Виклик додатку "Термінал" для виконання операції (Android)

  4. Виклик додатку "Термінал" для виконання операції ( iOS )

  5. Сервіс отримання інформації щодо операції

  6. Коди відповідей

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     
*/
$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".

Запрос отримання токену:

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)

Успішна відповідь

{
 "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, застосунок може бути налаштовано одним із способів:

Отримання та обробка результату відбуваєтся через Сервіс отримання інформації щодо операції

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
}

Опис вихідних параметрів

Атрибут Опис Формат даних
Блок 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
status код стану http запиту int

6.Коди відповідей

HTTP code Опис
200 Успішна обробка
400 Неправильний запит
401 Неправильно сформовано підпис
418 Час який використовувася  у  параметрі  signed більший на 60 секунд ніж час  обробки запиту
500 Внутрішня помилка сервісу

Приклад відповіді з помилкою

{
 "success": false,
 "rid": "ce2f4a3454c35a6429adfd7a67f35ddc",
 "status": 400,
}