Skip to main content
The sandbox environment is a full simulator: it accepts the same requests as production and returns the same response shapes. Use it to test your end-to-end integration without moving any real money. This guide describes the deterministic recipes the simulator uses to drive specific outcomes.
Sandbox does not send webhooks to your configured endpoints — for any event type. A webhook endpoint belongs to the account, not to an environment, so sandbox activity is never delivered to it. Drive a sandbox integration by polling GET /v1/payments/{paymentId} and by forcing terminal outcomes with POST /v1/payments/{paymentId}/simulate. See Webhooks in sandbox.

Selecting sandbox

Send a request with a ypk_test_... key. There is no separate URL — the same https://api.yuvexpay.com base URL serves both environments.

Payment behavior matrix

The terminal status is not reached at creation. POST /v1/payments always returns the non-terminal status — NEW, or PENDING_METHOD_SELECTION for a hosted checkout. A status check runs about 5 seconds later and writes the outcome; in the hosted flow, 5 seconds after the payer selects a method. The outcome is picked from the decimal cents of the requested amount: So R$ 49.02 simulates an unpaid PIX, R$ 99.04 simulates an expired PIX, and any value ending in .01 (R$ 1.01, R$ 49.01, R$ 1000.01) simulates a successful payment. These recipes drive PIX only. Sandbox CARD and BOLETO charges are created at the card and boleto acquirer rather than at the PIX simulator, so their cents are ignored — drive those with POST /v1/payments/{paymentId}/simulate.

Forcing a terminal status

POST /v1/payments/{paymentId}/simulate moves a sandbox payment to a terminal status immediately, whatever its amount and payment method. Use it instead of waiting for the check, and to reach outcomes the cents table cannot produce. It requires the payments:write scope and a ypk_test_ key. A production key is rejected with 403 and error code FORBIDDEN. A production payment id is not visible to a sandbox key at all, so it returns 404.
Any other value is rejected with 400. The response is the updated payment, in the same shape as GET /v1/payments/{paymentId}. X-Idempotency-Key is optional here — honoured when you send it, not required.

Withdrawal behavior matrix

Sandbox withdrawals follow the same convention. The status is reached synchronously, so a GET /v1/withdrawals/{withdrawalId} right after creation already shows it:

Refund behavior matrix

The decimal portion is read from the payment amount being refunded, not the refund request itself.

Webhooks in sandbox

Sandbox does not send webhooks to your configured endpoints. This holds for every event type in the event tablePAYMENT_PAID included — and for both payments and withdrawals. Sandbox activity is never delivered to an endpoint you registered.
A webhook endpoint belongs to the account, not to an environment: there is no separate sandbox endpoint and no separate sandbox secret. So a sandbox charge that reaches PAID produces no PAYMENT_PAID delivery, and waiting for one will not succeed. Read the resource instead. Poll GET /v1/payments/{paymentId} or GET /v1/withdrawals/{withdrawalId} and read status. A withdrawal is already terminal on the first read; a payment reaches its terminal status about 5 seconds after creation, or immediately if you call /simulate, which is the fastest way to put a charge into the state your handler is waiting for. To exercise your verifier — signature, timestamp skew, header parsing — use the Send test button on the endpoint in the dashboard. It delivers a real, correctly signed TEST event to your endpoint with X-Webhook-Event: TEST and a body of {"event":"webhook.test","createdAt":"…","data":{"message":"…","livemode":false}}. That is the one delivery a sandbox-only account receives. See the Webhooks guide for the verification algorithm.

Sandbox idempotency keys

Idempotency keys are scoped per environment. The same key value can be reused in sandbox and production without colliding — they’re separate keyspaces. Within sandbox, the same rules apply as in production: a 24-hour TTL and a payload match on retries.

Limits and isolation

  • Sandbox payments and withdrawals never affect your production balance or reports.
  • Receipts are generated for sandbox payments and withdrawals, and the lookup is scoped to the key’s environment: a ypk_test_ key resolves only sandbox ids and a ypk_live_ key only production ids. The other environment returns 404 even for an id on your own account.
  • Statements are built from the real-money ledger, which sandbox transactions never touch. GET /v1/documents/statements with a sandbox key therefore returns an empty statement with zero balances, not your production ledger.
  • Splits stay inside one environment. A sandbox payment can only split to a company that is in sandbox mode, and a production payment only to a production company; the other direction is always rejected, never silently ignored, with 400 SPLIT_RELATIONSHIP_PENDING when the recipient has not accepted in this environment and 400 SPLIT_ENVIRONMENT_MISMATCH when it had. Consent is per environment, so a recipient that accepted in production still has to accept in sandbox. A sandbox split never touches a production balance, statement or report.
  • Webhooks are not delivered — see Webhooks in sandbox.
  • Sandbox keys cannot access production data, and vice versa.

Going live

When your integration is stable:
  1. Create a ypk_live_ key in the dashboard (requires completed KYB).
  2. Configure your webhook endpoint and store its secret. This is the point at which webhooks start being delivered at all — verify the endpoint with the dashboard’s Send test button before opening real traffic.
  3. Swap the API key in your environment variables.
  4. Run a small live transaction end-to-end before opening real traffic.