Payment Flow

Understand the complete payment lifecycle

Overview

A payment goes through several states from creation to completion. The gateway supports two capture methods: direct capture (immediate) and reservation (capture later).

Payment States

CREATED->PROCESSING->REQUIRES_ACTION->PRE_AUTHORIZED->SUCCEEDED
StateCodeDescription
CREATED-Payment intent has been created, awaiting payment method
PROCESSING-Payment is being processed with the provider
REQUIRES_ACTION12OTP verification required — redirect user to payUrl
PRE_AUTHORIZED13Funds reserved, awaiting capture or release
SUCCEEDED2Payment completed successfully
FAILED3Payment was rejected (terminal state)
CANCELED10Pre-authorization was released (terminal state)
REFUNDED4Payment was fully refunded (terminal state)
PARTIALLY_REFUNDED16Payment was partially refunded

Direct Capture Flow

This is the default flow. The payment is captured immediately when processed.

  1. Create Payment Intent — Your server creates a payment intent with the amount and currency. Leave captureMethod as default (DIRECT) or omit it.
  2. Proceed with Wallet — Call proceed with paymentMethodCode: "WALLET_V2".
  3. Handle OTP — If require3DS is true, redirect the user to the payUrl for OTP verification. Append your returnUrl so the user is redirected back after verification.
  4. Check Result — After the user returns, call the Check endpoint to confirm the payment status. A statusCode of 2 means success.
  5. Webhook — Your server receives a webhook with remoteStatusCode: 2 (succeeded) or 3 (rejected).
Direct Capture Flow
// 1. Create intent (server-side)
POST /payments/intents?countryCode=DZA
{ "actionId": "order_123", "amount": 1500, "actionCurrencyCode": "DZD", "userId": "user_1" }

// 2. Proceed with wallet (client-side)
POST /payments/intents/:id/proceed
{ "paymentMethodCode": "WALLET_V2" }

// 3. If require3DS=true, redirect user to payUrl
// 4. After return, check status
GET /payments/intents/:id/check
// → statusCode: 2 (succeeded)

Reservation Flow (Manual Capture)

For scenarios where you need to reserve funds first and capture later (e.g., hotels, car rentals, service bookings), use the reservation flow.

  1. Create Payment Intent — Set captureMethod: "RESERVATION".
  2. Proceed with Wallet — Same as direct flow. If OTP is required, redirect the user.
  3. Pre-Authorized — After successful verification, the payment enters the PRE_AUTHORIZED state (statusCode 13). Funds are reserved in the user's wallet but not yet captured.
  4. Capture or Release — When ready:
    • Capture — Call the Capture endpoint. You can capture the full amount or a partial amount (the remainder is automatically released).
    • Release — Call the Release endpoint to release all reserved funds back to the user.
  5. Webhook — Your server receives a webhook after capture (remoteStatusCode: 2) or release (remoteStatusCode: 10).
Reservation Flow
// 1. Create intent with reservation (server-side)
POST /payments/intents?countryCode=DZA
{ "actionId": "booking_456", "amount": 5000, "actionCurrencyCode": "DZD",
  "userId": "user_1", "captureMethod": "RESERVATION" }

// 2. Proceed with wallet
POST /payments/intents/:id/proceed
{ "paymentMethodCode": "WALLET_V2" }
// → After OTP: statusCode: 13 (pre-authorized)

// 3a. Capture (full or partial)
POST /payments/intents/:id/capture
{ "amount": 4500 }  // captures 4500, releases remaining 500
// → statusCode: 2 (succeeded)

// 3b. OR Release (cancel reservation)
POST /payments/intents/:id/release
{}
// → statusCode: 10 (released)

Refund Flow

After a payment has been successfully captured (statusCode 2), you can refund it fully or partially.

  • Full refund — Omit the amount field. The entire payment amount is refunded to the user's wallet.
  • Partial refund — Specify an amount less than the original payment. The specified amount is refunded.
  • Multiple partial refunds — You can issue multiple partial refunds on the same payment. Each refund reduces the remaining refundable balance until it reaches zero.
Multiple Partial Refunds
// Original payment: 1500 DZD

// Partial refund #1: refund 500
POST /payments/:id/refund
{ "description": "Item returned", "amount": 500 }
// → Remaining refundable: 1000 DZD, webhook: remoteStatusCode 16

// Partial refund #2: refund 300
POST /payments/:id/refund
{ "description": "Service discount", "amount": 300 }
// → Remaining refundable: 700 DZD, webhook: remoteStatusCode 16

// Full refund of remainder
POST /payments/:id/refund
{ "description": "Cancel order" }
// → Remaining refundable: 0 DZD, webhook: remoteStatusCode 4

Webhook Notifications

A webhook is sent to your registered URL after every state change (proceed, capture, release, refund). Use the remoteStatusCode field to determine the event type. See the Webhooks guide for the full payload format.