--- title: "Quickstart" description: "Complete walkthrough for buying Bitcoin and sending it as a reward to an external Spark wallet for self-custody" icon: "/images/icons/rocket.svg" "og:image": "/images/og/og-rewards.png" --- Rewards quickstart hero Rewards quickstart hero This guide walks you through the complete process of buying Bitcoin with USD and sending it to a self-custody Spark wallet, from customer onboarding through quote execution. ## Understanding Entity Mapping for Rewards In this guide, the entities map as follows (platform-funded model): | Entity Type | Who They Are | In This Example | |------------|--------------|----------------| | **Platform** | Your rewards app paying rewards directly | Your cashback/rewards platform | | **Customer** | (Not used in this model) | N/A | | **External Account** | Users' crypto wallets receiving rewards | User's self-custody Spark wallet | **Flow**: Your platform funds its internal account → sends Bitcoin micro-payouts directly → to users' external crypto wallets at scale. This is common for cashback apps where you earn affiliate commissions and share them with users. For white-label reward programs where brands like Nike or Starbucks fund their own reward campaigns, those brands would be created as **Customers** who manage their own reward budgets. ## 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 sent ## Overview The process consists of the following steps: 1. **List platform internal accounts** to find your platform's USD funding instructions 2. **Fund your internal account** via ACH push and receive a webhook notification 3. **Generate a spark wallet** for your customer, or let them connect their own 4. **Register the destination wallet** as an external account 5. **Execute a quote** to complete the Bitcoin purchase and transfer a reward to the user's own Spark wallet. ## Step 1: List your platform's internal accounts When your platform is first created, it is automatically assigned an internal account with a balance in your configured fiat currency. List your platform's internal accounts to see the available balances and funding instructions for USD. ### Request ```bash curl -X GET "https://api.lightspark.com/grid/2025-10-13/platform/internal-accounts?currency=USD" \ -H "Authorization: Basic $GRID_CLIENT_ID:$GRID_CLIENT_SECRET" ``` ### Response ```json { "data": [ { "id": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965", "balance": { "amount": 0, "currency": { "code": "USD", "name": "United States Dollar", "symbol": "$", "decimals": 2 } }, "totalBalance": { "amount": 0, "currency": { "code": "USD", "name": "United States Dollar", "symbol": "$", "decimals": 2 } }, "fundingPaymentInstructions": [ { "instructionsNotes": "Include the reference code in your ACH transfer memo", "accountOrWalletInfo": { "accountType": "US_ACCOUNT", "reference": "FUND-BTC123", "accountNumber": "9876543210", "routingNumber": "021000021", "accountHolderName": "Lightspark Payments FBO John Doe", "bankName": "JP Morgan Chase" } }, { "accountOrWalletInfo": { "accountType": "SPARK_WALLET", "assetType": "USDB", "address": "spark1pgssyuuuhnrrdjswal5c3s3rafw9w3y5dd4cjy3duxlf7hjzkp0rqx6dj6mrhu", "invoice": "lnbc15u1p3xnhl2pp5jptserfk3zk4qy42tlucycrfwxhydvlemu9pqr93tuzlv9cc7g3sdqsvfhkcap3xyhx7un8cqzpgxqzjcsp5f8c52y2stc300gl6s4xswtjpc37hrnnr3c9wvtgjfuvqmpm35evq9qyyssqy4lgd8tj637qcjp05rdpxxykjenthxftej7a2zzmwrmrl70fyj9hvj0rewhzj7jfyuwkwcg9g2jpwtk3wkjtwnkdks84hsnu8xps5vsq4gj5hs" } }, { "accountOrWalletInfo": { "accountType": "SOLANA_WALLET", "assetType": "USDC", "address": "4Nd1m6Qkq7RfKuE5vQ9qP9Tn6H94Ueqb4xXHzsAbd8Wg" } } ], "createdAt": "2025-10-03T12:00:00Z", "updatedAt": "2025-10-03T12:00:00Z" } ] } ``` The `fundingPaymentInstructions` provide the bank account details and reference code needed to fund this internal account via ACH pull from the customer's bank. You can also see that there are Spark wallet funding instructions in this example response which can be used to fund the internal account with USDB instantly. ## Step 2: Fund your Internal Account You can initiate an ACH transfer from your bank to the account details provided in the funding instructions, making sure to include the reference code `FUND-BTC123` in the transfer memo. In sandbox mode, you can use the `/sandbox/internal-accounts/{accountId}/fund` endpoint to simulate receiving funds. In production, actual ACH transfers typically take 1-3 business days to settle. ### Webhook Notification When the funds are received and the internal account balance is updated, you'll receive a webhook notification: ```json { "id": "Webhook:019542f5-b3e7-1d02-0000-000000000020", "type": "INTERNAL_ACCOUNT.BALANCE_UPDATED", "timestamp": "2025-10-03T14:32:00Z", "data": { "id": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965", "type": "INTERNAL_FIAT", "status": "ACTIVE", "balance": { "amount": 200000, "currency": { "code": "USD", "name": "United States Dollar", "symbol": "$", "decimals": 2 } }, "totalBalance": { "amount": 200000, "currency": { "code": "USD", "name": "United States Dollar", "symbol": "$", "decimals": 2 } }, "fundingPaymentInstructions": [], "createdAt": "2025-10-03T12:00:00Z", "updatedAt": "2025-10-03T14:32:00Z" } } ``` The internal account now has a balance of $2,000.00 (200000 cents). You can use this balance to instantly distribute Bitcoin rewards to your customers. ## Step 3: Customer Onboarding This guide assumes you have a Spark wallet address for your customer who will receive the Bitcoin reward. For rewards, the only entity who needs to be KYB'd is the entity paying for the reward - in this case, you, the platform! All you need in order to pay out a reward is the wallet address. No need to go through the full hosted KYC flow for this use case! To generate a spark wallet, you can use a tool like [Privy](https://privy.io) or the Spark SDK directly. ## Step 4: Register the Destination Spark Wallet Register the customer's Spark wallet as an external account. ### Request ```bash curl -X POST "https://api.lightspark.com/grid/2025-10-13/customers/external-accounts" \ -H "Authorization: Basic $GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001", "currency": "BTC", "accountInfo": { "accountType": "SPARK_WALLET", "address": "spark1pgssyuuuhnrrdjswal5c3s3rafw9w3y5dd4cjy3duxlf7hjzkp0rqx6dj6mrhu" } }' ``` ### Response ```json { "id": "ExternalAccount:b23dcbd6-dced-4ec4-b756-3c3a9ea3d456", "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001", "status": "ACTIVE", "currency": "BTC", "accountInfo": { "accountType": "SPARK_WALLET", "address": "spark1pgssyuuuhnrrdjswal5c3s3rafw9w3y5dd4cjy3duxlf7hjzkp0rqx6dj6mrhu" } } ``` ## Step 5: Create and Execute a Quote to the Customer's Spark Wallet Create and execute a trade from USD to BTC using the external account as the destination. ### Request ```bash 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": { "sourceType": "ACCOUNT", "accountId": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965" }, "destination": { "destinationType": "ACCOUNT", "accountId": "ExternalAccount:b23dcbd6-dced-4ec4-b756-3c3a9ea3d456" }, "lockedCurrencySide": "SENDING", "lockedCurrencyAmount": 100, "immediatelyExecute": true, "description": "Bitcoin reward payout!" }' ``` **Immediate Quote Execution (Market Order)**: Note that `immediatelyExecute` is set to `true` in this example. Because we always just want to send $1.00 worth of BTC to users as a reward at the current market rate, we don't need to lock a quote and view the rate details before executing. If you want to lock a quote and confirm fees and exchange rate details before executing the quote, set `immediatelyExecute` to `false` or omit the field. ### Response ```json { "id": "Quote:019542f5-b3e7-1d02-0000-000000000020", "status": "PROCESSING", "createdAt": "2025-10-03T15:00:00Z", "expiresAt": "2025-10-03T15:05:00Z", "source": { "sourceType": "ACCOUNT", "accountId": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965" }, "destination": { "destinationType": "ACCOUNT", "accountId": "ExternalAccount:b23dcbd6-dced-4ec4-b756-3c3a9ea3d456" }, "sendingCurrency": { "code": "USD", "name": "United States Dollar", "symbol": "$", "decimals": 2 }, "receivingCurrency": { "code": "BTC", "name": "Bitcoin", "symbol": "₿", "decimals": 8 }, "totalSendingAmount": 100, "totalReceivingAmount": 810, "exchangeRate": 8.1, "feesIncluded": 5, "transactionId": "Transaction:019542f5-b3e7-1d02-0000-000000000025" } ``` The quote shows: - **Sending**: \$1.00 USD (including $0.05 fee) - **Receiving**: 0.0000081 BTC (810 satoshis) - **Exchange rate**: 8.1 sats per USD cent (~$123,000 per BTC) The quote status changes to `PROCESSING` and the Bitcoin transfer is initiated. USD is debited from the internal account, Bitcoin is purchased, and then sent to the Spark wallet address. ### Completion Webhook When the Bitcoin transfer completes, you'll receive a webhook notification: ```json { "id": "Webhook:019542f5-b3e7-1d02-0000-000000000030", "type": "OUTGOING_PAYMENT.COMPLETED", "timestamp": "2025-10-03T15:02:00Z", "data": { "id": "Transaction:019542f5-b3e7-1d02-0000-000000000025", "status": "COMPLETED", "type": "OUTGOING", "sentAmount": { "amount": 100, "currency": { "code": "USD", "name": "United States Dollar", "symbol": "$", "decimals": 2 } }, "receivedAmount": { "amount": 810, "currency": { "code": "BTC", "name": "Bitcoin", "symbol": "₿", "decimals": 8 } }, "settledAt": "2025-10-03T15:01:45Z", "createdAt": "2025-10-03T15:00:00Z", "description": "Bitcoin purchase for self-custody", "exchangeRate": 8.1, "quoteId": "Quote:019542f5-b3e7-1d02-0000-000000000020" } } ``` Bitcoin transfers to Spark wallets typically complete within seconds, much faster than traditional Bitcoin on-chain transactions. ## Summary You've successfully completed a Bitcoin purchase and transfer to a self-custody Spark wallet! Here's what happened: 1. ✅ Listed internal accounts and obtained USD funding instructions 2. ✅ Funded the internal account with USD via ACH 3. ✅ Generated a Spark wallet for the customer 4. ✅ Registered the destination Spark wallet as an external account 5. ✅ Created and executed a quote to purchase Bitcoin and send to the Spark wallet The customer now has 810 Satoshis in their self-custody Spark wallet! ## Next Steps - **Transaction history**: Use `GET /transactions` to track all Bitcoin purchases - **Price monitoring**: Build price alerts using the lookup endpoint to monitor rates - **Webhook verification**: Implement signature verification for webhook security (see [Webhooks guide](/rewards/platform-tools/webhooks)) ## Related Resources - [API Reference](/api-reference) - Complete API documentation - [Platform Configuration](/rewards/developer-guides/platform-configuration) - Configure your platform settings - [Webhooks](/rewards/platform-tools/webhooks) - Webhook security and verification