Quick Start
HankoPay integrations should be server-to-server. Your backend sends the payment request, handles the response, stores the transaction reference, and confirms the final result through callback or status lookup.
Base URL
https://your-api-domain.com/api/v1
Auth Header
Authorization: Bearer YOUR_MERCHANT_API_KEY
Content Type
application/json
Authentication
Every request must include your merchant API key in the bearer token. Do not send dashboard credentials, private secrets, or internal configuration values in this header.
Authorization: Bearer YOUR_MERCHANT_API_KEY
Important: A wrong bearer token can fail the transaction even when the request body is valid.
Recommended Payment Flow
- Create the transaction with `POST /api/v1/transactions`.
- If `paymentLink` is returned, redirect the customer to that URL.
- Wait for your callback endpoint to receive the final payment outcome.
- If the customer returns before callback arrives, call the status API.
- Mark the order as paid only after the transaction is `success`.
Create a Transaction
POST /api/v1/transactions
Send a complete transaction object from your backend. In production, always include `success`, `failure`, and `callback` URLs, plus the shopper IP address.
Example Request
{
"orderId": "ORD-0427215821",
"amount": 500,
"currency": "USD",
"customer": {
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"phone": "+15551234567",
"ipAddress": "203.0.113.10"
},
"billingAddress": {
"street1": "123 Main Street",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"country": "IN",
"postalCode": "10001"
},
"urls": {
"success": "https://example.com/payment-success",
"failure": "https://example.com/payment-failure",
"callback": "https://example.com/payment-callback"
},
"paymentMethod": {
"cardNumber": "4111111111111111",
"cardholderName": "John Doe",
"cardSecurityCode": "029",
"expiryMonth": "01",
"expiryYear": "2030"
},
"metadata": {
"source": "dummy-api-test",
"notes": "test transaction"
}
}
cURL Example
curl -X POST "https://your-api-domain.com/api/v1/transactions" \
-H "Authorization: Bearer YOUR_MERCHANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"orderId": "ORD-0427215821",
"amount": 500,
"currency": "USD",
"customer": {
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"phone": "+15551234567",
"ipAddress": "203.0.113.10"
},
"billingAddress": {
"street1": "123 Main Street",
"street2": "Apt 4B",
"city": "New York",
"state": "NY",
"country": "IN",
"postalCode": "10001"
},
"urls": {
"success": "https://example.com/payment-success",
"failure": "https://example.com/payment-failure",
"callback": "https://example.com/payment-callback"
},
"paymentMethod": {
"cardNumber": "4111111111111111",
"cardholderName": "John Doe",
"cardSecurityCode": "029",
"expiryMonth": "01",
"expiryYear": "2030"
},
"metadata": {
"source": "dummy-api-test",
"notes": "test transaction"
}
}'
Example Response
{
"success": true,
"transactionId": "662d7a1f4d8c91f0b1d2e345",
"orderId": "ORD-0427215821",
"status": "pending",
"statusId": "hkp_status_8fd42a1",
"paymentLink": "https://checkout.hankopay.example/session/8fd42a1",
"createdAt": "2026-04-27T12:30:00.000Z"
}
Heads up: `pending` is normal during redirect and 3DS flows. Do not treat it as a failure or a success.
Check Transaction Status
GET /api/v1/transactions/:transactionId/status
{
"success": true,
"transactionId": "662d7a1f4d8c91f0b1d2e345",
"orderId": "ORD-0427215821",
"status": "success",
"statusReason": "Approved",
"statusId": "hkp_status_8fd42a1",
"updatedAt": "2026-04-27T12:34:10.000Z"
}
List Transactions
GET /api/v1/transactions?limit=50&page=1
Use this endpoint to retrieve paginated transaction history for the authenticated merchant account.
{
"success": true,
"data": [
{
"_id": "662d7a1f4d8c91f0b1d2e345",
"orderId": "ORD-0427215821",
"status": "success",
"fromAmount": 500,
"currency": "USD",
"createdAt": "2026-04-27T12:30:00.000Z"
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 1,
"pages": 1
}
}
Get Transaction Details
GET /api/v1/transactions/:transactionId
Use this endpoint to fetch the current stored record for a specific transaction that belongs to the authenticated merchant.
Callback Handling
- Use a public HTTPS callback endpoint controlled by your backend.
- Return a fast `200 OK` after processing or queueing the event.
- Make callback handling idempotent so retries do not duplicate state changes.
- Verify amount, currency, and order reference before marking the payment complete.
- Do not trust the browser redirect page as the only source of truth.
Refunds
POST /api/v1/transactions/:transactionId/refund
Use this endpoint from your backend for full or partial refunds.
Example Request
{
"amount": 200,
"reason": "Customer requested partial refund",
"metadata": {
"ticketId": "SUP-2049"
}
}
Example Response
{
"success": true,
"refundTransactionId": "662d80574d8c91f0b1d2e999",
"referenceTransactionId": "662d7a1f4d8c91f0b1d2e345",
"status": "pending",
"statusId": "refund-reference-id"
}
Payouts and Wallet Balance
POST /api/v1/payouts
GET /api/v1/wallet/balance
Payout requests require beneficiary details, destination details, and payout-specific payment fields. Check available wallet balance before pushing live payout volume.
Payout Request Example
{
"orderId": "PO-1001",
"amount": 150,
"currency": "USD",
"beneficiary": {
"firstName": "Jane",
"lastName": "Doe",
"email": "jane.doe@example.com",
"phone": "+15557654321",
"ipAddress": "203.0.113.11"
},
"billingAddress": {
"street1": "456 Park Avenue",
"city": "New York",
"state": "NY",
"country": "US",
"postalCode": "10022"
},
"destination": {
"walletId": "wallet_123456"
},
"paymentMethod": {
"cardNumber": "4111111111111111",
"expiryMonth": "01",
"expiryYear": "2030"
},
"urls": {
"callback": "https://example.com/payout-callback"
}
}
Payout Response Example
{
"success": true,
"payoutTransactionId": "662d83094d8c91f0b1d2eb10",
"orderId": "PO-1001",
"status": "pending",
"statusId": "payout-reference-id",
"payoutLink": null,
"createdAt": "2026-04-27T12:42:00.000Z"
}
Wallet Balance Response Example
{
"success": true,
"balance": {
"wallets": [
{
"walletId": "wallet_123456",
"currency": "USD",
"amount": 2500,
"paymentMethod": "card",
"status": "active"
}
]
}
}
Security Requirements
- Send payment requests from your backend, never directly from the browser.
- Never store CVV after authorization. Not raw, not encrypted, not in logs.
- If you must retain card details, store only masked PAN and only where operationally necessary.
- Do not log full request payloads that contain card data.
- Use HTTPS for all callbacks, redirects, and server-to-server requests.
- Keep test and live credentials separated to avoid environment mixups.
Common Integration Mistakes
Wrong bearer token
Use the merchant API key in the `Authorization` header. Do not send dashboard credentials or internal secrets there.
Premature success confirmation
Only finalize the order after callback confirmation or a successful status lookup.
Missing callback or shopper IP
These values help with fraud controls, redirects, and reconciliation. Always send them in production.
Mixing test and live setup
Make sure your API keys, callback URLs, and deployment environment all belong to the same mode.
Storing raw card data
Do not store CVV anywhere. Only store masked card data if a clear operational need exists.