Developer Documentation

Integrate HankoPay with a cleaner, safer payment flow.

This page gives your engineering team the HankoPay API contract, including request format, response handling, callbacks, refunds, payouts, wallet balance, and security rules needed to avoid common integration failures.

Go-Live Checklist

  • Use your merchant API key in the `Authorization` header.
  • Send requests from your backend over HTTPS.
  • Provide valid success, failure, and callback URLs.
  • Treat `pending` as an in-progress state, not a final success.
  • Never store CVV and only retain masked card data if needed.

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

  1. Create the transaction with `POST /api/v1/transactions`.
  2. If `paymentLink` is returned, redirect the customer to that URL.
  3. Wait for your callback endpoint to receive the final payment outcome.
  4. If the customer returns before callback arrives, call the status API.
  5. 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.