Testing and Sandbox Scenarios

Simulate approvals, declines, webhooks, refunds, and payouts before going live.

Overview

Watenga's sandbox environment is completely isolated from live payments. Sandbox transactions never move real money and do not appear in live reports. Use the same API host as production with test keys — there is no separate sandbox subdomain.

API base URL: https://api.watenga.africa
Authentication: Authorization: Bearer sk_test_… (or rk_test_… for restricted keys)
Create a sandbox API app at: https://dashboard.watenga.africa/developer → New App → Sandbox

Test Cards

Card NumberBrandScenarioExpiryCVV
4111 1111 1111 1111VisaSuccessful payment12/26123
4000 0000 0000 0002VisaGeneric decline12/26123
4000 0000 0000 9995VisaInsufficient funds12/26123
4000 0000 0000 0069VisaExpired card12/26123
4000 0000 0000 0127VisaIncorrect CVV12/26999
4000 0000 0000 0119VisaGateway timeout (slow)12/26123
5200 0000 0000 0007MastercardSuccessful payment12/26123
5200 0000 0000 0114MastercardGeneric decline12/26123
6011 0000 0000 0004ZimswitchSuccessful payment12/26123
6011 0000 0000 0012ZimswitchDeclined — card blocked12/26123

Use any name, billing address, and expiry in the future. Only the card number determines the test scenario.

Test Mobile Money Numbers

Phone NumberWalletScenarioTiming
0771111111EcoCashImmediate successInstant
0772222222EcoCashDelayed success (simulates slow PIN entry)30 seconds
0773333333EcoCashCustomer cancelled30 seconds
0774444444EcoCashInsufficient balance (fails immediately)Instant
0775555555EcoCashWrong PIN entered 3 times (fails)45 seconds
0776666666EcoCashNetwork timeout (never responds)120 seconds

Use any of these numbers when testing EcoCash payments. The number simulates the customer's behaviour — you don't need a real phone to test.

Triggering Specific Error Codes

VALIDATION_ERROR — send amount: 0 or a negative number.
Expected response: 400 { code: 'INVALID_AMOUNT' }

PHONE_REQUIRED — send walletType: 'ecocash' without customerPhone.
Expected: 400 { code: 'PHONE_REQUIRED' }

DUPLICATE_REQUEST — send two checkout requests with the same merchantTransactionId.
Second request returns: 409 { code: 'DUPLICATE_REQUEST' }

RATE_LIMIT_EXCEEDED — send more than 60 requests in 60 seconds.
Expected: 429 { code: 'RATE_LIMIT_EXCEEDED' } — the Retry-After header shows seconds to wait.

KYC_REQUIRED — use a sandbox app whose merchant account has kyc_tier = 0.
Expected: 403 { code: 'KYC_REQUIRED' }
To bypass in sandbox: contact support to set your sandbox merchant to approved KYC.

Testing Webhooks Locally

Watenga webhooks are sent from our servers to your notificationUrl. In local development, your server is not publicly accessible. Use one of these tools to expose your local server:

Option 1 — ngrok (recommended)

bash
# Install ngrok from ngrok.com
ngrok http 3000

# ngrok gives you a public URL like:
# https://abc123.ngrok.io

# Set your webhook URL in the Developer Dashboard to:
# https://abc123.ngrok.io/webhooks/watenga

Option 2 — Cloudflare Tunnel (free, no account needed)

bash
npx cloudflared tunnel --url http://localhost:3000

# Gives you a permanent-ish URL for the session

Node.js webhook test script:

javascript
// test-webhook.js — simulate a signed webhook event locally
const crypto = require('crypto')

const secret = 'your_webhook_secret_from_dashboard'

// Canonical webhook envelope
const payload = JSON.stringify({
  id: 'evt_test_001',
  object: 'event',
  type: 'payment.capture.completed',
  created: Math.floor(Date.now() / 1000),
  data: {
    id: 'txn_test_001',
    amount: '25.0000',
    net: '24.1300',
    currency: 'USD',
    status: 'completed',
  },
})

// Watenga-Signature: t=<unix>,v1=HMAC_SHA256(secret, `${t}.${rawBody}`)
const t = Math.floor(Date.now() / 1000)
const v1 = crypto
  .createHmac('sha256', secret)
  .update(`${t}.${payload}`, 'utf8')
  .digest('hex')

fetch('http://localhost:3000/webhooks/watenga', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Watenga-Signature': `t=${t},v1=${v1}`,
  },
  body: payload,
}).then(r => r.json()).then(console.log)

// Run: node test-webhook.js

Testing Webhook Retries

Watenga retries failed webhooks up to 5 times with exponential backoff. To test retry behaviour in sandbox:

  1. Set your webhook URL to a URL that returns a non-200 status (e.g. httpstat.us/500)
  2. Trigger a payment.capture.completed event by completing a sandbox payment
  3. Check the Webhook Events log in Developer Dashboard
  4. See the delivery attempts with timestamps and response codes
  5. Update your webhook URL to a working endpoint
  6. Use the "Resend" button in the Webhook Events log to replay the event

Testing Refunds

To test a refund:

  1. Complete a sandbox payment using test card 4111 1111 1111 1111
  2. Note the transaction ID from the response or from GET /v1/transactions
  3. Call POST /v1/transactions/{id}/refund
  4. Verify the transaction status changes to reversed
  5. Check that the merchant balance is reduced by the refunded amount
bash
curl -X POST https://api.watenga.africa/v1/transactions/txn_01HQXYZ/refund \
  -H "Authorization: Bearer sk_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Customer request"}'

Testing Payouts

Sandbox payouts do not actually transfer money. To test a payout:

  1. Ensure your sandbox merchant has an available balance (complete a few test payments first)
  2. Call POST /v1/payouts/request with method: 'bank_transfer'
  3. In sandbox, payouts auto-complete after 5 minutes
  4. Check that available_balance decreased and a payment.payout-item.succeeded webhook fires

Sandbox Reset

Daily reset

Sandbox transaction data resets every 24 hours at midnight UTC. Your sandbox API apps and keys are NOT reset — only transaction/payment data. If you need to reset your sandbox data immediately, contact support.

Going Live Checklist

Before switching from sandbox to live:

  • All test scenarios pass — approvals, declines, refunds, webhooks
  • Webhook signature verification implemented and tested
  • Idempotency keys used on all payment creation requests
  • Error handling covers all error codes in the Errors reference
  • Duplicate payment prevention tested (same merchantTransactionId twice)
  • Mobile money polling implemented with timeout and cancel handling
  • KYC approved in merchant dashboard (check Status in dashboard sidebar)
  • Live API app created in Developer Dashboard (not sandbox)
  • Live keys saved securely (never in code — use environment variables)
  • Webhook URL updated to production URL in live app settings
  • Test with a real small transaction ($1.00) before going fully live

See also: Error codes, Webhooks, API Versioning.

Get notified when InnBucks and OneMoney go live.