iPay Payment System Integration
iPay is Ukrainian payment service, aimed at small and medium business. Supports Visa, Mastercard cards, Privat24 payment, plus card tokenization for repeat debits. Documentation available on ipay.ua, REST API with JSON.
Registration and Getting Keys
After registration in iPay and business verification:
-
salt— signature salt -
sign_key— signature key -
merchant_id(mch_id) — store identifier
Test mode activated by s_cost=1 parameter in test transactions.
Transaction Creation
function createIPayTransaction(int $orderId, float $amount, string $description): array
{
$mchId = env('IPAY_MERCHANT_ID');
$salt = env('IPAY_SALT');
$signKey = env('IPAY_SIGN_KEY');
// Signature: HMAC-SHA512 from parameter concatenation
$body = [
'auth' => [
'mch_id' => $mchId,
'salt' => $salt,
'sign' => '', // will be replaced
],
'transaction' => [
'mch_id' => $mchId,
'srv_id' => 1, // Service ID from account
's_amount' => $amount,
's_currency_iso' => 'UAH',
'dsc' => $description,
'ext_trn_id' => (string)$orderId,
'response_url' => 'https://example.com/webhook/ipay',
'redirect_url' => 'https://example.com/payment/return',
'lang' => 'ru',
],
];
$signData = $body['transaction'];
ksort($signData);
$signString = implode(';', array_values($signData));
$body['auth']['sign'] = hash_hmac('sha512', $signString, $signKey);
$response = Http::post('https://api.ipay.ua/api/v1/transactions', $body);
return $response->json();
}
// Usage:
$result = createIPayTransaction(12345, 1500.00, 'Order #12345');
$paymentUrl = $result['url']; // redirect customer
Notification Processing
public function webhook(Request $request): JsonResponse
{
$data = $request->json()->all();
// Check response signature
$receivedSign = $data['auth']['sign'] ?? '';
$transaction = $data['transaction'];
ksort($transaction);
$expectedSign = hash_hmac('sha512', implode(';', array_values($transaction)), env('IPAY_SIGN_KEY'));
if (!hash_equals($expectedSign, $receivedSign)) {
return response()->json(['error' => 'invalid sign'], 403);
}
$status = $data['transaction']['status'];
$extId = $data['transaction']['ext_trn_id']; // our order ID
if ($status === 'SUCCESS') {
Order::where('id', $extId)->update([
'status' => 'paid',
'transaction_id' => $data['transaction']['id'],
]);
}
return response()->json(['ok' => true]);
}
Transaction statuses: SUCCESS, FAILURE, PROCESSING, REFUNDED.
Transaction Status Check
Additionally to webhook — status check by request on return page:
public function return(Request $request): View
{
$extTrnId = $request->input('ext_trn_id');
$body = [
'auth' => [
'mch_id' => env('IPAY_MERCHANT_ID'),
'salt' => env('IPAY_SALT'),
'sign' => hash_hmac('sha512', $extTrnId, env('IPAY_SIGN_KEY')),
],
'request' => ['ext_trn_id' => $extTrnId],
];
$response = Http::post('https://api.ipay.ua/api/v1/transactions/info', $body);
$status = $response->json('transaction.status');
$order = Order::where('id', $extTrnId)->firstOrFail();
return view('payment.result', ['paid' => $status === 'SUCCESS', 'order' => $order]);
}
Tokenization
iPay supports card saving for subsequent debits. After first payment, card_token returned in transaction data. For repeat debit:
$body = [
'auth' => [...],
'transaction' => [
'mch_id' => env('IPAY_MERCHANT_ID'),
'srv_id' => 1,
's_amount' => 500.00,
's_currency_iso' => 'UAH',
'card_token' => $savedToken,
'ext_trn_id' => 'order-12346',
'dsc' => 'Repeat debit',
],
];
Http::post('https://api.ipay.ua/api/v1/transactions/token', $body);
Refunds
$body = [
'auth' => [...],
'request' => [
'trn_id' => $iPayTransactionId,
'amount' => 750.00, // partial refund
'comment' => 'Customer request refund',
],
];
Http::post('https://api.ipay.ua/api/v1/transactions/refund', $body);
Activation period — 2–4 business days after verification. Transaction limits in first months — clarify with manager.







