Skip to content

Testing

Run the whole 221 Pay lifecycle in test mode, with no real money, then go through the production checklist.

In test mode, no real money moves. 221 Pay simulates the operator: every payment is confirmed automatically within seconds (except the simulated-outcome numbers, below), every payout succeeds. Webhooks, balances, refunds and payouts work as in live mode.

A sk_221_pay_test_… key selects the simulator and test data. A sk_221_pay_live_… key selects real operators and separate data after live mode is enabled for the project. Both keys use the same base URL.

Recognise test mode

Terminal
curl -s "$API_URL/v1/balances" -H "Authorization: Bearer $API_KEY" | jq '{livemode, gateway_mode}'

livemode: false and simulated: test mode. livemode: true and real: live mode. If live mode is not connected, the call fails with 503 PAYMENTS_UNAVAILABLE. See Authentication.

Full journey

Create a payment

Create a payment as described in Payments. Any valid mobile number in the rail's country works, for example 77 123 45 67 for sn_wave. The simulator answers in place of the customer's phone.

Wait for confirmation

A few seconds later, the payment becomes confirmed, fee and net are set and payment.succeeded goes to the subscribed endpoints.

Terminal
curl "$API_URL/v1/payments/$PAYMENT_ID" -H "Authorization: Bearer $API_KEY"

Refund

Request a quote then refund: see Refunds. The payment must have been created with customer_phone.

Withdraw

With a verified identity, register a number, request a quote then withdraw: see Payouts.

Test the other outcomes

In test mode, a payment is confirmed; fees and treasury are simulated. The customer_phone number imposes another outcome when it ends with:

Number endingOutcome at the first status readerror_code
0002failedprovider_failed
0003expiredexpired

For example 77 123 00 02 on sn_wave. The simulated payment page changes nothing about it, and live mode ignores these numbers.

unknown is tested by sending signed events to the application's endpoint: see the cURL example in Webhooks.

Verify a payout number

In test mode only, the code 000000 validates a payout number or a bank account (POST /v1/payout-destinations/{id}/verify), without reading the account owner's mailbox. An expired code is still refused. Live mode refuses 000000. See Payouts.

Webhooks in test mode

Events are signed and redelivered as in live mode. The URL must be reachable from the Internet; for a local server, use an HTTPS tunnel.

Before production

  • Project live mode activated, sk_221_pay_live_… key created with the payments scope only and stored in the server's secret manager.
  • Detection of current and 221pay_ keys (pattern in Authentication), plus older sk_221_ keys, in the code repository and logs.
  • gateway_mode is real.
  • Every POST carries an Idempotency-Key stable per order, reused on retry.
  • customer_phone sent with every payment.
  • Webhook signature verified on the raw body, deduplication on id.
  • failed, expired and unknown statuses handled, with no automatic second payment.
  • Identity verified and payout number registered.