Sandbox (Test) Keys
Self-provisioned sk_test_ / pk_test_ credentials: rehearse your whole integration - API calls, hosted checkout, confirmations, webhooks - with zero real funds before you go live.
What sandbox keys are#
Sandbox keys are a separate credential type for testing, kept deliberately apart from your live keys:
sk_test_...- your sandbox secret key. Server-side, used exactly like your live API key (theX-Api-Keyheader onpay.u.cash/api.phpand the agents/v1API).pk_test_...- your sandbox publishable key, the twin of the Cloud token: safe for hosted test-checkout URLs, rejected by every server API.
Every record created under a sandbox key is tagged as a test record: no funds move, no fees are metered, nothing appears in live reporting, balances, or payouts. The reverse also holds: your live keys cannot create test artifacts, and sandbox keys are refused on live-only operations (refunds, payouts, balance reads, settings writes) with a clear 403 uxc_sandbox_key_rejected.
Creating keys#
In the console open Account → Sandbox. Name each key (for example "Staging server"), then create a secret and/or publishable key. The raw key is shown exactly once at creation - it is stored hashed and cannot be recovered later. Rotate or revoke any key from the same card; a revoked key stops authenticating immediately.
Keys can also be managed from CI through the agents API: GET /v1/sandbox-keys to list, POST /v1/sandbox-keys {kind:"secret", label:"ci"} to create (raw returned once), POST ?key_id=N&rotate=key to rotate, DELETE ?key_id=N to revoke.
The full rehearsal flow#
- Create a test payment. With your
sk_test_key:POST /v1/resources {amount: 19.99, currency: "USD", test: true}(needs no wallet), orfunction=create-transactionon the merchant API. Everything the key creates is a test record. - Open the hosted test page. The resource's
checkout_urlrenders the real checkout with a TEST MODE banner and a Simulate payment button. - Simulate the payment. Each click (or
POST /v1/simulate-payment {challengeId}) advances the simulated confirmations; at the threshold the payment settles for $0 and your webhook fires withtest: truein the body. - Verify your handler. Check the HMAC signature exactly as for a live delivery (
t=,v1=over the raw body, see Webhooks), then confirm your dedup and fulfillment logic. Test deliveries are tagged in the webhook log and excluded from live views.
By default a simulated payment settles on the first call. Add test_confirmations (0-12, default 1) at resource creation to rehearse multi-confirmation settles step by step: with test_confirmations: 3 the payment stays pending at 1/3 and 2/3 and settles on the third advance - exactly the shape your integration sees while a real transaction waits on-chain confirmations.
Where test data lives#
Test payments live in the test table inside Account → Sandbox (same section as the keys and the mode toggle). The main Payments list, the dashboard totals, analytics, default CSV exports, and earnings all exclude test records, so your live reporting is never polluted; the Sandbox table has its own Export test payments (CSV) button (the file carries a -test name), and an sk_test_ key can export its test rows through download-transactions. The table also has a Simulate payment action on every pending simulated row, so you can drive the flow without opening the hosted page.
Sandbox keys vs. testnet mode#
They answer different questions and compose freely:
- Sandbox keys simulate the payment itself - no chain activity at all, instant, unlimited, perfect for integration tests and CI.
- Testnet mode exercises the real detection stack against Bitcoin testnet / Ethereum Sepolia using testnet coins - closer to production mechanics, and account-wide while enabled.
Use sandbox keys for day-to-day development and webhook verification; use testnet mode when you specifically want to exercise real detection and confirmation behavior.
Rules and limits#
- Sandbox keys are throttled: 10 key creations per hour, 30 simulate calls per minute.
- Live-only operations (refunds, payouts, balance reads, settings writes,
get-cloud-token, cron) always return403for a sandbox key - the split is enforced server-side, not by convention. - A sandbox key never provisions or mutates account-level configuration; it can only create test records.
- When you are ready to go live, nothing to clean up: simply switch your integration to your live API key and Cloud token. Test records stay in the Sandbox view, quarantined from live reporting.