1. Overview
AWDPay Gateway API V3 allows merchants to create payment requests directly from their own backend, redirect customers to the AWDPay payment page, and receive payment status updates through secure server-to-server callbacks.
2. Base URL
https://gateway.awdpay.com
3. Authentication
Generate an access token using your merchant API key.
Request body
{
"apiKey": "YOUR_MERCHANT_API_KEY"
}
paymentMethod is provided, the payment page displays only the selected method.
If no paymentMethod or allowedMethods is provided, Gateway V3 displays all compatible methods for the selected country and currency.
Wave redirect behavior
When paymentMethod is set to "wave", the hosted payment page displays Wave only.
After the customer starts the payment, Gateway V3 returns a Wave redirect URL.
{
"success": true,
"message": "Token generated successfully",
"gateway": "wave",
"redirectUrl": "https://pay.wave.com/...",
"tokenInfo": {
"paymentMethod": "wave",
"redirect": "https://pay.wave.com/...",
"redirectUrl": "https://pay.wave.com/..."
}
}
Selected payment method example
wave displays Wave with the Wave logo. Internal provider codes are never exposed
on the payment page or in the public documentation.
curl -X POST https://gateway.awdpay.com/v3/payment \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-d '{
"amount": 300,
"currency": "XOF",
"country": "CI",
"paymentMethod": "wave",
"customerName": "First Last",
"customerEmail": "test@example.com",
"customerAddress": "Abidjan",
"successUrl": "https://merchant.com/payment/success",
"cancelUrl": "https://merchant.com/payment/cancel",
"callbackUrl": "https://merchant.com/api/awdpay/callback"
}'
paymentMethod restricts the hosted payment page to the selected method only. Public method names are recommended to avoid numeric ID confusion.
Recommended public method codes are mtn, orange, moov, and wave. Numeric IDs are supported only for backward compatibility.
mtn, orange, moov, and wave.
Numeric IDs are supported only for backward compatibility. Current legacy mapping:
20 opens wave.
cURL example
curl -X POST https://gateway.awdpay.com/v3/token \
-H "Content-Type: application/json" \
-d '{
"apiKey": "YOUR_MERCHANT_API_KEY"
}'
Success response
{
"success": true,
"token": "ACCESS_TOKEN",
"expiredIn": 3600
}
Use the token on protected routes:
Authorization: Bearer ACCESS_TOKEN
4. Get Available Payment Methods
cURL example
curl -X GET https://gateway.awdpay.com/v3/gateways
Response example
[
{
"value": "mtn",
"name": "MTN Money",
"supportedCurrencies": ["XOF", "XAF", "GNF"],
"supportedCountries": ["BJ", "CI", "GN", "CM"]
},
{
"value": "wave",
"name": "Wave",
"supportedCurrencies": ["XOF", "XAF"],
"supportedCountries": ["SN", "CI"]
},
{
"value": "awdpay_v2",
"name": "AWDPay",
"supportedCurrencies": ["XOF", "XAF", "USD", "EUR", "GNF"],
"supportedCountries": ["*"]
}
]
AWDPay availability
awdpay_v2 is not a mobile money operator. It is payment by
AWDPay Wallet balance: the customer settles from the balance held in
their AWDPay account.
This changes how availability works:
| Mobile money methods | awdpay_v2 | |
|---|---|---|
| Nature | operator rail (MTN, Orange, Wave…) | AWDPay wallet balance |
supportedCountries | explicit list — ["CI","SN"] | ["*"] |
| Scope | country-specific | country-independent |
| Depends on | operator coverage in that country | the customer's AWDPay balance |
The value "*" in supportedCountries is the marker of a
global method. It means every country: an AWDPay account works the same
way regardless of where its holder is.
supportedCountries against the customer's country, treat
"*" as always matching. A strict equality test drops AWDPay from
every country, and your customers will never see it.
country remains required when creating a payment — it
describes the transaction, not the eligibility of AWDPay. Sending
"country": "CI" does not restrict AWDPay to Côte d'Ivoire.
What does condition the payment is the currency: the customer must hold
a sufficient AWDPay balance in the currency of the transaction. A wallet
funded in XOF cannot settle a payment created in EUR. Supported currencies are listed in
supportedCurrencies.
Whenever the AWDPay rail is enabled, awdpay_v2 must appear in the
/v3/gateways list. Its absence indicates the rail is disabled, not a
geographic restriction.
5. Create a Payment
Headers
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
amount | number | Yes | Payment amount. |
currency | string | Yes | XOF, XAF, GNF, USD, EUR. |
country | string | Yes | Two-letter country code, for example CI, SN, BF. |
paymentMethod | string | number | No | Restrict the payment page to a single selected method. Example: "mtn", "orange", "moov", or "wave". Public method names are recommended. |
allowedMethods | array | No | Restrict payment methods for this transaction. |
successUrl | string | Yes | Customer redirect URL after success. |
cancelUrl | string | Yes | Customer redirect URL after cancellation. |
callbackUrl | string | Recommended | Merchant backend URL to receive payment callback. |
sandbox | boolean | No | Use true for test payments. |
custom | object | No | Merchant custom data, such as order ID. |
feeByCustomer | boolean | No | If true, payment fees are charged to the customer. |
customerName | string | Yes | Customer full name. |
customerEmail | string | Yes | Customer email address. |
customerAddress | string | Yes | Customer address or city. |
logo | string | No | Merchant logo URL. |
cURL example
curl -X POST https://gateway.awdpay.com/v3/payment \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-d '{
"amount": 1000,
"currency": "XOF",
"country": "CI",
"allowedMethods": ["wave", "mtn", "orange", "moov"],
"successUrl": "https://merchant.com/payment/success",
"cancelUrl": "https://merchant.com/payment/cancel",
"callbackUrl": "https://merchant.com/api/awdpay/callback",
"sandbox": false,
"custom": {
"orderId": "CMD-2026-0001",
"customerId": "CLIENT-1001"
},
"feeByCustomer": false,
"customerName": "John Doe",
"customerEmail": "john@example.com",
"customerAddress": "Abidjan"
}'
Success response
{
"success": true,
"message": "Payment created successfully",
"trxId": "M8VQA190J71Y",
"redirectUrl": "https://gateway.awdpay.com/payment/M8VQA190J71Y"
}
redirectUrl to complete the payment.
6. Check Payment Status
Protected status check
curl -X GET https://gateway.awdpay.com/v3/payment/check/M8VQA190J71Y \
-H "Authorization: Bearer ACCESS_TOKEN"
Response example
{
"success": true,
"data": {
"trxId": "M8VQA190J71Y",
"status": "success",
"sandbox": false,
"amount": 1000,
"fee": 0,
"currency": "XOF",
"country": "CI",
"custom": {
"orderId": "CMD-2026-0001"
},
"paidWith": "mtn",
"customer": {
"name": "John Doe",
"email": "john@example.com",
"address": "Abidjan"
}
}
}
Public status check
curl -X GET https://gateway.awdpay.com/status-check/M8VQA190J71Y
{
"success": true,
"status": "success"
}
7. Payment Statuses
| Status | Description |
|---|---|
| pending | Payment created but not yet completed. |
| success | Payment completed successfully. |
| failed | Payment failed or was rejected. |
success as final payment confirmation.
8. Merchant Callback
AWDPay sends an HTTP POST request to the merchant’s callbackUrl
when the payment status changes.
Callback payload example
{
"type": "payment",
"event": "payment.success",
"trxId": "M8VQA190J71Y",
"status": "success",
"amount": 1000,
"fee": 0,
"currency": "XOF",
"country": "CI",
"sandbox": false,
"paidWith": "mtn",
"custom": {
"orderId": "CMD-2026-0001",
"customerId": "CLIENT-1001"
},
"customer": {
"name": "John Doe",
"email": "john@example.com",
"address": "Abidjan"
},
"transactedAt": "2026-05-09T07:39:33.000+00:00"
}
Callback headers
Content-Type: application/json
X-AWDPAY-Event: payment.success
X-AWDPAY-Signature: sha256=<RECEIVED_SIGNATURE>
X-AWDPAY-Timestamp: <TIMESTAMP>
X-AWDPAY-Signature-Key: merchant_v3
| Header | Description |
|---|---|
X-AWDPAY-Event | Event type — payment.success or payment.failed. |
X-AWDPAY-Timestamp | Unix epoch in seconds. Part of the signed message. |
X-AWDPAY-Signature | HMAC-SHA256, hexadecimal, prefixed with sha256=. |
X-AWDPAY-Signature-Key | Which key was used to sign. See section 9. |
All four headers are present on every callback, for both
payment.success and payment.failed, in every environment.
HTTP 200 OK after successfully receiving and processing the callback.
9. Webhook signature verification
Use the raw request body and your webhook secret to verify X-AWDPAY-Signature.
Signature formula
message = <TIMESTAMP> + "." + <RAW_BODY>
signature = "sha256=" + HMAC_SHA256_HEX(<WEBHOOK_SECRET>, message)
<TIMESTAMP> is the exact value of the X-AWDPAY-Timestamp
header. <RAW_BODY> is the exact byte sequence of the request body,
as received.
Rules
- Use the exact raw body received. Capture it before any JSON parsing middleware runs.
- Never rebuild the JSON after parsing. A
JSON.parsefollowed byJSON.stringifycan reorder keys or change spacing, and the signature will no longer match. - Do not alter whitespace, field order or encoding in any way.
- Compare in constant time — use
crypto.timingSafeEqualor an equivalent, never==or!==. - Reject invalid signatures. Refuse to process the callback — logging it and continuing is not rejecting it.
- Reject stale timestamps. A window of 5 minutes is recommended, to prevent replay.
- Process each
trxIdonly once, for failures as well as successes.
Which key signed the callback
The X-AWDPAY-Signature-Key header tells you which secret was used.
Always read this header before choosing your verification key.
| Value | Secret used |
|---|---|
merchant_v3 | Your own V3 webhook key. |
global | The AWDPay Gateway V3 global key, shared by all merchants who have not generated their own key yet. |
global_core_key_legacy | Legacy fallback, used only when the standard global key is unavailable. Contact AWDPay if you observe it. |
global to merchant_v3 the moment you
generate your own key — automatically, on the very next callback, with no prior notice.
A verifier hard-coded to a single key will break at that point. Read the header.
Test and production keys are separate
When X-AWDPAY-Signature-Key is merchant_v3, you hold two independent
keys. Select the one matching the sandbox field of the payload:
| Payload | Key to use |
|---|---|
"sandbox": 1 (or true) | your TEST V3 webhook key |
"sandbox": 0 (or false) | your LIVE V3 webhook key |
Never reuse the same value across both environments: a leak on the test side would compromise production.
Key selection — pseudo-code
if (header["X-AWDPAY-Signature-Key"] == "merchant_v3") {
secret = payload.sandbox ? <MERCHANT_TEST_WEBHOOK_SECRET>
: <MERCHANT_LIVE_WEBHOOK_SECRET>
} else {
secret = <AWDPAY_GLOBAL_WEBHOOK_SECRET>
}
expected = "sha256=" + HMAC_SHA256_HEX(secret, <TIMESTAMP> + "." + <RAW_BODY>)
if (!constantTimeEquals(expected, <RECEIVED_SIGNATURE>)) reject()
if (now() - <TIMESTAMP> > 300) reject()
if (alreadyProcessed(payload.trxId)) return 200
if (payload.sandbox) return 200 // deliver nothing
successUrl is a browser redirect. It is neither signed nor authenticated,
and anyone who knows the address can open it — it proves no payment.
Only a callback whose signature you verified, or a server-side status check, is proof.
A payment carrying
"sandbox": 1 is a test payment:
deliver nothing, credit nothing, confirm nothing, activate nothing —
including from a staging environment connected to live data.
Node.js example
import crypto from "crypto";
function verifyAwdpaySignature(rawBody, signatureHeader, timestampHeader, webhookSecret) {
const expectedSignature =
"sha256=" +
crypto
.createHmac("sha256", webhookSecret)
.update(`${timestampHeader}.${rawBody.toString("utf8")}`)
.digest("hex");
const expected = Buffer.from(expectedSignature);
const received = Buffer.from(String(signatureHeader || ""));
// timingSafeEqual throws on length mismatch, so compare lengths first.
// This only reveals the length, never the content.
if (expected.length !== received.length) return false;
return crypto.timingSafeEqual(expected, received);
}
// Pick the key from the headers and the payload, never assume one.
function pickWebhookSecret(signatureKeyHeader, isSandbox) {
if (signatureKeyHeader === "merchant_v3") {
return isSandbox
? process.env.AWDPAY_WEBHOOK_SECRET_TEST
: process.env.AWDPAY_WEBHOOK_SECRET_LIVE;
}
return process.env.AWDPAY_WEBHOOK_SECRET_GLOBAL;
}
Express callback example
import express from "express";
import crypto from "crypto";
const app = express();
app.post(
"/api/awdpay/callback",
// express.raw keeps the exact bytes. Do NOT use express.json() here:
// a parsed-then-restringified body will not match the signature.
express.raw({ type: "application/json" }),
(req, res) => {
const signature = req.headers["x-awdpay-signature"];
const timestamp = req.headers["x-awdpay-timestamp"];
const signatureKey = req.headers["x-awdpay-signature-key"];
const rawBody = req.body;
// Parsed only to read `sandbox`, which decides which key to use.
// The signature is still verified against rawBody, never against this object.
const payload = JSON.parse(rawBody.toString("utf8"));
const webhookSecret = pickWebhookSecret(signatureKey, Boolean(payload.sandbox));
if (!verifyAwdpaySignature(rawBody, signature, timestamp, webhookSecret)) {
return res.status(401).json({
success: false,
message: "Invalid signature"
});
}
// Replay protection: reject timestamps older than 5 minutes.
if (Math.abs(Math.floor(Date.now() / 1000) - Number(timestamp)) > 300) {
return res.status(401).json({
success: false,
message: "Stale timestamp"
});
}
// Test payments must never trigger any business action.
if (payload.sandbox) {
return res.status(200).json({ success: true, message: "Sandbox ignored" });
}
// Idempotency: trxId is the key, for failures as well as successes.
if (alreadyProcessed(payload.trxId)) {
return res.status(200).json({ success: true, message: "Already processed" });
}
if (payload.status === "success") {
// Mark your order as paid using payload.custom.orderId
}
return res.status(200).json({
success: true,
message: "Callback received"
});
}
);
app.listen(3000);
10. Sandbox Mode & Test API Key
Test API Key (recommended)
Every merchant account now has a dedicated test API key, available in your merchant dashboard under Integration → Test toggle. It can be regenerated independently from your production key.
sandbox parameter is omitted or set
to false. You can integrate and test with zero financial risk.
# 1. Get a token with your TEST key
curl -X POST https://gateway.awdpay.com/v3/token \
-H "Content-Type: application/json" \
-d '{"apiKey": "YOUR_TEST_KEY"}'
# 2. Any transaction is automatically sandboxed
curl -X POST https://gateway.awdpay.com/v3/withdraw \
-H "Content-Type: application/json" \
-H "Authorization: Bearer THE_TOKEN" \
-d '{"amount":300, "currency":"XOF", "country":"CI", "paymentMethod":8,
"number":"0700000000", "customerName":"Test Client",
"customerEmail":"test@example.com", "customerAddress":"Abidjan"}'
The response contains "sandbox": true and a trxId you can track like a real transaction. To go live, simply switch to your production key.
Sandbox parameter (with production key)
Alternatively, you can use "sandbox": true in the payment creation request with
your production key to create a one-off test transaction.
{
"amount": 100,
"currency": "XOF",
"country": "CI",
"sandbox": true,
"callbackUrl": "https://merchant.com/api/awdpay/callback"
}
Completing a sandbox payment
A sandbox transaction is created as pending. Left alone, it expires after
15 minutes and becomes failed. To obtain a
payment.success callback in test, you must complete it
explicitly — no real money is ever involved.
Two equivalent ways:
1. From the sandbox simulator page. After creating the payment, the checkout redirects to:
https://gateway.awdpay.com/payment/<trxId>/sandbox
Choose Success or Failed and confirm.
2. Programmatically, with your test API key — the recommended way for automated test suites:
curl -X POST https://gateway.awdpay.com/v3/sandbox/payments/<trxId>/succeed \
-H "Authorization: Bearer <TEST_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"status": "success"}'
status is optional and defaults to success; the only other
accepted value is failed. The token must come from your
test API key.
Success response:
{
"success": true,
"message": "Sandbox transaction completed",
"trxId": "<trxId>",
"status": "success",
"sandbox": true
}
| Response | Meaning |
|---|---|
200 | Transaction completed, callback emitted |
400 | status is neither success nor failed |
401 | Missing or invalid token |
403 | A live token was used — a test key is required |
409 | Transaction cannot be completed (see below) |
409 is returned identically whether the transaction does not exist, is
live, has already been completed, has expired, or belongs to another
merchant. This is deliberate: the response reveals nothing about transactions
you do not own.
Compared with the public /sandbox-payment endpoint used by the simulator
page, this route additionally verifies that the transaction belongs to the
merchant behind the token, and refuses live API keys outright. Prefer it in any
automated integration test.
3. The public endpoint used by the simulator page remains available:
curl -X POST https://gateway.awdpay.com/sandbox-payment \
-H "Content-Type: application/json" \
-d '{"trxId": "<trxId>", "status": "success"}'
The callback is then emitted through the normal dispatcher: same
signature algorithm, same key selection, same headers as a live payment. You will receive
event: payment.success, X-AWDPAY-Signature-Key: merchant_v3
(if your test webhook key is generated) and "sandbox": 1 in the body.
| Rule | Behaviour |
|---|---|
status accepted | success or failed only — anything else returns 400 |
| Live transactions | unreachable — only sandbox: 1 transactions can be completed this way |
| Already completed | 409 — a transaction is completed once, never twice |
| Expired | 409 |
| Financial impact | none — no deposit, no debit, no credit |
409 response is deliberately identical whether the transaction does not
exist, is live, or has already been completed. Do not infer anything from it beyond
"this transaction cannot be completed".
awdpay_v2.
A sandbox awdpay_v2 payment is completed here, on the gateway — not on the
AWDPay wallet page, which refuses test settlements by design so that no real balance can
ever be touched.
11. Observed Payment Method IDs
| Method ID | Name | Countries | Currencies |
|---|---|---|---|
mtn | MTN Money | BJ, CI, GN, CM | XOF, XAF, GNF |
orange | Orange Money | CI, SN, BF, ML | XOF, XAF |
expresso | Expresso | SN | XOF, XAF |
wave | Wave | SN, CI | XOF, XAF |
moov | Moov | CI, BF, BJ, ML, TG | XOF, XAF |
tmoney | TMoney | TG | XOF, XAF |
ebilling | E-BILLING | GA | XAF |
airtel_money_gabon | Airtel Money Gabon | GA | XAF |
moov_money_gabon | Moov Money Gabon | GA | XAF |
awdpay_v2 | AWDPay V2 | Depends on configuration | Depends on configuration |
moov_burkina_faso | Moov Burkina Faso | BF | XOF |
GET /v3/gateways.
12. Orange Money — OTP Payment Flow
Orange Money payments require a two-step OTP flow. The customer must generate a temporary payment code on their phone before confirming the payment.
This flow applies to the following countries: CI, SN, BF, ML.
Step 1 — Initialize the payment
After creating a payment with paymentMethod: "orange", call this endpoint to initialize the Orange Money flow and receive OTP instructions.
POST /v3/orange/init
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
trxId | string | Yes | Transaction ID returned by Create Payment |
phoneNumber | string | Yes | Customer Orange Money phone number |
country | string | Yes | Country code: CI, SN, BF, or ML |
Response
{
"success": true,
"trxId": "ABC123XYZ",
"otpRequired": true,
"otpInstructions": "Dial #144*82# on your Orange Money phone, choose option 2, then enter the generated payment code."
}
OTP Instructions by Country
| Country | Instructions |
|---|---|
| CI | Dial #144*82#, choose option 2 |
| SN | Dial #144#391*YOUR_PIN# |
| BF | Dial *144*4*6*Amount# |
| ML | Dial #144#77# |
Step 2 — Confirm with OTP
Once the customer has generated their OTP code, submit it to confirm the payment.
POST /v3/orange/confirm
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
trxId | string | Yes | Transaction ID |
otp | string | Yes | OTP code generated by the customer |
Response
{
"success": true,
"message": "Orange Money payment confirmed successfully.",
"trxId": "ABC123XYZ"
}
12. Withdraw / Payout Methods
Use this endpoint to retrieve the list of available withdraw/payout methods. The response includes method ID, country, currency, minimum amount, maximum amount, API availability, and fees.
Headers
Authorization: Bearer ACCESS_TOKEN
cURL example
curl -X GET https://gateway.awdpay.com/v3/methods \
-H "Authorization: Bearer ACCESS_TOKEN"
Response example
{
"data": [
{
"id": 8,
"name": "MTN Money CIV",
"minAmount": 300,
"maxAmount": 100000,
"currency": "XOF",
"percentageCharge": 2.5,
"country": "CI",
"active_api": true,
"recommanded": true
},
{
"id": 39,
"name": "WAVE Côte d'ivoire",
"minAmount": 300,
"maxAmount": 100000,
"currency": "XOF",
"percentageCharge": 3,
"country": "CI",
"active_api": true,
"recommanded": false
}
],
"count": 21
}
GET /v3/methods before creating a withdrawal,
because active methods, limits, fees, countries, and currencies may change.
13. Create Withdraw / Payout
This endpoint creates a withdraw request from the merchant account to a customer wallet.
The amount field is always the amount the customer should receive.
Gateway V3 calculates the withdraw fee and the merchant debit total automatically.
For testing, use "sandbox": true. In sandbox mode, AWDPay creates a local pending
withdraw record without triggering a real payout.
Headers
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
amount | number | Yes | Withdraw amount. |
currency | string | Yes | XOF, XAF, GNF, USD, or EUR. |
country | string | Yes | Two-letter country code, for example CI, SN, BF. |
paymentMethod | number | Yes | Withdraw method ID returned by GET /v3/methods. |
callbackUrl | string | Recommended | Merchant backend URL to receive withdraw status callback. |
sandbox | boolean | No | Use true to test without triggering a real payout. |
custom | object | No | Merchant custom data, such as withdraw reference. |
customerName | string | Yes | Customer full name. |
customerEmail | string | Yes | Customer email address. |
customerAddress | string | Yes | Customer address or city. |
number | string | Depends on method | Mobile money number required for most mobile money payout methods. |
extWallet | string | Depends on method | External wallet identifier, required for specific wallet-based methods. |
Sandbox cURL example
curl -X POST https://gateway.awdpay.com/v3/withdraw \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-d '{
"amount": 300,
"currency": "XOF",
"country": "CI",
"paymentMethod": 8,
"callbackUrl": "https://merchant.com/api/awdpay/withdraw-callback",
"sandbox": true,
"custom": {
"withdrawRef": "WD-SANDBOX-001",
"source": "manual_test"
},
"customerName": "Client Retrait Test",
"customerEmail": "withdraw.test@example.com",
"customerAddress": "Abidjan",
"number": "0101010101"
}'
Sandbox success response
{
"success": true,
"message": "Withdraw sandbox created successfully",
"data": {
"trxId": "CPJ8P3GQA4OE",
"status": "pending",
"amount": 300,
"fee": 0,
"total": 300,
"withdrawId": null,
"sandbox": true
}
}
sandbox is omitted or set to false, the request may trigger a real payout.
Merchants must ensure KYC, balance, customer number, country, currency, and method limits are valid before creating a real withdrawal.
14. Withdraw Fees & Merchant Debit
For API V3 withdrawals, the customer receives the requested amount.
The merchant is debited the requested amount plus the Gateway V3 withdraw fee.
Calculation rule
fee = amount × percentageCharge / 100
total = amount + fee
Example
| Item | Value | Description |
|---|---|---|
amount |
500 XOF |
Amount sent to the customer. |
percentageCharge |
2.5% |
Gateway V3 withdraw fee for the selected method. |
fee |
12.5 XOF |
Fee paid by the merchant. |
total |
512.5 XOF |
Total debited from the merchant AWDPay wallet. |
Response example
{
"success": true,
"message": "Withdraw is pending",
"data": {
"trxId": "SG8MN2U9YJHP",
"status": "pending",
"amount": 500,
"fee": 12.5,
"total": 512.5,
"currency": "XOF",
"country": "CI",
"paymentMethod": 8,
"withdrawId": 51056,
"sandbox": false
}
}
amount is the amount sent to the customer,
while total is the amount debited from the merchant balance.
amount + fee), not only the customer amount.
15. Check Withdraw Status
Use this endpoint to verify the status of a withdraw request using its trxId.
Headers
Authorization: Bearer ACCESS_TOKEN
cURL example
curl -X GET https://gateway.awdpay.com/v3/withdraw/CPJ8P3GQA4OE \
-H "Authorization: Bearer ACCESS_TOKEN"
Response example
{
"success": true,
"data": {
"trxId": "CPJ8P3GQA4OE",
"status": "pending",
"amount": 300,
"fee": 0,
"total": 300,
"withdrawId": null,
"sandbox": true
}
}
16. Integration Best Practices
- Never expose your merchant API key in frontend code.
- Generate the AWDPay token from your backend only.
- Create payments from your backend only.
- Redirect the customer to
redirectUrl. - Store
trxIdwith your internal order. - Do not mark an order as paid only because the customer returns to
successUrl. - Always verify payment status using callback or
/v3/payment/check/{trxId}. - Always verify
X-AWDPAY-Signaturebefore confirming an order. - For withdrawals, the customer receives
amount; the merchant is debitedamount + fee. - Always use
GET /v3/methodsbefore creating a withdrawal to get current Gateway V3 limits and fees. - Use
"sandbox": truefor withdrawal testing to avoid triggering a real payout. - Respond with
HTTP 200 OKafter receiving a valid callback. - Only
successshould be treated as final payment confirmation.
17. Support Information
When contacting AWDPay support, please provide:
trxId- Transaction date
- Amount and currency
- Country
- Payment method used
- API response received
- Callback URL concerned