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
| State | Code | Description |
|---|---|---|
CREATED | - | Payment intent has been created, awaiting payment method |
PROCESSING | - | Payment is being processed with the provider |
REQUIRES_ACTION | 12 | OTP verification required — redirect user to payUrl |
PRE_AUTHORIZED | 13 | Funds reserved, awaiting capture or release |
SUCCEEDED | 2 | Payment completed successfully |
FAILED | 3 | Payment was rejected (terminal state) |
CANCELED | 10 | Pre-authorization was released (terminal state) |
REFUNDED | 4 | Payment was fully refunded (terminal state) |
PARTIALLY_REFUNDED | 16 | Payment was partially refunded |
Direct Capture Flow
This is the default flow. The payment is captured immediately when processed.
- Create Payment Intent — Your server creates a payment intent with the amount and currency. Leave
captureMethodas default (DIRECT) or omit it. - Proceed with Wallet — Call proceed with
paymentMethodCode: "WALLET_V2". - Handle OTP — If
require3DSistrue, redirect the user to thepayUrlfor OTP verification. Append yourreturnUrlso the user is redirected back after verification. - Check Result — After the user returns, call the Check endpoint to confirm the payment status. A
statusCodeof2means success. - Webhook — Your server receives a webhook with
remoteStatusCode: 2(succeeded) or3(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)// 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.
- Create Payment Intent — Set
captureMethod: "RESERVATION". - Proceed with Wallet — Same as direct flow. If OTP is required, redirect the user.
- Pre-Authorized — After successful verification, the payment enters the
PRE_AUTHORIZEDstate (statusCode13). Funds are reserved in the user's wallet but not yet captured. - 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.
- 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)// 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
amountfield. The entire payment amount is refunded to the user's wallet. - Partial refund — Specify an
amountless 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// 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 4Webhook 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.