Testing
Sandbox is a first-class environment per merchant: same API, same Cashier, same webhooks, same state machines, with test_gateway acting as the Provider. Point an sk_test_ key at it — the prefix selects sandbox.
Magic amounts
The cent fraction of the amount steers the outcome:
| Amount ends in | Behaviour | What it proves |
|---|---|---|
| .01 | createPayment declines → failed | Your payment.failed handling |
| .02 | Stays pending, then succeeds via async webhook | Webhook-driven crediting (not redirect) |
| .03 | Expires without completion → expired | Your expiry handling / no stuck rows |
| .04 | Confirmation webhook delivered twice (stable event id) | Your dedupe on the evt_ id |
| .05 | Succeeds; a later refund of it fails | Refunds are Phase 1-deferred (informational) |
| .06 | Underpayment — a smaller received_amount | Your under/over-paid crypto handling |
| 999.99 | Seeded Risk Rule → under_review | The Payment sits until an operator approves |
| any other | Succeeds promptly | The happy path end-to-end |
Run at minimum: a happy path (any amount), .02 (async webhook crediting), .04 (dedupe), .01 (failure), and 999.99 (review) — and confirm each drives the correct record change on your side.
- The
999.99review trigger is a seeded Risk Rule, not gateway logic — review is a Risk engine decision by design. The Payment sits inunder_reviewuntil an operator approves or rejects it in the Portal review queue. - For crypto methods,
test_gatewayissues a fake deposit address and simulates the confirmation webhook after ~10 seconds. - Sandbox outbound webhooks are real deliveries with real signatures against the endpoint's test-mode secret.
Fire a webhook on demand
In sandbox you can force a signed inbound webhook at a Payment (PayXiro-side artisan command):
artisan
php artisan payxiro:test-gateway:fire-webhook pay_... --type=payment.succeededBefore you go live
- Sandbox cases above pass: happy path, async webhook, dedupe, failure, review.
- Signature verification rejects a tampered body and a stale timestamp.
- Crediting is idempotent on
payment.id: a replayed webhook and a status-poll cannot double-credit. - The webhook route is excluded from CSRF and responds 2xx well within the delivery timeout.
- Live
sk_live_key andwhsec_secret are set in your secret store (never committed). success_url/cancel_urlare within the Platform's allowed redirect patterns; embed origins (if used) are on the allow-list.