Skip to main content
This guide walks you through the complete process of converting USD to Bitcoin and sending it to a Spark wallet using just-in-time (JIT) funding.

Prerequisites

Before starting this guide, ensure you have:
  • A Grid API account with valid authentication credentials
  • Access to the Grid API endpoints (production or sandbox)
  • A webhook endpoint configured to receive notifications
  • A Spark wallet address where the Bitcoin will be delivered

Overview

The on-ramp process consists of the following steps:
  1. Create a customer via the API
  2. Create a quote for the USD-to-BTC conversion with current exchange rate
  3. Fund the quote using the provided payment instructions (JIT funding)
  4. Receive webhook notification confirming Bitcoin delivery to the Spark wallet

Step 1: Customer Onboarding

If your platform is a regulated financial institution that already has a KYC/KYB process in place, you can create a customer directly via the API. However, if your platform is not regulated, you must use the hosted KYC/KYB link flow to onboard your customers.
  • Regulated Platforms
  • Unregulated Platforms
Regulated platforms have lighter KYC requirements since they handle compliance verification internally.
The KYC/KYB flow allows you to onboard customers through direct API calls.Regulated financial institutions can:
  • Direct API Onboarding: Create customers directly via API calls with minimal verification
  • Internal KYC/KYB: Handle identity verification through your own compliance systems
  • Reduced Documentation: Only provide essential customer information required by your payment counterparty or service provider.
  • Faster Onboarding: Streamlined process for known, verified customers

Creating Customers via Direct API

For regulated platforms, you can create customers directly through the API without requiring external KYC verification:To register a new customer in the system, use the POST /customers endpoint:
curl -X POST "https://api.lightspark.com/grid/2025-10-13/customers" \
  -H "Authorization: Basic $GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "platformCustomerId": "customer_12345",
    "customerType": "INDIVIDUAL",
    "fullName": "Jane Doe",
    "birthDate": "1992-03-25",
    "nationality": "US",
    "address": {
      "line1": "123 Pine Street",
      "city": "Seattle",
      "state": "WA",
      "postalCode": "98101",
      "country": "US"
    },
    "bankAccountInfo": {
      "accountType": "US_ACCOUNT",
      "accountNumber": "123450000",
      "routingNumber": "000123456",
      "accountCategory": "CHECKING",
      "bankName": "Chase Bank"
    }
  }'
The API allows creating a customer with minimal PII.Here is an example of a customer creation request body bankAccountInfo is always required:
{
  "platformCustomerId": "9f84e0c2a72c4fa",
  "customerType": "INDIVIDUAL",
  "bankAccountInfo": {
      "accountType": "US_ACCOUNT",
      "accountNumber": "123450000",
      "routingNumber": "000123456",
      "accountCategory": "CHECKING",
      "bankName": "Chase Bank"
    }
}
The examples below show a more comprehensive set of data. Not all fields are strictly required by the API for customer creation itself, but become necessary based on currency and UMA provider requirements if using UMA.
  • Individual customer
  • Business Customer
{
  "platformCustomerId": "9f84e0c2a72c4fa",
  "customerType": "INDIVIDUAL",
  "fullName": "John Sender",
  "birthDate": "1985-06-15",
  "address": {
    "line1": "Paseo de la Reforma 222",
    "line2": "Piso 15",
    "city": "Ciudad de México",
    "state": "Ciudad de México",
    "postalCode": "06600",
    "country": "MX"
  },
  "bankAccountInfo": {
    "accountType": "CLABE",
    "clabeNumber": "123456789012345678",
    "bankName": "Banco de México"
  }
}

Step 2: Create a Quote for Fiat-to-Crypto Conversion

Create a quote to convert USD to Bitcoin and deliver it to a Spark wallet. The quote will provide the current exchange rate and payment instructions for funding.

Request

curl -X POST "https://api.lightspark.com/grid/2025-10-13/quotes" \
  -H "Authorization: Basic $GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "source": {
      "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
      "currency": "USD"
    },
    "destination": {
      "externalAccountDetails": {
        "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
        "currency": "BTC",
        "accountInfo": {
          "accountType": "SPARK_WALLET",
          "address": "spark1pgssyuuuhnrrdjswal5c3s3rafw9w3y5dd4cjy3duxlf7hjzkp0rqx6dj6mrhu"
        }
      }
    },
    "lockedCurrencySide": "SENDING",
    "lockedCurrencyAmount": 10000,
    "description": "On-ramp: Buy $100 of Bitcoin"
  }'
Combined External Account Creation: The externalAccountDetails option automatically creates the external account (Spark wallet) and uses it as the destination for the Bitcoin transfer in a single API call. If you want to reuse the same external accounts for many quotes, you can add them using the /external-accounts endpoint, and then use the accountId in the quote creation request.

Response

{
  "id": "Quote:019542f5-b3e7-1d02-0000-000000000006",
  "status": "PENDING",
  "createdAt": "2025-10-03T15:00:00Z",
  "expiresAt": "2025-10-03T15:05:00Z",
  "source": {
    "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
    "currency": "USD"
  },
  "destination": {
    "accountId": "ExternalAccount:b23dcbd6-dced-4ec4-b756-3c3a9ea3d456",
    "currency": "BTC"
  },
  "sendingCurrency": {
    "code": "USD",
    "name": "United States Dollar",
    "symbol": "$",
    "decimals": 2
  },
  "receivingCurrency": {
    "code": "BTC",
    "name": "Bitcoin",
    "symbol": "₿",
    "decimals": 8
  },
  "totalSendingAmount": 10000,
  "totalReceivingAmount": 83333,
  "exchangeRate": 8.3333,
  "feesIncluded": 250,
  "paymentInstructions": [
    {
      "reference": "RAMP-ABC123",
      "instructionsNotes": "Include reference code in transfer memo",
      "bankAccountInfo": {
        "accountType": "US_ACCOUNT",
        "accountNumber": "9876543210",
        "routingNumber": "021000021",
        "accountHolderName": "Lightspark Payments FBO Customer",
        "bankName": "JP Morgan Chase"
      }
    }
  ]
}
The quote shows:
  • Sending: $100.00 USD (including $2.50 fee)
  • Receiving: 0.00083333 BTC (83,333 satoshis)
  • Exchange rate: 8.3333 sats per USD cent (~$120,000 per BTC)
  • Quote expires: In 5 minutes
  • Payment instructions: Bank account details and reference code for funding
For JIT-funded quotes, do NOT call the /quotes/{quoteId}/execute endpoint. Simply fund using the payment instructions, and Grid will automatically execute the conversion upon receiving your payment. The execute endpoint is used for quotes with an internal account or pullable external account as the source.

Step 3: Fund the Quote (Just-in-Time)

In production, you would initiate a real-time push payment (ACH, RTP, wire, etc.) to the bank account provided in paymentInstructions, making sure to include the exact reference code RAMP-ABC123 in the transfer memo.
  • Sandbox (Simulated)
  • Production (Real Funding)
In Sandbox, you can simulate funding using the /sandbox/send endpoint:
curl -X POST "https://api.lightspark.com/grid/2025-10-13/sandbox/send" \
  -H "Authorization: Basic $GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "reference": "RAMP-ABC123",
    "currencyCode": "USD",
    "currencyAmount": 10000
  }'
Response:
{
  "id": "Transaction:019542f5-b3e7-1d02-0000-000000000025",
  "status": "PROCESSING",
  "type": "OUTGOING",
  "quoteId": "Quote:019542f5-b3e7-1d02-0000-000000000006"
}
The reference code is critical for matching your payment to the quote. Always include it exactly as provided in the payment instructions.

Step 4: Receive Completion Webhook

Once Grid receives your payment and completes the USD-to-BTC conversion and delivery, you’ll receive a webhook notification:
{
  "transaction": {
    "id": "Transaction:019542f5-b3e7-1d02-0000-000000000025",
    "status": "COMPLETED",
    "type": "OUTGOING",
    "sentAmount": {
      "amount": 10000,
      "currency": {
        "code": "USD",
        "name": "United States Dollar",
        "symbol": "$",
        "decimals": 2
      }
    },
    "receivedAmount": {
      "amount": 83333,
      "currency": {
        "code": "BTC",
        "name": "Bitcoin",
        "symbol": "₿",
        "decimals": 8
      }
    },
    "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
    "settledAt": "2025-10-03T15:02:30Z",
    "createdAt": "2025-10-03T15:00:00Z",
    "description": "On-ramp: Buy $100 of Bitcoin",
    "exchangeRate": 8.3333,
    "quoteId": "Quote:019542f5-b3e7-1d02-0000-000000000006",
    "paymentInstructions": {
      "reference": "RAMP-ABC123"
    }
  },
  "timestamp": "2025-10-03T15:03:00Z",
  "webhookId": "Webhook:019542f5-b3e7-1d02-0000-000000000030",
  "type": "OUTGOING_PAYMENT"
}
The customer now has 83,333 satoshis (0.00083333 BTC) in their Spark wallet!

Summary

You’ve successfully completed a fiat-to-crypto on-ramp! Here’s what happened:
  1. ✅ Created a customer via API
  2. ✅ Created a quote with exchange rate and payment instructions
  3. ✅ Funded the quote using JIT payment (simulated in sandbox)
  4. ✅ Bitcoin automatically converted and delivered to Spark wallet

Next Steps

I