Docs Open Console

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 (the X-Api-Key header on pay.u.cash/api.php and the agents /v1 API).
  • 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 (Test) Keys. 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#

  1. Create a test payment. With your sk_test_ key: POST /v1/resources {amount: 19.99, currency: "USD", test: true} (needs no wallet), or function=create-transaction on the merchant API. Everything the key creates is a test record.
  2. Open the hosted test page. The resource's checkout_url renders the real checkout with a TEST MODE banner and a Simulate payment button.
  3. 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 with test: true in the body.
  4. 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 their own console view: Sales → Sandbox. The main Payments list, the dashboard totals, analytics, CSV exports, and earnings all exclude test records, so your live reporting is never polluted. The Sandbox view also has a Simulate payment action on every pending 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 return 403 for 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.