Skip to main content

Overview

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

Getting Started with Sandbox

Sandbox Credentials

To use the sandbox environment:
  1. Contact Lightspark to get your inital sandbox credentials configured. Email support@lightspark.com to get started.
  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 Internal Accounts

In production, internal accounts are funded by following the payment instructions (bank transfer, wire, etc.). In sandbox, you can instantly add funds to any internal account using the following endpoint:
POST /sandbox/internal-accounts/{accountId}/fund

{
  "amount": 100000  # $1,000 in cents
}
Example:
curl -X POST https://api.lightspark.com/grid/2025-10-13/sandbox/internal-accounts/InternalAccount:abc123/fund \
  -u "sandbox_token_id:sandbox_token_secret" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 100000
  }'
This endpoint returns the updated InternalAccount object with the new balance. Alternatively, you can also fund internal accounts using the /quotes or /transfer-in endpoints as described below.

Testing Transfer Scenarios

Adding Test External Accounts

The flows for creating external accounts in sandbox are the same as in production. However, when creating external accounts in sandbox, you can use special account number patterns to simulate different transfer behaviors. The last 3 digits of the account number determine the test scenario:
Last DigitsBehaviorUse Case
002Insufficient fundsTransfer-in fails immediately
003Account closed/invalidAll transfers fail immediately
004Transfer rejectedBank rejects the transfer
005Timeout/delayed failureTransaction stays pending ~30s, then fails
Any otherSuccessAll transfers complete normally
Example - Creating a Test Account with Insufficient Funds:
POST /customers/external-accounts

{
  "customerId": "Customer:123",
  "currency": "USD",
  "accountInfo": {
    "accountType": "US_ACCOUNT",
    "accountNumber": "000000002",  // Will trigger insufficient funds
    "routingNumber": "110000000",
    "accountCategory": "CHECKING",
    "beneficiary": {
      "beneficiaryType": "INDIVIDUAL",
      "fullName": "Test User",
      "address": {
        "line1": "123 Test St",
        "city": "San Francisco",
        "state": "CA",
        "postalCode": "94105",
        "country": "US"
      }
    }
  }
}
These patterns apply to the primary identifier for any account type: US account numbers, IBANs, CLABEs, Spark wallet addresses, etc. Just ensure the identifier ends with the appropriate test digits. For scenarios like PIX and UPI, where there’s a domain part involved, append the test digits to the user name part. For example, if testing email addresses as a PIX key, the full identifier would be “testuser.002@pix.com.br” to trigger the insufficient funds scenario.

Testing Transfer-In (Pull from External Account)

When you call /transfer-in with an external account created using test patterns, the transfer will complete instantly in sandbox with the behavior determined by the account number:
POST /transfer-in

{
  "source": {
    "accountId": "ExternalAccount:abc123"  // Uses test pattern from creation
  },
  "destination": {
    "accountId": "InternalAccount:xyz789"
  },
  "amount": 10000  // $100 in cents
}
Expected Behaviors:
  • Success (default): Transaction completes immediately with status COMPLETED
  • Insufficient funds (002): Transaction fails immediately with appropriate error
  • Account closed (003): Transaction fails immediately with account validation error
  • Transfer rejected (004): Transaction fails immediately with rejection error
  • Timeout (009): Transaction shows PENDING status for ~30 seconds, then transitions to FAILED

Testing Transfer-Out (Push to External Account)

Transfer-out works the same way - the destination external account’s test pattern determines the outcome:
POST /transfer-out

{
  "source": {
    "accountId": "InternalAccount:xyz789"
  },
  "destination": {
    "accountId": "ExternalAccount:abc123"  // Uses test pattern
  },
  "amount": 10000
}
The transfer will instantly simulate the bank transfer process and complete with the appropriate status based on the external account’s test pattern.

Testing Cross-Currency Quotes

Creating Quotes with Test Accounts

When creating quotes with the externalAccountDetails destination type, you can provide test account patterns inline:
POST /quotes

{
  "source": {
    "accountId": "InternalAccount:abc123"
  },
  "destination": {
    "externalAccountDetails": {
      "customerId": "Customer:123",
      "currency": "EUR",
      "accountInfo": {
        "accountType": "IBAN_ACCOUNT",
        "iban": "DE89370400440532013003",  // Ends in 003 = account closed
        "beneficiary": {
          "beneficiaryType": "INDIVIDUAL",
          "fullName": "Test User"
        }
      }
    }
  },
  "lockedCurrencySide": "SENDING",
  "lockedCurrencyAmount": 100000
}

Executing Quotes in Sandbox

For quotes from an external account source, execute as in production via /quotes/{quoteId}/execute. The sandbox will:
  1. Instantly process the currency conversion
  2. Apply the test behavior based on any external accounts involved
  3. Update transaction statuses immediately (no waiting for bank processing)
  4. Trigger webhooks for state changes
For quotes with payment instructions (no source account), use the existing /sandbox/send endpoint to simulate payment:
POST /sandbox/send

{
  "reference": "UMA-Q12345-REF",  // From quote payment instructions
  "currencyCode": "USD",
  "currencyAmount": 100000
}

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 (transfers, quote execution, etc.)
  3. Receive webhook events at your endpoint
  4. Verify signature using the sandbox public key
You can also manually trigger a test webhook:
POST /webhooks/test

{
  "url": "https://your-app.com/webhooks"
}

Common Testing Workflows

Complete Payout Flow Test

Here’s a complete test workflow for a USD → EUR payout:
  1. Create customer and internal accounts (via regular API)
  2. Fund customer’s USD internal account:
    POST /sandbox/internal-accounts/InternalAccount:customer-usd/fund
    { "amount": 100000 }  # $1,000
    
  3. Create a test external EUR account:
    POST /customers/external-accounts
    # Use default account number for success case
    
  4. Create and execute a quote:
    POST /quotes
    # USD internal → EUR external
    
    POST /quotes/{quoteId}/execute
    
  5. Verify transaction status and webhooks

Testing Error Scenarios

Test each failure mode systematically:
# 1. Test insufficient funds
# Create external account ending in 002
POST /customers/external-accounts { "accountNumber": "000000002" }

# Attempt transfer-in - should fail immediately
POST /transfer-in

# 2. Test account closed
# Create external account ending in 003
POST /customers/external-accounts { "accountNumber": "000000003" }

# Attempt transfer-out - should fail immediately
POST /transfer-out

# 3. Test timeout scenario
# Create external account ending in 005
POST /customers/external-accounts { "accountNumber": "000000005" }

# Attempt transfer - should pend then fail after ~30s
POST /transfer-in
# Check status immediately - will show PENDING
GET /transactions/{transactionId}
# Wait 30s, check again - will show FAILED

Sandbox Limitations

While sandbox closely mimics production, there are some differences:
  • Instant settlement: All transfers complete immediately (success cases) or fail immediately (error cases), except timeout scenarios (005)
  • No real bank validation: Account numbers aren’t validated against real banking networks
  • Simplified KYC: KYC processes are simulated and complete instantly. You must add customers via the /customers endpoint, rather than using the KYC link flow.
  • Fixed exchange rates: Currency conversion rates may not reflect real-time market rates.
Do not try sending money to any sandbox addresses or accounts. These are not real addresses and will not receive money.

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

I