Skip to main content
This guide covers how to distribute Bitcoin rewards to your customers, including quote creation, execution options, and tracking delivery.

Overview

Distributing Bitcoin rewards involves creating a quote that converts your fiat balance (typically USD) to Bitcoin and sends it to the customer’s wallet. You have flexibility in how you lock amounts, register destinations, and execute transfers.

Basic Flow

  1. Create a quote - Specify source account, destination, and amount
  2. Execute the quote - Either immediately or after review
  3. Monitor completion - Track via webhooks or polling

Finding your platform’s internal account

In this guide, we’ll use the platform’s USD internal account as the funding source for the rewards. You can find your platform’s internal account by listing all internal accounts for your platform.
curl -X GET "https://api.lightspark.com/grid/2025-10-13/platform/internal-accounts" \
  -H "Authorization: Basic $GRID_CLIENT_ID:$GRID_CLIENT_SECRET"
Response:
{
  "data": [
    {
      "id": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965",
      "balance": {
        "amount": 10000,
        "currency": {
          "code": "USD",
          "name": "United States Dollar",
          "symbol": "$",
          "decimals": 2
        }
      },
      "fundingPaymentInstructions": [...],
      "createdAt": "2025-10-03T12:00:00Z",
      "updatedAt": "2025-10-03T12:00:00Z"
    }
  ]
}

Creating a Quote

The core request specifies your platform’s internal account as the source and the customer’s wallet as the destination.
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": {
      "accountId": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965"
    },
    "destination": {
      "externalAccountDetails": {
        "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
        "currency": "BTC",
        "accountInfo": {
          "accountType": "SPARK_WALLET",
          "address": "spark1pgssyuuuhnrrdjswal5c3s3rafw9w3y5dd4cjy3duxlf7hjzkp0rqx6dj6mrhu"
        }
      }
    },
    "lockedCurrencySide": "SENDING",
    "lockedCurrencyAmount": 100,
    "immediatelyExecute": true,
    "description": "Weekly reward payout"
  }'
Response:
{
  "quoteId": "Quote:019542f5-b3e7-1d02-0000-000000000020",
  "status": "PROCESSING",
  "createdAt": "2025-10-03T15:00:00Z",
  "expiresAt": "2025-10-03T15:05:00Z",
  "source": {
    "accountId": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965",
    "currency": "USD"
  },
  "destination": {
    "accountId": "ExternalAccount:b23dcbd6-dced-4ec4-b756-3c3a9ea3d456",
    "currency": "BTC"
  },
  "sendingCurrency": {
    "code": "USD",
    "decimals": 2
  },
  "receivingCurrency": {
    "code": "BTC",
    "decimals": 8
  },
  "totalSendingAmount": 100,
  "totalReceivingAmount": 810,
  "exchangeRate": 8.1,
  "feesIncluded": 5,
  "transactionId": "Transaction:019542f5-b3e7-1d02-0000-000000000025"
}

Locking Amount: Sending vs. Receiving

When creating a quote, you can choose to either lock the amount you’re sending (fiat) or the amount the customer receives (Bitcoin).

Lock Sending Amount

Use this when you want to send a fixed dollar amount (e.g., $1.00 reward).
{
  "lockedCurrencySide": "SENDING",
  "lockedCurrencyAmount": 100 // $1.00 in cents
}
The customer receives whatever Bitcoin this amount buys at the current rate.

Lock Receiving Amount

Use this when you want the receiver to receive a specific Bitcoin amount (e.g., 1000 sats).
{
  "lockedCurrencySide": "RECEIVING",
  "lockedCurrencyAmount": 1000 // 1000 satoshis
}
Your platform account is debited whatever fiat amount is needed to send that Bitcoin amount.
For consistent dollar-value rewards, use SENDING. For consistent Bitcoin-value rewards, use RECEIVING.

Execution Options

Immediate Execution (Market Order)

Set immediatelyExecute: true to create and execute the quote in one step. This is ideal for automated reward distribution where you accept the current market rate.
{
  "immediatelyExecute": true
}
The quote is created and executed immediately. You receive a transactionId in the response.

Two-Step Execution (Review Before Sending)

Omit immediatelyExecute or set it to false to review the quote before executing.
{
  "immediatelyExecute": false // or omit this field
}
The response will be the same as the immediate execution response, but the status will be PENDING and you’ll have until the quote’s expiresAt timestamp to execute the quote. After reviewing the quote’s exchange rate and fees, execute it:
curl -X POST "https://api.lightspark.com/grid/2025-10-13/quotes/{quoteId}/execute" \
  -H "Authorization: Basic $GRID_CLIENT_ID:$GRID_CLIENT_SECRET"
Quotes expire after a short time (typically 5 minutes). You must execute before expiration.

Destination Options

Inline External Account Creation

Use externalAccountDetails to create the destination wallet on the fly. This is perfect for one-time or infrequent payouts.
{
  "destination": {
    "externalAccountDetails": {
      "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
      "currency": "BTC",
      "accountInfo": {
        "accountType": "SPARK_WALLET",
        "address": "spark1pgssyuuuhnrrdjswal5c3s3rafw9w3y5dd4cjy3duxlf7hjzkp0rqx6dj6mrhu"
      }
    }
  }
}
The external account is created automatically and returned in the quote response.

Pre-Registered External Account

If you’ve already registered the external account, reference it by ID. This is more efficient for recurring rewards to the same wallets. First, create the external account:
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"
    }
  }'
Then reference it in /quotes:
{
  "destination": {
    "accountId": "ExternalAccount:b23dcbd6-dced-4ec4-b756-3c3a9ea3d456"
  }
}
Pre-register external accounts for customers who receive regular rewards. This avoids duplicate account creation and improves performance.

Tracking Delivery

Webhook Notification

When the Bitcoin transfer completes, you’ll receive a webhook:
{
  "transaction": {
    "id": "Transaction:019542f5-b3e7-1d02-0000-000000000025",
    "status": "COMPLETED",
    "type": "OUTGOING",
    "sentAmount": {
      "amount": 100,
      "currency": { "code": "USD" }
    },
    "receivedAmount": {
      "amount": 810,
      "currency": { "code": "BTC" }
    },
    "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
    "settledAt": "2025-10-03T15:01:45Z"
  },
  "type": "OUTGOING_PAYMENT"
}

Polling Status

Alternatively, poll the quote or transaction endpoint:
curl -X GET "https://api.lightspark.com/grid/2025-10-13/quotes/{quoteId}" \
  -H "Authorization: Basic $GRID_CLIENT_ID:$GRID_CLIENT_SECRET"
Or:
curl -X GET "https://api.lightspark.com/grid/2025-10-13/transactions/{transactionId}" \
  -H "Authorization: Basic $GRID_CLIENT_ID:$GRID_CLIENT_SECRET"

Common Patterns

Fixed Dollar Rewards (e.g., $1.00 per action)

{
  "source": { "accountId": "InternalAccount:..." },
  "destination": { "externalAccountDetails": { ... } },
  "lockedCurrencySide": "SENDING",
  "lockedCurrencyAmount": 100,
  "immediatelyExecute": true
}

Fixed Satoshi Rewards (e.g., 1000 sats per action)

{
  "source": { "accountId": "InternalAccount:..." },
  "destination": { "accountId": "ExternalAccount:..." },
  "lockedCurrencySide": "RECEIVING",
  "lockedCurrencyAmount": 1000,
  "immediatelyExecute": true
}

Review Before Sending

{
  "source": { "accountId": "InternalAccount:..." },
  "destination": { "accountId": "ExternalAccount:..." },
  "lockedCurrencySide": "SENDING",
  "lockedCurrencyAmount": 5000,
  "immediatelyExecute": false
}
Then review the exchange rate and fees, and execute:
curl -X POST "https://api.lightspark.com/grid/2025-10-13/quotes/{quoteId}/execute" \
  -H "Authorization: Basic $GRID_CLIENT_ID:$GRID_CLIENT_SECRET"

Best Practices

Use immediatelyExecute: true for automated, small-dollar rewards where you accept market rates.
Pre-register external accounts for customers receiving recurring rewards to improve performance.
Set up webhook handlers to track completion status and update your reward records.
Ensure your platform’s internal account has sufficient balance before distributing rewards. Monitor balances via the /platform/internal-accounts endpoint or account status webhooks.
I