Sandbox Testing
The sandbox lets you drive a transaction through its entire lifecycle without real money movement. Two tools make this possible: test data that triggers specific compliance behaviors, and a force-event endpoint that simulates the external callbacks (gateway webhooks, payout-network notifications) that normally advance a transaction.
Forcing Status Transitions
Endpoint: POST /organizations/{tenant}/fx/transactions/{transactionId}/events
Authentication: Agent-level
Availability: Sandbox/staging only β this endpoint does not exist in production.
curl --request POST \
--url https://{FQDN}/organizations/$TENANT/fx/transactions/$TRANSACTION_ID/events \
--header 'Content-Type: application/json' \
--header "x-api-key: $API_KEY" \
--header "x-agent-id: $AGENT_ID" \
--header "x-agent-api-key: $AGENT_KEY" \
--data '{
"event": "payment_authorized",
"message": "Optional description"
}'
Available Events
| Event | Valid from state | What it simulates |
|---|---|---|
payment_authorized | WaitingChallenge3ds | The gateway 3DS callback. Resumes the flow β dispatches payout integration. Use when the transaction is stuck waiting for 3DS. |
ach_settled | WaitingSettlement | The ACH settlement callback. Moves the transaction through PaymentSettled β PaymentCaptured and triggers payout confirmation. |
payment_captured | ReviewApproved | A card capture confirmation. Triggers payout confirmation. |
payout_paid | PayoutAccepted, PayoutReleased, WaitingPayout | The payout network confirming the beneficiary received funds. Moves the transaction to Paid β Completed. |
payout_void | PayoutAccepted, PayoutHold, PayoutReleased, WaitingPayout | The payout network voiding the transaction. Depending on tenant configuration, auto-reverses or parks at PendingReversalApproval. |
hold_released | PayoutHold | The payout network releasing a compliance hold. Resumes the flow. |
cancelled | Any cancellable state | Client-initiated cancellation (voids the payment and cancels the payout). |
refunded | Refundable states | Marks the transaction as refunded. |
If the transaction is not in a valid state for the event, the endpoint returns an error explaining the current state.
Typical Test Flow (Card + 3DS)
- Create the transaction β status
WaitingChallenge3ds,paymentStatus: ActionRequired - Force 3DS:
{ "event": "payment_authorized" } - Transaction auto-progresses β
PayoutAcceptedβManualReviewβReviewApprovedβPaymentCapturedβWaitingPayout - Force delivery:
{ "event": "payout_paid" } - Transaction reaches
Completed
Typical Test Flow (ACH)
- Create the transaction β progresses to
WaitingSettlement - Force settlement:
{ "event": "ach_settled" } - Transaction auto-progresses β
PaymentSettledβPaymentCapturedβWaitingPayout - Force delivery:
{ "event": "payout_paid" } - Transaction reaches
Completed
Compliance Test Scenarios
Certain sender data values trigger specific compliance behaviors in the sandbox:
| Parameter | Value | Result | Compliance Status | Payout Status |
|---|---|---|---|---|
address.zipcode | 99999 | Transaction REJECTED | Rejected | Cancelled |
phoneNumber | +14155550000 | Transaction REJECTED | Rejected | Cancelled |
firstName + lastName | BLOCK LIST MATCH | Transaction REJECTED | Rejected | Cancelled |
firstName + lastName | OFAC MATCH | Transaction held for verification | Pending | Pending (status PayoutHold) |
Payout-Network Hold
Use sender name JULIO SOLANO to trigger a compliance hold at the payout network:
{ "firstName": "JULIO", "lastName": "SOLANO", "...": "..." }
The transaction reaches PayoutHold after payout integration. Release it with the hold_released force event (or it is released by the network/backoffice).
Expected flow:
... β ProcessingPayout β PayoutHold β [hold released] β PayoutReleased β ...
Payout-Network Rejection (Missing Receiver Data)
Use zipcode 96738 on the sender's billing address to trigger receiver-data validation failure at the payout network:
{ "address": { "zipcode": "96738", "...": "..." } }
The rejection depends on missing beneficiary data (country, city, state). If the recipient has complete address data, the transaction is accepted regardless of zipcode.
Payment Decline
Use a card token that the gateway sandbox rejects, or an expired token. The transaction reaches PaymentDeclined β Cancelled.
3DS Decline
When redirected to the 3DS challenge page, choose "Decline" (where the sandbox offers it). The gateway reports the failure and the transaction moves to PaymentDeclined β Cancelled.
Test Cards
Use sandbox test cards to simulate 3DS scenarios. The full list is in Payments Gateway test cards. Common ones:
| Card Number | Scheme | 3DS Behavior |
|---|---|---|
4462030000000000 | VISA | 3DS Challenge |
4035874000424977 | VISA | Frictionless (no challenge) |
5425230000004415 | Mastercard | 3DS Challenge |
4000000000000002 | VISA | Declined |
Tokenize these via the gateway SDK, then pass the token as
paymentMethod.tokenwhen creating a funding account.
Polling for Status
After creating a transaction, poll GET /organizations/{tenant}/fx/transactions/{transactionId} and watch:
| Field | What to expect |
|---|---|
complianceStatus | Pending β Approved (after payout integration) |
payoutStatus | Pending β Processing β Completed |
paymentStatus | ActionRequired β null (after 3DS completes) |
receipt | Regulatory disclosures (available from creation) |
For the full transition audit trail, use GET /fx/transactions/{transactionId}/status β see Transaction. In production, prefer webhooks over polling.
