Skip to main content

Overview

The Grid sandbox environment allows you to test your rewards integration without moving real money or cryptocurrency. All API endpoints work the same way in sandbox as they do in production, but transactions are simulated and you can control test scenarios using special test values.

Getting Started with Sandbox

Sandbox Credentials

To use the sandbox environment:
  1. Go to app.lightspark.com, create an account, and generate your sandbox API keys from the dashboard.
  2. Add your sandbox API token and secret to your environment variables.
  3. Use the normal production base URL: https://api.lightspark.com/grid/2025-10-13
  4. Authenticate using your sandbox token with HTTP Basic Auth

Simulating Money Movements

Funding Platform Internal Accounts

In production, your platform’s internal account is funded by following the payment instructions (bank transfer, wire, etc.). In sandbox, you can instantly add funds to your platform’s internal account using the following endpoint:
Example:
This endpoint returns the updated InternalAccount object with the new balance. You’ll also receive an INTERNAL_ACCOUNT.BALANCE_UPDATED webhook showing the balance change.
In production, ACH transfers typically take 1-3 business days to settle. In sandbox, funding is instant.

Testing Reward Distributions

Testing Successful Bitcoin Rewards

The standard reward flow works seamlessly in sandbox. First create the destination external account, then create and execute a quote to instantly convert USD to BTC:
In sandbox:
  • The USD is instantly debited from your platform’s internal account
  • Bitcoin is “purchased” at a simulated exchange rate
  • The Bitcoin is delivered to the Spark wallet address. In sandbox, BTC funds are regtest funds so that they’re compatible with real regtest spark wallets.
  • You receive an OUTGOING_PAYMENT webhook notification
In sandbox, Bitcoin transfers complete instantly on regtest. In production, Spark wallet transfers typically complete within seconds.

Testing Wallet Address Failures

Use special Spark wallet address patterns to test different failure scenarios. The last 3 digits of the wallet address determine the test behavior: Example - Testing Wallet Unavailable:
The quote execution will fail immediately with a wallet unavailable error. Note that these failure test patterns work for any external account type. If you want to test other cases of funding from a broken fiat account, you can create an external account with the appropriate test pattern and use that for the quote source for funding. There are also two other failure test patterns relevant for bank accounts:
  • 002: Insufficient funds (transfer-in will fail)
  • 004: Transfer rejected (bank rejects the transfer)

Testing Customer Onboarding

Sandbox KYB Flow

In sandbox, the KYB onboarding process is simplified to always use the /customers endpoint instead of the KYB link flow.
In sandbox, customers are automatically approved. In production, KYB verification may take several minutes.

Testing Insufficient Balance

To test insufficient balance scenarios, simply attempt to send more than your platform’s internal account balance:
The quote execution will fail with an insufficient balance error.

Testing Webhooks

All webhook events fire normally in sandbox. To test your webhook endpoint:
  1. Configure your webhook URL in the dashboard
  2. Perform actions that trigger webhooks (funding accounts, executing quotes, etc.)
  3. Receive webhook events at your endpoint
  4. Verify signature using the sandbox public key
You can also manually trigger a test webhook:

Common Testing Workflows

Complete Reward Distribution Test

Here’s a complete test workflow for distributing a $1.00 Bitcoin reward:
  1. Fund your platform’s internal account:
  2. Create a test customer:
  3. Execute a reward quote:
  4. Verify completion via webhook (OUTGOING_PAYMENT event)
  5. Check transaction history:

Testing Error Scenarios

Test each failure mode systematically. First create external accounts with test address patterns, then use them in quotes:

Global Account magic values

The Grid sandbox accepts a small set of magic values for Global Account flows, so you can exercise the full request shape without standing up Turnkey, WebAuthn, or an OIDC provider. OTP, passkey, and wallet signatures use fixed sandbox-only values. OAuth uses JWT-shaped sandbox OIDC tokens: sandbox skips real IdP signature verification, but still validates the token claims, freshness, credential identity, and verify-time nonce binding. A wrong magic value or sandbox OIDC authentication failure returns 401 UNAUTHORIZED with a reason field that names the specific check that failed. A malformed OIDC JWT can return 400 INVALID_INPUT before authentication starts.

Email OTP code

Pass 000000 as the body otp on POST /auth/credentials/{id}/verify when the credential type is EMAIL_OTP. The sandbox skips OTP delivery and accepts this value as a valid response to the issued challenge.
Any other code returns 401 UNAUTHORIZED with reason: "Invalid OTP code".

Passkey assertion signature

Pass sandbox-valid-passkey-signature as assertion.signature on POST /auth/credentials/{id}/verify when the credential type is PASSKEY. The sandbox accepts the rest of the assertion as-is and skips the WebAuthn signature check. Passkey reauthentication is a two-step /challenge/verify flow. The clientPublicKey is sent on /challenge (so Grid can seal the session signing key to your device) — the magic value bypasses the credential check, not the HPKE plumbing, so the public key is still required.
Any other signature returns 401 UNAUTHORIZED with reason: "Invalid passkey signature".

OAuth (OIDC) token

OAuth does not use a fixed magic token in sandbox. Pass a JWT-shaped OIDC token as oidcToken. The JWT signature segment can be a dummy value, but the payload must look like a real ID token. For POST /auth/credentials with type: "OAUTH", the sandbox token must include:
  • iss: a supported issuer, such as https://accounts.google.com, accounts.google.com, or https://appleid.apple.com
  • aud: a non-empty string, or a single-element string array
  • sub: a non-empty subject identifier for the user
  • iat: a numeric issued-at timestamp no more than 60 seconds before the request, with 5 seconds of clock skew allowed
  • exp: a numeric expiration timestamp later than the request time
Grid stores the OAuth credential’s registered identity from iss, aud, and sub. On POST /auth/credentials/{id}/verify, the fresh oidcToken must carry the same iss, aud, and sub as the credential being verified. It must also include nonce equal to sha256(clientPublicKey), where clientPublicKey is the exact hex public key sent in the verify request.
The old literal sandbox-valid-oidc-token is no longer accepted. Use a freshly generated sandbox JWT for both OAuth credential registration and OAuth verification. Production requires a real ID token from your provider and verifies the provider signature.

Wallet signature header

Pass sandbox-valid-signature as the Grid-Wallet-Signature HTTP header on any signed-retry flow:
  • POST /auth/credentials (add-additional-credential signed retry)
  • DELETE /auth/credentials/{id} (revoke credential)
  • DELETE /auth/sessions/{id} (revoke session)
  • POST /internal-accounts/{id}/export (export wallet)
  • PATCH /internal-accounts/{id} (update wallet privacy)
  • POST /quotes/{quoteId}/execute (when source is an embedded wallet)
Any other header value returns 401 UNAUTHORIZED with reason: "Invalid Grid-Wallet-Signature".

Sandbox Limitations

While sandbox closely mimics production, there are some differences:
  • Instant settlement: All Bitcoin transfers complete instantly (success cases) or fail immediately (error cases), except timeout scenarios (005)
  • Uses Regtest funds: Spark bitcoin funds are regtest funds so that they’re compatible with real regtest spark wallets.
  • Simplified KYB: KYB processes are simulated and complete instantly with automatic approval
  • Fixed exchange rates: Currency conversion rates may not reflect real-time market rates
Do not try sending money to any sandbox wallet addresses or bank accounts. These are not real addresses and will not receive funds.

Moving to Production

When you’re ready to move to production:
  1. Generate production API tokens in the dashboard
  2. Swap those credentials for the sandbox credentials in your environment variables
  3. Remove any sandbox-specific test patterns from your code (magic number wallet addresses)
  4. Configure production webhook endpoints
  5. Test with small reward amounts first (0.010.01-1.00)
  6. Gradually increase volume as you gain confidence

Next Steps