Skip to content

Select Payment Method

Select a payment method for a checkout session. Returns the payment details the customer needs to complete the transfer.

POST /v1/checkout/session/:sessionId/payment-method

Required permission: checkout

Authentication

Requires an API key. Origin/domain validation is enforced for public keys.

Path parameters

ParameterTypeDescription
sessionIdstringThe checkout session ID

Request body

ParameterTypeRequiredDescription
payment_methodstringYes"bank_transfer" or "payid"

Example request

bash
curl -X POST https://api.zevpaycheckout.com/v1/checkout/session/ecc48011-e36e-4741-9b99-657f4a1ee86e/payment-method \
  -H "Content-Type: application/json" \
  -H "x-api-key: pk_test_your_public_key" \
  -d '{"payment_method": "bank_transfer"}'

Response: Bank Transfer

When payment_method is "bank_transfer", a temporary virtual account is created. Show the customer account_number, bank_name and account_name exactly as returned. ZevPay mints these accounts through partner banks and rotates partners over time, so the bank differs between sessions.

json
{
  "success": true,
  "data": {
    "payment_method": "bank_transfer",
    "account_number": "5000973258",
    "bank_name": "9 Payment Service Bank",
    "bank_code": "000036",
    "account_name": "Your Business Name",
    "amount": 500000,
    "expires_at": "2026-03-07T19:37:00.000Z",
    "banks": [
      { "provider": "psb9", "bank_name": "9 Payment Service Bank", "bank_code": "000036", "current": true },
      { "provider": "palmpay", "bank_name": "PalmPay", "bank_code": "100039", "current": false }
    ]
  }
}
FieldTypeDescription
payment_methodstringAlways "bank_transfer"
account_numberstringVirtual account number for the transfer
bank_namestringBank the customer must select. Not fixed: read it per session, never hardcode it
bank_codestringNIP code for the bank, for UIs that match on code
account_namestringMerchant's business name (or "ZevPay Checkout" if not configured)
amountintegerAmount in kobo the customer should transfer
expires_atstringISO 8601 timestamp: when the virtual account expires
banksarrayEvery bank this session can be paid into, with the active one flagged current

Letting the customer change bank

Some customers cannot complete a transfer to a given bank. The banks array is the list you can offer them. Render it as a "change bank" control and call Switch Bank with the chosen provider.

The list is served per session, so a bank added on our side appears in your checkout with no change on yours. Never hardcode it.

Switch Bank

Move a pending bank transfer to another bank without starting a new session.

POST /v1/checkout/session/:sessionId/switch-bank

Required permission: checkout

Request body

ParameterTypeRequiredDescription
providerstringYesA provider value from the banks array

Example request

bash
curl -X POST https://api.zevpaycheckout.com/v1/checkout/session/ecc48011-e36e-4741-9b99-657f4a1ee86e/switch-bank \
  -H "Content-Type: application/json" \
  -H "x-api-key: pk_test_your_public_key" \
  -d '{"provider": "palmpay"}'

The response is the same bank transfer payload shown above, carrying the new account_number, bank_name and refreshed banks list.

The old account number stops working

Switching retires the previous account before issuing the new one, so the same session can never be paid twice. Replace the account number on screen as soon as the call returns, and never show two at once.

The amount, reference and session are unchanged. Payment webhooks and verification behave exactly as they would have on the original bank.

Switch bank errors

StatusCodeCause
400BANK_UNAVAILABLEThe provider is not in the session's banks list
503BANK_SWITCH_FAILEDThe previous account could not be retired. Retry shortly

Response: PayID

When payment_method is "payid", a dynamic PayID is created:

json
{
  "success": true,
  "data": {
    "payment_method": "payid",
    "pay_id": "5de2.dypid",
    "qr_data": "https://zevpay.me/5de2.dypid",
    "amount": 500000,
    "expires_at": "2026-03-07T19:37:00.000Z"
  }
}
FieldTypeDescription
payment_methodstringAlways "payid"
pay_idstringDynamic PayID for the payment
qr_datastringURL for QR code generation (https://zevpay.me/{payId})
amountintegerAmount in kobo
expires_atstringISO 8601 timestamp: when the dynamic PayID expires

Behavior

  • Calling this endpoint multiple times for the same method reuses the existing virtual account or PayID (as long as it's still active/pending)
  • Switching methods (e.g., from bank_transfer to payid) logs a method_switched event and increments the attempt counter
  • Switching methods also retires what the customer left behind, so a session is never payable in two places at once. Stop showing the previous account number as soon as you switch: it no longer accepts payment
  • The session must be active; expired, completed, or failed sessions return an error

Errors

StatusMessageCause
400Session is {status}.Session is not active (e.g., "Session is completed.")
400Session has expired.Session's expiry time has passed
400Unsupported payment method:Invalid payment_method value
400Session does not belong to this API key.API key mismatch
401Invalid API keyKey not found or inactive
404Session not found.Invalid session ID

Try it

API Playground
POSThttps://api.zevpaycheckout.com/v1/checkout/session/:sessionId/payment-method

ZevPay Checkout Developer Documentation