Developer Guide
Sending (USD Line of Credit)
Sending Payments with USD Line of Credit
Section titled “Sending Payments with USD Line of Credit”This guide explains how to send Lightning Network and on-chain Bitcoin payments from a USD-denominated wallet using the Voltage Payments API. USD wallets leverage a line of credit to convert USD to BTC at the time of payment.
Prerequisites
Section titled “Prerequisites”- A Voltage account with an active USD wallet (credit-backed wallet with an associated USD line of credit)
- An API key with access to the environment (from the “API Keys” page in your dashboard)
- The Quotes API enabled, and a valid
line_of_credit_idfor your USD wallet’s line of credit - The target Lightning invoice or Bitcoin address you intend to pay
Workflow Overview
Section titled “Workflow Overview”Sending from a USD wallet involves three steps:
- Determine the BTC amount – If paying a Lightning invoice, decode it to extract the payment amount in millisatoshis. For on-chain payments where you already know the amount, skip to Step 2.
- Obtain a conversion quote – Use the
POST /quotesendpoint to get a quote for converting USD to BTC. This locks in an exchange rate and returns aquote_id. - Create the payment – Call the
POST /paymentsendpoint with your USD wallet, including thequote_idand payment details.
Step 1: Determine the BTC Amount from a Lightning Invoice
Section titled “Step 1: Determine the BTC Amount from a Lightning Invoice”To create a quote, you need the BTC amount in millisatoshis (msats). When paying a Lightning invoice, the amount is encoded in the invoice string itself and must be extracted before you can request a quote.
JavaScript / TypeScript
Section titled “JavaScript / TypeScript”Using light-bolt11-decoder:
npm install light-bolt11-decoderimport { decode } from 'light-bolt11-decoder';
const invoice = 'lnbc1500n1p...';const decoded = decode(invoice);
const amountSection = decoded.sections.find(s => s.name === 'amount');const amountMsats = amountSection ? Number(amountSection.value) : null;
if (!amountMsats) { throw new Error('Invoice does not contain an amount');}
console.log(`Amount: ${amountMsats} msats`);// Use amountMsats as the "amount" in your quote request (Step 2)Python
Section titled “Python”Using bolt11:
pip install bolt11import bolt11
invoice = "lnbc1500n1p..."decoded = bolt11.decode(invoice)
amount_msats = decoded.amount_msatif not amount_msats: raise ValueError("Invoice does not contain an amount")
print(f"Amount: {amount_msats} msats")# Use amount_msats as the "amount" in your quote request (Step 2)Step 2: Get a Quote for USD→BTC Conversion
Section titled “Step 2: Get a Quote for USD→BTC Conversion”Before creating a payment from a USD wallet, you must get a quote to convert the payment amount into BTC. Use the amount you decoded in Step 1 (or the amount you already know for on-chain payments).
Endpoint
Section titled “Endpoint”POST https://voltageapi.com/v1/organizations/{organization_id}/environments/{environment_id}/quotesHeaders
Section titled “Headers”x-api-key: your-api-keyContent-Type: application/jsonExample Request
Section titled “Example Request”curl 'https://voltageapi.com/v1/organizations/{organization_id}/environments/{environment_id}/quotes' \ --request POST \ --header 'x-api-key: your-api-key' \ --header 'Content-Type: application/json' \ --data '{ "id": "87654321-4321-8765-cba9-fed987654321", "line_of_credit_id": "{line_of_credit_id}", "network": "mainnet", "amount": { "amount": 150000, "currency": "btc", "unit": "msats" }, "to": "usd" }'Request Fields
Section titled “Request Fields”id– A client-generated UUID for the quote (for idempotency)line_of_credit_id– Your USD line of credit IDnetwork– The Bitcoin network (“mainnet”, “testnet”, “signet”, or “mutinynet”)amount– The BTC amount you need to send (in msats). When paying a Lightning invoice, this is the amount decoded in Step 1.to– Target currency for conversion (“usd”)
The API will respond with a quote object containing an exchange rate and a quote_id. Use that quote_id in Step 3.
Step 3: Create a Payment from the USD Wallet
Section titled “Step 3: Create a Payment from the USD Wallet”With a valid quote in hand, create the payment using the POST /payments endpoint.
Endpoint
Section titled “Endpoint”POST https://voltageapi.com/v1/organizations/{organization_id}/environments/{environment_id}/paymentsHeaders
Section titled “Headers”x-api-key: your-api-keyContent-Type: application/json3.1 Send a Lightning (Bolt11) Payment
Section titled “3.1 Send a Lightning (Bolt11) Payment”To pay a Lightning invoice from a USD wallet, provide the invoice in the payment_request field.
curl 'https://voltageapi.com/v1/organizations/{organization_id}/environments/{environment_id}/payments' \ --request POST \ --header 'x-api-key: your-api-key' \ --header 'Content-Type: application/json' \ --data '{ "id": "68d00852-8dd8-4c71-94d2-91c84695da78", "wallet_id": "{usd_wallet_id}", "currency": "usd", "quote_id": "12345678-1234-5678-9abc-def012345678", "type": "bolt11", "data": { "payment_request": "lnbc1500n1p...", "amount": { "currency": "btc", "amount": 150000, "unit": "msats" }, "max_fee": { "currency": "btc", "amount": 1000, "unit": "msats" } } }'Request Fields
Section titled “Request Fields”id– A client-generated UUID for the payment (for idempotency)wallet_id– The UUID of your USD walletcurrency– “usd” (the wallet’s currency)quote_id– The UUID of the quote obtained in Step 2 (required for USD wallets)type– “bolt11” for a Lightning paymentdata.payment_request– The BOLT-11 Lightning invoice string (cannot be empty)data.amount– Optional BTC amount object. Required if the invoice has no amount encoded; must match if the invoice has a fixed amountdata.max_fee– Optional maximum routing fee in BTC (defaults to 1% of payment or 1,000 msats, whichever is greater)
3.2 Send an On-Chain Bitcoin Payment
Section titled “3.2 Send an On-Chain Bitcoin Payment”To send BTC on-chain from a USD wallet, provide the Bitcoin address and amount.
curl 'https://voltageapi.com/v1/organizations/{organization_id}/environments/{environment_id}/payments' \ --request POST \ --header 'x-api-key: your-api-key' \ --header 'Content-Type: application/json' \ --data '{ "id": "2ec1e783-19b4-4c10-8181-66336a6232bd", "wallet_id": "{usd_wallet_id}", "currency": "usd", "quote_id": "12345678-1234-5678-9abc-def012345678", "type": "onchain", "data": { "address": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh", "amount": { "currency": "btc", "amount": 15000000, "unit": "msats" }, "max_fee": { "currency": "btc", "amount": 1000000, "unit": "msats" }, "description": "Payment for services" } }'Request Fields
Section titled “Request Fields”type– “onchain” for an on-chain BTC paymentdata.address– The recipient’s Bitcoin addressdata.amount– The amount to send in BTC (msats). Example: 15,000,000 msats = 15,000 satsdata.max_fee– Optional maximum miner fee in msatsdata.description– Optional memo for your records
3.3 Send a Unified BIP21 Payment
Section titled “3.3 Send a Unified BIP21 Payment”A BIP21 URI can include both an on-chain address and an embedded Lightning invoice. The API will parse the URI and execute the payment via Lightning or on-chain as appropriate.
curl 'https://voltageapi.com/v1/organizations/{organization_id}/environments/{environment_id}/payments' \ --request POST \ --header 'x-api-key: your-api-key' \ --header 'Content-Type: application/json' \ --data '{ "id": "3e84b6c5-5bbe-4e0f-9fb3-f1198330f6fa", "wallet_id": "{usd_wallet_id}", "currency": "usd", "quote_id": "12345678-1234-5678-9abc-def012345678", "type": "bip21", "data": { "address": "bitcoin:bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh?label=Example%20Store&message=Payment%20for%20services&lightning=lnbc1500...qpz", "payment_request": "lnbc1500n1p...", "amount": { "currency": "btc", "amount": 150000, "unit": "msats" }, "max_fee": { "currency": "btc", "amount": 1000, "unit": "msats" }, "description": "Payment for services" } }'Request Fields
Section titled “Request Fields”type– “bip21” for a unified Bitcoin paymentdata.address– The BIP21 URI string (required)data.payment_request– Optional Lightning invoice if you have it separatelydata.amount– Optional BTC amount object (can be omitted if URI contains amount)data.max_fee– Optional max Lightning fee in msatsdata.description– Optional memo (independent of any invoice memo)
Monitoring Payment Status
Section titled “Monitoring Payment Status”After initiating a payment, monitor its status using:
GET https://voltageapi.com/v1/organizations/{organization_id}/environments/{environment_id}/payments/{payment_id}Example
Section titled “Example”curl 'https://voltageapi.com/v1/organizations/{organization_id}/environments/{environment_id}/payments/{payment_id}' \ --header 'x-api-key: your-api-key'Payment States
Section titled “Payment States”- sending – Payment is in progress
- completed – Payment was successful and funds have been delivered
- failed – Payment failed (check the
errorfield for details)
Response Fields for USD Payments
Section titled “Response Fields for USD Payments”For completed USD payments, the response includes:
data.market_quote– The exchange rate used for USD/BTC conversiondata.amount– The amount in USD that was debited from your wallet
Error Handling
Section titled “Error Handling”HTTP Status Codes
Section titled “HTTP Status Codes”- 200 – Success
- 400 – Invalid request (missing fields, expired/invalid quote, etc.)
- 403 – Authentication or permissions error
- 404 – Resource not found
- 500 – Server error
Common Errors
Section titled “Common Errors”- Missing quote_id – USD wallet payments require a valid
quote_id - Expired quote – Quotes are time-limited; obtain a new one
- Invalid invoice – The Lightning invoice is malformed or expired
- Insufficient balance – Your USD wallet doesn’t have enough funds
When a payment fails, the status will be “failed” and the error object will contain details about the failure reason.