AWDPay Checkout API V2

Merchant integration guide for hosted checkout payments, OTP validation, payment confirmation, status verification, and secure callbacks.

1. Overview

AWDPay Checkout API V2 allows a merchant to initiate a payment from their platform, redirect the customer to AWDPay for OTP/payment confirmation, and receive payment status updates.

Recommended routes for new integrations use /api/v2/checkout/.... Older routes using /api/checkout/v2/... may remain available for existing integrations.

2. Base URL

https://www.awdpay.com

3. Authentication

All protected requests must include the merchant private key in the Authorization header.

Authorization: Bearer YOUR_PRIVATE_KEY
Content-Type: application/json
Never expose your private key in frontend code. All API calls must be made from your backend.

4. Initiate Checkout

Create a checkout transaction and receive a hosted payment URL.

POST https://www.awdpay.com/api/v2/checkout/initiate

Request body

FieldTypeRequiredDescription
amountnumberYesPayment amount.
currencystringYesCurrency code, for example XOF, USD, EUR.
customIdentifierstringYesYour internal order/payment reference.
callbackUrlstringRecommendedWebhook URL to receive payment updates.
successUrlstringYesCustomer redirect URL after successful payment.
failedUrlstringYesCustomer redirect URL if payment fails or is cancelled.
logostringNoMerchant logo URL displayed on checkout page.
testbooleanNoUse true for test mode and false for production.

cURL example

curl -X POST https://www.awdpay.com/api/v2/checkout/initiate \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_PRIVATE_KEY" \
  -d '{
    "amount": 1000,
    "currency": "XOF",
    "customIdentifier": "ORDER-2026-0001",
    "callbackUrl": "https://merchant.com/api/awdpay/v2/callback",
    "successUrl": "https://merchant.com/payment/success",
    "failedUrl": "https://merchant.com/payment/failed",
    "logo": "https://merchant.com/logo.png",
    "test": false
  }'

Success response

{
  "success": true,
  "message": "Checkout initiated successfully",
  "trxId": "TRX_ID",
  "redirectUrl": "https://www.awdpay.com/checkout/..."
}

5. Send Customer OTP

Send or validate the customer OTP step depending on the checkout flow.

POST https://www.awdpay.com/api/v2/checkout/customer/otp

Example

curl -X POST https://www.awdpay.com/api/v2/checkout/customer/otp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_PRIVATE_KEY" \
  -d '{
    "trxId": "TRX_ID",
    "otp": "123456"
  }'

6. Confirm Customer Payment

Confirm the payment after the OTP or customer authorization step.

POST https://www.awdpay.com/api/v2/checkout/customer/pay

Example

curl -X POST https://www.awdpay.com/api/v2/checkout/customer/pay \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_PRIVATE_KEY" \
  -d '{
    "trxId": "TRX_ID",
    "otp": "123456"
  }'
Only a final success status should be considered as confirmed payment.

7. Verify Payment

Verify a payment by transaction ID or merchant custom identifier.

GET https://www.awdpay.com/api/v2/checkout/verify

Examples

curl -X GET "https://www.awdpay.com/api/v2/checkout/verify?trxId=TRX_ID" \
  -H "Authorization: Bearer YOUR_PRIVATE_KEY"

curl -X GET "https://www.awdpay.com/api/v2/checkout/verify?customIdentifier=ORDER-2026-0001" \
  -H "Authorization: Bearer YOUR_PRIVATE_KEY"

Response example

{
  "success": true,
  "trxId": "TRX_ID",
  "status": "success",
  "amount": 1000,
  "currency": "XOF",
  "customIdentifier": "ORDER-2026-0001",
  "paidBy": "customer@example.com",
  "test": false,
  "updatedAt": "2026-05-09T10:00:00.000Z"
}

8. Find Pending Payment

Find a checkout payment if the merchant needs to recover a pending transaction.

GET https://www.awdpay.com/api/v2/checkout/find

Example

curl -X GET "https://www.awdpay.com/api/v2/checkout/find?trxId=TRX_ID" \
  -H "Authorization: Bearer YOUR_PRIVATE_KEY"

9. Merchant Callback

AWDPay sends an HTTP POST callback to the merchant’s callbackUrl when the payment status changes.

Callback payload example

{
  "event": "payment.success",
  "status": "success",
  "trxId": "TRX_ID",
  "amount": 1000,
  "currency": "XOF",
  "customIdentifier": "ORDER-2026-0001",
  "paidBy": "customer@example.com",
  "timestamp": "2026-05-09T10:00:00.000Z"
}

Callback headers

Content-Type: application/json
X-AWDPAY-Event: payment.success
X-AWDPAY-Timestamp: TIMESTAMP
X-AWDPAY-Signature: sha256=SIGNATURE
Your callback endpoint must return HTTP 200 OK after successful processing.

10. Verify Callback Signature

Use the raw body and your webhook secret to verify X-AWDPAY-Signature.

import crypto from "crypto";

function verifyAwdpaySignature(rawBody, signatureHeader, webhookSecret) {
  const expected =
    "sha256=" +
    crypto.createHmac("sha256", webhookSecret)
      .update(rawBody)
      .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signatureHeader)
  );
}

11. Payment Statuses

StatusDescription
pendingPayment initiated but not completed.
successPayment completed successfully.
failedPayment failed or was cancelled.

12. Best Practices

  1. Do not expose your private key in frontend code.
  2. Create checkout requests from your backend only.
  3. Store trxId and customIdentifier with your order.
  4. Do not mark an order as paid only because the customer reaches successUrl.
  5. Always verify the final status using callback or /api/v2/checkout/verify.
  6. Only success is a final successful payment.
  7. Always verify X-AWDPAY-Signature before confirming an order.

Forfaits prépayés et Formules d’abonnement

AWDPay Checkout API V2 supporte maintenant trois types d’intégration : payment, prepaid et subscription. Cette évolution permet aux marchands de vendre des paiements simples, des forfaits prépayés et des formules d’abonnement avec un seul endpoint.

Endpoint : POST https://www.awdpay.com/checkout/v2/initiate

Types disponibles

Type Description Webhook succès
payment Paiement simple et ponctuel. payment.success
prepaid Forfait payé une fois avec validité, unités ou accès. prepaid.payment.success
subscription Formule d’abonnement liée à un plan. subscription.activated

Exemple — Paiement simple

curl -X POST https://www.awdpay.com/checkout/v2/initiate \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "payment",
    "amount": 5000,
    "currency": "XOF",
    "country": "CI",
    "customIdentifier": "ORDER-2026-0001",
    "paymentName": "Commande Boutique",
    "callbackUrl": "https://merchant.com/api/awdpay/callback",
    "successUrl": "https://merchant.com/payment/success",
    "failedUrl": "https://merchant.com/payment/failed",
    "logo": "https://merchant.com/logo.png"
  }'

Exemple — Forfait prépayé

curl -X POST https://www.awdpay.com/checkout/v2/initiate \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "prepaid",
    "amount": 10000,
    "currency": "XOF",
    "country": "CI",
    "customIdentifier": "PACK-2026-0001",
    "paymentName": "Forfait SMS",
    "customer": {
      "name": "Client Test",
      "email": "client@example.com",
      "phone": "+2250700000000",
      "external_id": "CUSTOMER-001"
    },
    "prepaid": {
      "plan_id": "PACK_SMS_5000",
      "name": "Pack SMS 5000",
      "validity_days": 30,
      "units": 5000,
      "unit_type": "sms"
    },
    "metadata": {
      "order_id": "ORDER-2026-0001",
      "service": "sms_pack"
    },
    "callbackUrl": "https://merchant.com/api/awdpay/callback",
    "successUrl": "https://merchant.com/payment/success",
    "failedUrl": "https://merchant.com/payment/failed",
    "logo": "https://merchant.com/logo.png"
  }'

Exemple — Formule d’abonnement

curl -X POST https://www.awdpay.com/checkout/v2/initiate \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "subscription",
    "amount": 15000,
    "currency": "XOF",
    "country": "CI",
    "customIdentifier": "SUB-ORDER-2026-0001",
    "paymentName": "Premium Mensuel",
    "customer": {
      "name": "Client Abonnement",
      "email": "client@example.com",
      "phone": "+2250500000000",
      "external_id": "CUSTOMER-SUB-001"
    },
    "subscription": {
      "plan_id": "PREMIUM_MONTHLY",
      "name": "Premium Mensuel",
      "interval": "monthly",
      "interval_count": 1,
      "auto_renew": true,
      "renewal_mode": "wallet_auto_debit",
      "grace_period_days": 3
    },
    "metadata": {
      "merchant_user_id": "USER-001",
      "package": "premium"
    },
    "callbackUrl": "https://merchant.com/api/awdpay/callback",
    "successUrl": "https://merchant.com/subscription/success",
    "failedUrl": "https://merchant.com/subscription/failed",
    "logo": "https://merchant.com/logo.png"
  }'

Réponse checkout

{
  "success": true,
  "message": "Generated Checkout Link",
  "trxId": "NOQTFCL3U7V9",
  "type": "subscription",
  "planId": "PREMIUM_MONTHLY",
  "subscriptionId": "SUB-NOQTFCL3U7V9",
  "redirectUrl": "https://www.awdpay.com/checkoutv2?trxId=NOQTFCL3U7V9"
}

Headers webhook

X-AWD-Event: subscription.activated
X-AWD-Timestamp: 1778426580
Content-Type: application/json

Webhook — Forfait prépayé payé

{
  "event": "prepaid.payment.success",
  "status": "success",
  "trxId": "R1Q4SWHHVHV4",
  "type": "prepaid",
  "amount": 10000,
  "currency": "XOF",
  "customIdentifier": "PACK-2026-0001",
  "planId": "PACK_SMS_5000",
  "subscriptionId": null,
  "country": "CI",
  "paymentName": "Forfait SMS",
  "paidBy": "client@example.com",
  "customer": {
    "name": "Client Test",
    "email": "client@example.com",
    "phone": "+2250700000000",
    "external_id": "CUSTOMER-001"
  },
  "prepaid": {
    "plan_id": "PACK_SMS_5000",
    "name": "Pack SMS 5000",
    "validity_days": 30,
    "units": 5000,
    "unit_type": "sms"
  },
  "subscription": null,
  "metadata": {
    "order_id": "ORDER-2026-0001",
    "service": "sms_pack"
  },
  "timestamp": "2026-05-10T15:23:00.000Z"
}

Webhook — Abonnement activé

{
  "event": "subscription.activated",
  "status": "success",
  "trxId": "NOQTFCL3U7V9",
  "type": "subscription",
  "amount": 15000,
  "currency": "XOF",
  "customIdentifier": "SUB-ORDER-2026-0001",
  "planId": "PREMIUM_MONTHLY",
  "subscriptionId": "SUB-NOQTFCL3U7V9",
  "country": "CI",
  "paymentName": "Premium Mensuel",
  "paidBy": "client@example.com",
  "customer": {
    "name": "Client Abonnement",
    "email": "client@example.com",
    "phone": "+2250500000000",
    "external_id": "CUSTOMER-SUB-001"
  },
  "prepaid": null,
  "subscription": {
    "plan_id": "PREMIUM_MONTHLY",
    "name": "Premium Mensuel",
    "interval": "monthly",
    "interval_count": 1,
    "auto_renew": true,
    "renewal_mode": "wallet_auto_debit",
    "grace_period_days": 3
  },
  "metadata": {
    "merchant_user_id": "USER-001",
    "package": "premium"
  },
  "timestamp": "2026-05-10T15:23:00.000Z"
}

Codes d’erreur

{
  "success": false,
  "code": "INVALID_PAYMENT_TYPE",
  "message": "Invalid payment type. Allowed values: payment, prepaid, subscription."
}
{
  "success": false,
  "code": "SUBSCRIPTION_INTERVAL_REQUIRED",
  "message": "subscription.interval is required."
}

Renouvellement automatique des abonnements

Lorsqu’une transaction de type subscription est payée avec succès, AWDPay crée un abonnement actif. Le système peut ensuite renouveler automatiquement l’abonnement selon son intervalle, créer une facture de renouvellement et envoyer un webhook au marchand.

Cycle de vie d’un abonnement

Statut Description Action AWDPay
active L’abonnement est actif et peut être renouvelé automatiquement. AWDPay surveille nextBillingAt.
past_due Le renouvellement a échoué, par exemple solde client insuffisant. AWDPay envoie subscription.payment.failed.
cancelled L’abonnement est désactivé ou annulé. Aucun renouvellement automatique n’est exécuté.

Champs importants

{
  "subscriptionId": "SUB-HC8HBMYWJJZN",
  "subscriptionStatus": "active",
  "currentPeriodStart": "2026-05-10T16:38:02.000Z",
  "currentPeriodEnd": "2026-06-10T16:38:02.000Z",
  "nextBillingAt": "2026-06-10T16:38:02.000Z",
  "lastBillingAt": "2026-05-10T16:46:08.000Z"
}

Webhook — Abonnement renouvelé

{
  "event": "subscription.renewed",
  "status": "success",
  "trxId": "RNWVYQQTISKG138",
  "type": "subscription",
  "amount": 15000,
  "currency": "XOF",
  "customIdentifier": "RENEWAL-SUB-HC8HBMYWJJZN-1778426768",
  "transactionNumber": "subscription-renewal-rnwvyqqtiskg138",
  "planId": "PREMIUM_MONTHLY",
  "subscriptionId": "SUB-HC8HBMYWJJZN",
  "invoiceId": "INV-RNWVYQQTISKG138",
  "billingReason": "renewal",
  "subscriptionStatus": "active",
  "currentPeriodStart": "2026-05-10T16:38:02.000Z",
  "currentPeriodEnd": "2026-06-10T16:38:02.000Z",
  "nextBillingAt": "2026-06-10T16:38:02.000Z",
  "paidBy": "client@example.com",
  "customer": {
    "name": "Client Abonnement",
    "email": "client@example.com",
    "phone": "+2250500000000",
    "external_id": "CUSTOMER-SUB-001"
  },
  "subscription": {
    "plan_id": "PREMIUM_MONTHLY",
    "name": "Premium Mensuel",
    "interval": "monthly",
    "interval_count": 1,
    "auto_renew": true,
    "renewal_mode": "wallet_auto_debit",
    "subscription_status": "active"
  },
  "metadata": {},
  "timestamp": "2026-05-10T16:46:08.000Z"
}

Webhook — Échec de renouvellement

{
  "event": "subscription.payment.failed",
  "status": "failed",
  "trxId": null,
  "type": "subscription",
  "amount": 15000,
  "currency": "XOF",
  "planId": "PREMIUM_MONTHLY",
  "subscriptionId": "SUB-HC8HBMYWJJZN",
  "invoiceId": "INV-FAILED-SUB-HC8HBMYWJJZN-1778426768",
  "billingReason": "renewal",
  "subscriptionStatus": "past_due",
  "currentPeriodStart": "2026-05-10T16:38:02.000Z",
  "currentPeriodEnd": "2026-06-10T16:38:02.000Z",
  "nextBillingAt": "2026-06-10T16:38:02.000Z",
  "paidBy": "client@example.com",
  "customer": {
    "name": "Client Abonnement",
    "email": "client@example.com"
  },
  "subscription": {
    "plan_id": "PREMIUM_MONTHLY",
    "interval": "monthly",
    "auto_renew": true
  },
  "metadata": {},
  "timestamp": "2026-05-10T16:46:08.000Z"
}

Headers webhook

X-AWD-Event: subscription.renewed
X-AWD-Timestamp: 1778426768
Content-Type: application/json
Important : pour un renouvellement automatique, le client doit avoir un solde suffisant dans son wallet AWDPay. Si le solde est insuffisant, l’abonnement passe en past_due et le marchand reçoit subscription.payment.failed.