Production Gateway V3

AWDPay Gateway API V3

Professional merchant integration guide for direct payments, payment status verification, available payment methods, secure callbacks, and sandbox testing.

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.

API V3 is designed for merchant integrations where the merchant controls the checkout flow and receives a callback after the payment status changes.

2. Base URL

https://gateway.awdpay.com

3. Authentication

Generate an access token using your merchant API key.

POST https://gateway.awdpay.com/v3/token

Request body

{
  "apiKey": "YOUR_MERCHANT_API_KEY"
}
When 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

The hosted payment page uses public method branding only. For 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"
  }'
In this example, 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.
Public method names are the recommended format for Gateway V3 Payin integrations: 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
}
Never expose your API key in frontend code. Token generation must be done from your backend only.

Use the token on protected routes:

Authorization: Bearer ACCESS_TOKEN

4. Get Available Payment Methods

GET https://gateway.awdpay.com/v3/gateways

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": ["*"]
  }
]
Merchants should call this endpoint dynamically because available methods may change depending on country, currency, and operator availability.

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 methodsawdpay_v2
Natureoperator rail (MTN, Orange, Wave…)AWDPay wallet balance
supportedCountriesexplicit list — ["CI","SN"]["*"]
Scopecountry-specificcountry-independent
Depends onoperator coverage in that countrythe 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.

Do not filter AWDPay out by country. If your checkout builds its method list by matching 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.

Not to be confused with the classic AWDPay merchant payment. AWDPay also offers a wallet-to-wallet merchant payment through API V2 (payment link, QR code). That flow is a different product: it does not go through Gateway V3, creates no V3 transaction, and emits no signed V3 callback. A successful payment through API V2 therefore proves nothing about your V3 integration — the two rails must be validated separately.

5. Create a Payment

POST https://gateway.awdpay.com/v3/payment

Headers

Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN

Request fields

Field Type Required Description
amountnumberYesPayment amount.
currencystringYesXOF, XAF, GNF, USD, EUR.
countrystringYesTwo-letter country code, for example CI, SN, BF.
paymentMethodstring | numberNoRestrict the payment page to a single selected method. Example: "mtn", "orange", "moov", or "wave". Public method names are recommended.
allowedMethodsarrayNoRestrict payment methods for this transaction.
successUrlstringYesCustomer redirect URL after success.
cancelUrlstringYesCustomer redirect URL after cancellation.
callbackUrlstringRecommendedMerchant backend URL to receive payment callback.
sandboxbooleanNoUse true for test payments.
customobjectNoMerchant custom data, such as order ID.
feeByCustomerbooleanNoIf true, payment fees are charged to the customer.
customerNamestringYesCustomer full name.
customerEmailstringYesCustomer email address.
customerAddressstringYesCustomer address or city.
logostringNoMerchant 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"
}
Redirect the customer to redirectUrl to complete the payment.

6. Check Payment Status

Protected status check

GET https://gateway.awdpay.com/v3/payment/check/{trxId}
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

GET https://gateway.awdpay.com/status-check/{trxId}
curl -X GET https://gateway.awdpay.com/status-check/M8VQA190J71Y
{
  "success": true,
  "status": "success"
}

7. Payment Statuses

StatusDescription
pendingPayment created but not yet completed.
successPayment completed successfully.
failedPayment failed or was rejected.
Merchants must consider only 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
HeaderDescription
X-AWDPAY-EventEvent type — payment.success or payment.failed.
X-AWDPAY-TimestampUnix epoch in seconds. Part of the signed message.
X-AWDPAY-SignatureHMAC-SHA256, hexadecimal, prefixed with sha256=.
X-AWDPAY-Signature-KeyWhich 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.

The merchant callback endpoint must return 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.parse followed by JSON.stringify can 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.timingSafeEqual or 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 trxId only 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.

ValueSecret used
merchant_v3Your own V3 webhook key.
globalThe AWDPay Gateway V3 global key, shared by all merchants who have not generated their own key yet.
global_core_key_legacyLegacy fallback, used only when the standard global key is unavailable. Contact AWDPay if you observe it.
The value switches from 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:

PayloadKey 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
Security reminders. 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.

Transactions made with the test key are always sandboxed server-side — no real money can ever be moved, even if the 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:

POST https://gateway.awdpay.com/v3/sandbox/payments/<trxId>/succeed
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
}
ResponseMeaning
200Transaction completed, callback emitted
400status is neither success nor failed
401Missing or invalid token
403A live token was used — a test key is required
409Transaction cannot be completed (see below)
The 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.

RuleBehaviour
status acceptedsuccess or failed only — anything else returns 400
Live transactionsunreachable — only sandbox: 1 transactions can be completed this way
Already completed409 — a transaction is completed once, never twice
Expired409
Financial impactnone — no deposit, no debit, no credit
The 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".
This applies to every payment method, including 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
mtnMTN MoneyBJ, CI, GN, CMXOF, XAF, GNF
orangeOrange MoneyCI, SN, BF, MLXOF, XAF
expressoExpressoSNXOF, XAF
waveWaveSN, CIXOF, XAF
moovMoovCI, BF, BJ, ML, TGXOF, XAF
tmoneyTMoneyTGXOF, XAF
ebillingE-BILLINGGAXAF
airtel_money_gabonAirtel Money GabonGAXAF
moov_money_gabonMoov Money GabonGAXAF
awdpay_v2AWDPay V2Depends on configurationDepends on configuration
moov_burkina_fasoMoov Burkina FasoBFXOF
The official source for available methods is always 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

FieldTypeRequiredDescription
trxIdstringYesTransaction ID returned by Create Payment
phoneNumberstringYesCustomer Orange Money phone number
countrystringYesCountry 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

CountryInstructions
CIDial #144*82#, choose option 2
SNDial #144#391*YOUR_PIN#
BFDial *144*4*6*Amount#
MLDial #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

FieldTypeRequiredDescription
trxIdstringYesTransaction ID
otpstringYesOTP 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.

GET https://gateway.awdpay.com/v3/methods

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
}
Merchants should always call 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.

POST https://gateway.awdpay.com/v3/withdraw

Headers

Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN

Request fields

Field Type Required Description
amountnumberYesWithdraw amount.
currencystringYesXOF, XAF, GNF, USD, or EUR.
countrystringYesTwo-letter country code, for example CI, SN, BF.
paymentMethodnumberYesWithdraw method ID returned by GET /v3/methods.
callbackUrlstringRecommendedMerchant backend URL to receive withdraw status callback.
sandboxbooleanNoUse true to test without triggering a real payout.
customobjectNoMerchant custom data, such as withdraw reference.
customerNamestringYesCustomer full name.
customerEmailstringYesCustomer email address.
customerAddressstringYesCustomer address or city.
numberstringDepends on methodMobile money number required for most mobile money payout methods.
extWalletstringDepends on methodExternal 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
  }
}
In production, when 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
  }
}
In this response, amount is the amount sent to the customer, while total is the amount debited from the merchant balance.
If the payout fails or times out, AWDPay refunds the merchant the full debited total (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.

GET https://gateway.awdpay.com/v3/withdraw/{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

  1. Never expose your merchant API key in frontend code.
  2. Generate the AWDPay token from your backend only.
  3. Create payments from your backend only.
  4. Redirect the customer to redirectUrl.
  5. Store trxId with your internal order.
  6. Do not mark an order as paid only because the customer returns to successUrl.
  7. Always verify payment status using callback or /v3/payment/check/{trxId}.
  8. Always verify X-AWDPAY-Signature before confirming an order.
  9. For withdrawals, the customer receives amount; the merchant is debited amount + fee.
  10. Always use GET /v3/methods before creating a withdrawal to get current Gateway V3 limits and fees.
  11. Use "sandbox": true for withdrawal testing to avoid triggering a real payout.
  12. Respond with HTTP 200 OK after receiving a valid callback.
  13. Only success should 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