Test Your Integration

Reevit’s sandbox includes a payment simulator: a built-in provider that produces any payment outcome on demand. Nothing about it is mocked — simulated payments run through the real router, the real failover logic, and the real webhook pipeline, so the events your app receives in test mode match production schemas by construction. There are two ways to drive it:
  1. Magic test values — create payment intents with special amounts (or phone-number suffixes) that force a specific outcome.
  2. The Reevit CLIreevit trigger fires outcomes by name, and reevit listen streams the resulting events to your local endpoint with production-valid signatures.
The simulator only works with test-mode keys (pfk_test_...). Live-mode requests to the simulator provider are rejected.

Magic test values

Create a payment intent with one of these amounts and the simulator produces the corresponding outcome. Failure outcomes can also be forced with a customer phone number ending in the listed suffix, whatever the amount.
AmountPhone suffixOutcomeFailover
4000Succeeds immediately
4001...0001Declined (card_declined)No — hard declines never fail over
4002...0002Declined (insufficient_funds)No
4003...0003Timeout (transient error)Yes — the router retries on your next connection
4004...0004Provider down (unavailable)Yes
Any other amount behaves like a normal sandbox payment (pending, then resolved by the provider’s test flow).
# Force a decline
curl -X POST https://api.reevit.io/v1/payments/intents \
  -H "X-Reevit-Key: pfk_test_your_key.secret" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 4001,
    "currency": "GHS",
    "method": "mobile_money",
    "country": "GH"
  }'
The failover column is the interesting part: 4003 and 4004 are how you test routing failover. With two or more connections, a timeout on the first provider makes the router retry on the next one — watch the payment’s route field to see every attempt. Hard declines (4001, 4002) intentionally never fail over: the customer’s bank said no, and retrying elsewhere would double-charge risk for the same answer.

The Reevit CLI

The CLI wraps the simulator in a stripe listen-style local workflow.
# Homebrew (macOS / Linux)
brew install reevit-platform/tap/reevit

# npm
npm install -g @reevit/cli
Authenticate with a test-mode API key scoped to what the CLI needs (payments:read, payments:write, connections:read, connections:write, and optionally webhooks:read):
reevit login   # prompts for the key, stores it with owner-only permissions

Trigger outcomes by name

reevit trigger creates a real test-mode payment using the magic amount for the outcome you name — the simulator connection is created automatically the first time.
reevit trigger payment.succeeded
reevit trigger payment.failed
reevit trigger payment.insufficient_funds
reevit trigger payment.timeout
reevit trigger payment.provider_downtime

Forward events to localhost

reevit listen subscribes to your account’s live test-mode event stream and POSTs each event to your local endpoint — signed exactly like production webhooks, so your signature-verification code runs unchanged:
reevit listen --forward-to http://localhost:3000/webhooks
Each delivery carries the production header set (X-Reevit-Signature, X-Reevit-Delivery-ID, X-Reevit-Delivery-Attempt, X-Reevit-Signature-Timestamp) with a real sha256=<hex HMAC-SHA256 of the raw body> signature. When your key has webhooks:read, events are signed with your account’s actual webhook secret; otherwise the CLI generates and prints an ephemeral secret to verify against. See Webhooks for verification snippets in every SDK.

The full loop

Two terminals and you can watch an outcome travel end to end:
# Terminal 1 — stream events into your local app
reevit listen --forward-to http://localhost:3000/webhooks

# Terminal 2 — cause the outcome
reevit trigger payment.failed
Your endpoint receives the same payment.* events production would send, your verification passes, and your failure handling runs against a real declined payment.

What to test before going live

  • Success and both declines — does your app message the customer correctly for card_declined vs insufficient_funds?
  • Timeout with one connection — the payment fails after retries; your app should treat it as retryable.
  • Timeout with two connections — the payment recovers via failover; check you handle a succeeded payment whose route shows multiple attempts.
  • Webhook signature rejection — send a request with a bad signature to your endpoint and confirm you reject it.
  • Idempotency — replay a delivery (same X-Reevit-Delivery-ID) and confirm you don’t double-process.
When everything passes, follow the path to production.