From 675a3a6c6b79f6921fccf4e6907939fc3866119a Mon Sep 17 00:00:00 2001 From: Peng Ying Date: Mon, 20 Apr 2026 18:14:42 -0700 Subject: [PATCH] docs(ramps): align sandbox-testing page with api-reference source of truth --- .../ramps/platform-tools/sandbox-testing.mdx | 380 ++---------------- 1 file changed, 35 insertions(+), 345 deletions(-) diff --git a/mintlify/ramps/platform-tools/sandbox-testing.mdx b/mintlify/ramps/platform-tools/sandbox-testing.mdx index 16fff472..231850a5 100644 --- a/mintlify/ramps/platform-tools/sandbox-testing.mdx +++ b/mintlify/ramps/platform-tools/sandbox-testing.mdx @@ -1,390 +1,80 @@ --- title: "Sandbox Testing" -description: "Test ramp flows safely without moving real funds" +description: "Use Grid sandbox magic values to trigger specific ramp outcomes" icon: "/images/icons/hammer.svg" "og:image": "/images/og/og-ramps.png" --- -import SandboxBeneficiaryVerification from '/snippets/sandbox-beneficiary-verification.mdx'; import SandboxExternalAccounts from '/snippets/sandbox-external-accounts.mdx'; +import SandboxBeneficiaryVerification from '/snippets/sandbox-beneficiary-verification.mdx'; import SandboxTransferPatterns from '/snippets/sandbox-transfer-patterns.mdx'; +import SandboxQuotePatterns from '/snippets/sandbox-quote-patterns.mdx'; +import SandboxKybVerification from '/snippets/sandbox-kyb-verification.mdx'; -The Grid Sandbox environment provides a complete testing environment for ramp operations, allowing you to validate on-ramp and off-ramp flows without using real money or cryptocurrency. - -## Sandbox overview - -Sandbox mirrors production behavior while using simulated funds: - -- **Same API endpoints**: Use identical API calls as production -- **Simulated funding**: Mock bank transfers and crypto deposits -- **Real webhooks**: Receive actual webhook notifications -- **No real money**: All transactions use test funds -- **Isolated environment**: Sandbox data never affects production - - - Sandbox is perfect for development, testing, and demonstrating ramp - functionality before going live. - - -## Getting started - -### Create sandbox credentials - -1. Log into the Grid dashboard -2. Navigate to **Settings** → **API Keys** -3. Click **Create API Key** and select **Sandbox** environment -4. Save your API key ID and secret securely - - - Sandbox credentials only work with the sandbox environment. They cannot access - production data or move real funds. - - -### Configure sandbox webhook - -Set up a webhook endpoint for sandbox notifications: - -```bash -curl -X PATCH 'https://api.lightspark.com/grid/2025-10-13/config' \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ - -H 'Content-Type: application/json' \ - -d '{ - "webhookEndpoint": "https://api.yourapp.dev/webhooks/grid" - }' -``` - - - Use tools like ngrok to expose local webhook endpoints during development: - `ngrok http 3000` - - -## Testing on-ramps (Fiat → Crypto) - -Simulate the complete on-ramp flow in sandbox: - -### Step 1: Create a test customer - -```bash -curl -X POST 'https://api.lightspark.com/grid/2025-10-13/customers' \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ - -H 'Content-Type: application/json' \ - -d '{ - "platformCustomerId": "test_user_001", - "customerType": "INDIVIDUAL", - "fullName": "Alice Test", - "email": "alice@example.com", - "birthDate": "1990-01-15", - "address": { - "line1": "123 Test Street", - "city": "San Francisco", - "state": "CA", - "postalCode": "94105", - "country": "US" - } - }' -``` - -In sandbox, customers are automatically approved for testing. - -### Step 2: Create an external account for the destination wallet - -```bash -curl -X POST 'https://api.lightspark.com/grid/2025-10-13/customers/external-accounts' \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ - -H 'Content-Type: application/json' \ - -d '{ - "customerId": "Customer:sandbox001", - "currency": "BTC", - "accountInfo": { - "accountType": "SPARK_WALLET", - "address": "spark1pgssyuuuhnrrdjswal5c3s3rafw9w3y5dd4cjy3duxlf7hjzkp0rqx6dj6mrhu" - } - }' -``` +The Grid sandbox environment simulates real on-ramp and off-ramp flows without moving real money or cryptocurrency. You can control test outcomes using special account number patterns and test addresses. -### Step 3: Create an on-ramp quote (just-in-time funding) +Ramp flows (create customer, register external account, create and execute quote) use the same endpoints as production — see [Fiat-to-Crypto and Crypto-to-Fiat](/ramps/conversion-flows/fiat-crypto-conversion). This page describes only the sandbox-specific controls used to drive those flows in tests. -```bash -curl -X POST 'https://api.lightspark.com/grid/2025-10-13/quotes' \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ - -H 'Content-Type: application/json' \ - -d '{ - "source": { - "customerId": "Customer:sandbox001", - "currency": "USD" - }, - "destination": { - "destinationType": "ACCOUNT", - "accountId": "ExternalAccount:b23dcbd6-dced-4ec4-b756-3c3a9ea3d456" - }, - "lockedCurrencySide": "SENDING", - "lockedCurrencyAmount": 10000, - "description": "Test on-ramp conversion" - }' -``` +## KYC/KYB verification -The quote response includes payment instructions with a reference code. - -### Step 4: Simulate funding - -Use the sandbox endpoint to simulate receiving the fiat payment: - -```bash -curl -X POST 'https://api.lightspark.com/grid/2025-10-13/sandbox/send' \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ - -H 'Content-Type: application/json' \ - -d '{ - "reference": "RAMP-ABC123", - "currencyCode": "USD", - "currencyAmount": 10000 - }' -``` - - - The reference code must match the one provided in the quote's payment - instructions. - - -### Step 5: Verify completion - -Within seconds, you'll receive a webhook notification confirming the on-ramp completed: - -```json -{ - "transaction": { - "id": "Transaction:sandbox025", - "status": "COMPLETED", - "type": "OUTGOING", - "sentAmount": { - "amount": 10000, - "currency": { "code": "USD" } - }, - "receivedAmount": { - "amount": 95000, - "currency": { "code": "BTC" } - }, - "settledAt": "2025-10-03T15:02:30Z" - }, - "type": "OUTGOING_PAYMENT" -} -``` + -## Testing off-ramps (Crypto → Fiat) - -Simulate the complete off-ramp flow: - -### Step 1: Fund internal account with crypto - -Simulate a Bitcoin deposit to the customer's internal account using the sandbox funding endpoint: - -```bash -curl -X POST 'https://api.lightspark.com/grid/2025-10-13/sandbox/internal-accounts/InternalAccount:btc001/fund' \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ - -H 'Content-Type: application/json' \ - -d '{ - "amount": 10000000 - }' -``` - -Replace `InternalAccount:btc001` with your actual BTC internal account ID. - - - You'll receive an `ACCOUNT_STATUS` webhook showing the updated balance. - - -### Step 2: Create external bank account - -```bash -curl -X POST 'https://api.lightspark.com/grid/2025-10-13/customers/external-accounts' \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ - -H 'Content-Type: application/json' \ - -d '{ - "customerId": "Customer:sandbox001", - "currency": "USD", - "platformAccountId": "test_bank_001", - "accountInfo": { - "accountType": "US_ACCOUNT", - "accountNumber": "123456001", - "routingNumber": "021000021", - "accountCategory": "CHECKING", - "bankName": "Test Bank", - "beneficiary": { - "beneficiaryType": "INDIVIDUAL", - "fullName": "Alice Test", - "birthDate": "1990-01-15", - "nationality": "US", - "address": { - "line1": "123 Test Street", - "city": "San Francisco", - "state": "CA", - "postalCode": "94105", - "country": "US" - } - } - } - }' -``` - - -In sandbox, you can use special account number patterns to test different scenarios. The **last 3 digits** determine the behavior: **002** (insufficient funds), **003** (account closed), **004** (transfer rejected), **005** (timeout/delayed failure). Any other ending succeeds normally. See "Testing transfer failures" below for details. - - -### Step 3: Create and execute off-ramp quote - -```bash -curl -X POST 'https://api.lightspark.com/grid/2025-10-13/quotes' \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ - -H 'Content-Type: application/json' \ - -d '{ - "source": { - "accountId": "InternalAccount:sandbox_btc001" - }, - "destination": { - "accountId": "ExternalAccount:sandbox_bank001", - "currency": "USD" - }, - "lockedCurrencySide": "SENDING", - "lockedCurrencyAmount": 5000000, - "description": "Test off-ramp conversion" - }' -``` - -Then execute the quote: - -```bash -curl -X POST 'https://api.lightspark.com/grid/2025-10-13/quotes/{quoteId}/execute' \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" -``` - - - In sandbox, off-ramp conversions complete instantly. In production, bank - settlement may take 1-3 business days. - - -## Testing transfer failures - -### External account test patterns +## Adding external accounts - - -## Beneficiary name verification +### Beneficiary name verification -## Test scenarios - -### Successful conversions +## Transfer in (funding internal accounts) -The complete on-ramp and off-ramp flows described in the sections above demonstrate successful conversion scenarios. For quick reference: +In production, internal accounts are funded by sending a bank transfer to the account's payment instructions or by pulling from an external account. In sandbox, you have two options: -**On-ramp test (USD → BTC):** -1. Create customer and quote with payment instructions -2. Use `/sandbox/send` to simulate funding -3. Verify completion via webhook +### Transfer in from an external account -**Off-ramp test (BTC → USD):** -1. Fund BTC internal account with `/sandbox/internal-accounts/{accountId}/fund` -2. Create external bank account (use default account number for success) -3. Create and execute quote -4. Verify completion via webhook +Use the `/transfer-in` endpoint to pull funds from an external account into an internal account. The external account's number suffix determines the outcome: -### Failed conversions + -Test error scenarios systematically using the magic account patterns: +### Sandbox fund endpoint -**1. Test external account insufficient funds (002):** +Instantly add funds to any internal account using `/sandbox/internal-accounts/{accountId}/fund`: ```bash -# Create account with insufficient funds pattern -curl -X POST 'https://api.lightspark.com/grid/2025-10-13/customers/external-accounts' \ +curl -X POST https://api.lightspark.com/grid/2025-10-13/sandbox/internal-accounts/{accountId}/fund \ -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ - -H 'Content-Type: application/json' \ - -d '{ - "customerId": "Customer:sandbox001", - "currency": "USD", - "accountInfo": { - "accountType": "US_ACCOUNT", - "accountNumber": "000000002", - "routingNumber": "021000021", - "accountCategory": "CHECKING", - "beneficiary": { - "beneficiaryType": "INDIVIDUAL", - "fullName": "Test User" - } - } - }' - -# Attempt off-ramp to this account - will fail immediately -curl -X POST 'https://api.lightspark.com/grid/2025-10-13/quotes/{quoteId}/execute' \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" -# Response: 400 Bad Request with insufficient funds error + -H "Content-Type: application/json" \ + -d '{ "amount": 100000 }' ``` -**2. Test account closed (003):** +## Creating quotes (cross-currency conversions) -```bash -# Create account with closed pattern -curl -X POST 'https://api.lightspark.com/grid/2025-10-13/customers/external-accounts' \ - -d '{"accountNumber": "000000003", ...}' + -# Attempt to use - will fail with account closed error -``` +### Executing a quote -**3. Test insufficient balance in internal account:** +After creating a quote, you need to fund it to trigger execution. There are two ways to do this in sandbox: -```bash -# Create quote from empty internal account -curl -X POST 'https://api.lightspark.com/grid/2025-10-13/quotes' \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ - -H 'Content-Type: application/json' \ - -d '{ - "source": { - "accountId": "InternalAccount:empty_btc" - }, - "destination": { - "accountId": "ExternalAccount:bank001", - "currency": "USD" - }, - "lockedCurrencySide": "SENDING", - "lockedCurrencyAmount": 10000000 - }' +**Prefunded internal account** — If your quote's source is an internal account (off-ramp), fund the account using one of the methods described in [transfer in](#transfer-in-funding-internal-accounts), then call the quote execute endpoint: -# Execute will fail with insufficient balance error +```bash +curl -X POST https://api.lightspark.com/grid/2025-10-13/quotes/{quoteId}/execute \ + -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" ``` -**4. Test invalid wallet address:** +**Real-time funding via sandbox send** — If your quote uses real-time funding (on-ramp), the quote response includes payment instructions for you to transfer funds to. Use `/sandbox/send` to simulate this payment: ```bash -# Attempt to create an external account with invalid Spark address -curl -X POST 'https://api.lightspark.com/grid/2025-10-13/customers/external-accounts' \ +curl -X POST https://api.lightspark.com/grid/2025-10-13/sandbox/send \ -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ - -H 'Content-Type: application/json' \ + -H "Content-Type: application/json" \ -d '{ - "currency": "BTC", - "accountInfo": { - "accountType": "SPARK_WALLET", - "address": "invalid_address" - } + "quoteId": "Quote:019542f5-b3e7-1d02-0000-000000000006", + "currencyCode": "USD" }' -# Response: 400 Bad Request with validation error ``` -## 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 -4. Configure production webhook endpoints -5. Test with small amounts first - -## Next steps +## Transferring out funds -- [Webhooks](/ramps/platform-tools/webhooks) - Handle real-time notifications -- [Fiat-to-Crypto Conversion](/ramps/conversion-flows/fiat-crypto-conversion) - Implement production flows -- [Self-Custody Wallets](/ramps/conversion-flows/self-custody-wallets) - Advanced wallet integration -- [Platform Configuration](/ramps/onboarding/platform-configuration) - Configure production settings -- [API Reference](/api-reference) - Complete API documentation +Use the `/transfer-out` endpoint to push funds from an internal account to an external account in the same currency. The external account's number suffix controls the outcome using the same patterns as [transfer in](#transfer-in-from-an-external-account).