Receiving (BTC Line of Credit)
Receiving Payments with Bitcoin Line of Credit
This guide explains how to receive Lightning, on-chain Bitcoin, and BIP21 unified payments into a BTC-denominated wallet using the Voltage Payments API.
For Development testing, choose Mutinynet Bitcoin. This is the correct wallet for a Bitcoin line of credit as well as Node-backed Bitcoin testing. Mutinynet USD and Voltage Cash are not the correct wallets for this workflow.
Prerequisites
- A Voltage account with an active BTC wallet (wallet associated with a Bitcoin line of credit)
- An Environment API key (x-api-key) from your dashboard
No quotes needed! Unlike USD wallets, BTC wallets receive payments directly in BTC without currency conversion. You do not need to use the Quotes API.
Workflow Overview
Receiving a payment is a two-step process:
- Create a receive payment request (invoice/address/URI)
- Retrieve the payment to get the invoice details and monitor status
Key Data Shapes
Amount Object
{
"amount": 150000,
"currency": "btc",
"unit": "msats"
}BTC amounts use millisatoshis (msats) as the smallest unit.
Legacy fields amount_msats and amount_sats are still accepted but deprecated. Prefer the amount object.
Payment Kinds (receive)
- bolt11 – Lightning invoice
- onchain – On-chain Bitcoin address
- bip21 – Unified BIP21 URI (on-chain + optional Lightning)
- taprootasset – Taproot Asset invoice (not covered in this guide)
Receive Statuses
- generating – Invoice/address is being created
- receiving – Invoice/address created and waiting for payment
- completed – Fully received and credited
- expired – Invoice expired before being paid
- failed – Could not be generated or completed
Creating Receive Payments
Endpoint
POST https://voltageapi.com/v1/organizations/{organization_id}/environments/{environment_id}/paymentsHeaders
x-api-key: your-api-key
Content-Type: application/jsonReceive a Fixed-Amount Lightning (BOLT11) Payment
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": "11ca843c-bdaa-44b6-965a-39ac550fcef7",
"wallet_id": "{wallet_id}",
"currency": "btc",
"payment_kind": "bolt11",
"amount": {
"amount": 150000,
"currency": "btc",
"unit": "msats"
},
"description": "test payment",
"expiration": 3600
}'Required Fields
- id – Your unique idempotent ID (UUID recommended)
- wallet_id – Wallet that will receive funds
- currency – "btc" (must match the wallet's currency)
- payment_kind – "bolt11"
- amount – Amount object for the requested amount
Optional Fields
- description – Memo/description (appears as memo in the response)
- expiration – Invoice expiry in seconds (default: 3600, max: 86400 for Lightning)
Receive a Lightning Invoice with Any Amount
BTC wallets support "pay any amount" invoices. Simply omit the amount 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": "b3e12e2f-5e80-4fb6-9c37-0a2d9af6c1f0",
"wallet_id": "{wallet_id}",
"currency": "btc",
"payment_kind": "bolt11",
"description": "donation (any amount)",
"expiration": 3600
}'Any-amount invoices are only supported for BTC wallets, not USD wallets (which require a fixed quote).
Receive an On-Chain BTC Payment
Creates a new on-chain address and tracks the payment:
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": "11ca843c-bdaa-44b6-965a-39ac550fcef8",
"wallet_id": "{wallet_id}",
"currency": "btc",
"payment_kind": "onchain",
"amount": {
"amount": 150000000,
"currency": "btc",
"unit": "msats"
},
"description": "on-chain deposit"
}'The response will include:
- A Bitcoin address in data.address
- data.receipts entries as the transaction confirms
For accounting simplicity, please separate Lightning and on-chain usage between different wallets if you are on a node-backed setup.
Receive a BIP21 Unified Payment (On-Chain + Lightning)
Creates a BIP21 URI that can embed both an on-chain address and a Lightning invoice:
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": "11ca843c-bdaa-44b6-965a-39ac550fcef9",
"wallet_id": "{wallet_id}",
"currency": "btc",
"payment_kind": "bip21",
"amount": {
"amount": 150000,
"currency": "btc",
"unit": "msats"
},
"description": "Payment for services",
"expiration": 3600
}'The resulting data will include:
- payment_request (optional BOLT11)
- address (BTC address)
- receipts for completed on-chain or Lightning parts
Retrieve Payment Details
Endpoint
GET https://voltageapi.com/v1/organizations/{organization_id}/environments/{environment_id}/payments/{payment_id}Example
curl 'https://voltageapi.com/v1/organizations/{organization_id}/environments/{environment_id}/payments/{payment_id}' \
--header 'x-api-key: your-api-key'Example Response
{
"direction": "receive",
"id": "11ca843c-bdaa-44b6-965a-39ac550fcef7",
"wallet_id": "{wallet_id}",
"organization_id": "{organization_id}",
"environment_id": "{environment_id}",
"created_at": "2025-02-12T20:16:14.095785Z",
"updated_at": "2025-02-12T20:16:14.807961Z",
"currency": "btc",
"type": "bolt11",
"data": {
"payment_request": "lntbs1500n1pn66qv...",
"amount": {
"amount": 150000,
"currency": "btc",
"unit": "msats"
},
"amount_msats": 150000,
"memo": "test payment",
"expiration": 3600,
"market_quote": null
},
"requested_amount": {
"amount": 150000,
"currency": "btc",
"unit": "msats"
},
"status": "receiving",
"error": null,
"frozen": [],
"exchanges": []
}Key Response Fields
- direction – Always "receive" for incoming payments
- type – bolt11 | onchain | bip21 | taprootasset
- data.payment_request / data.address / data.receipts depending on type
- requested_amount – What you originally requested
- status – Current receive state
- error – Structured error info if something failed
- frozen – Parts of the payment frozen for compliance (e.g., OFAC)
Listing Incoming Payments
Endpoint
GET https://voltageapi.com/v1/organizations/{organization_id}/environments/{environment_id}/paymentsQuery Parameters
- direction=receive – Only incoming payments
- wallet_id={wallet_id} – Specific wallet
- statuses[]=receiving&statuses[]=completed – Filter by status
- offset, limit – Pagination
Example
curl 'https://voltageapi.com/v1/organizations/{organization_id}/environments/{environment_id}/payments?direction=receive&wallet_id={wallet_id}&limit=50' \
--header 'x-api-key: your-api-key'Viewing Payment History
See the lifecycle of a receive payment:
GET https://voltageapi.com/v1/organizations/{organization_id}/environments/{environment_id}/payments/{payment_id}/historyThe response contains ordered events with timestamps and errors (if any), helpful for debugging or audits.
Monitoring Receive Status
Typical state transitions:
- generating → Payment being set up (invoice/address generation)
- receiving → Invoice/address generated, waiting for funds
- completed → Funds received and credited
- expired → Invoice expired before payment
- failed → An error occurred (see error field for details)
You can monitor by:
- Polling GET /payments/{payment_id} until status is terminal (completed, expired, or failed)
- Webhooks (recommended)
Webhooks for Receive Events
Create a webhook to get real-time notifications when receive payments are generated, completed, expired, etc.
Create a Webhook
POST https://voltageapi.com/v1/organizations/{organization_id}/environments/{environment_id}/webhooksInclude:
- id – A client-generated UUID for the webhook registration; the create response returns this same value
- url – Your HTTPS endpoint
- name – Webhook name
- events – Array of event types, e.g.:
[
{ "receive": "generated" },
{ "receive": "completed" },
{ "receive": "expired" },
{ "receive": "failed" }
]The create response also returns a one-time shared_secret. Store it for signature verification; it is not included in callbacks. In a receive callback, detail.data.id is the payment ID supplied when the payment was created, not the webhook ID or organization ID. See Webhooks for the complete payload and identifier map.
Test a Webhook
POST https://voltageapi.com/v1/organizations/{organization_id}/environments/{environment_id}/webhooks/{webhook_id}/testWebhook Payload
- type – "receive"
- detail.data – Full Payment object
- detail.event – Event type (generated, refreshed, expired, succeeded, completed, failed)
Error Handling
HTTP Status Codes
- 202 – Receive payment creation accepted (invoice/address generation started)
- 200 – Successful retrieval/list/history
- 400 – Invalid request (bad IDs, missing fields, etc.)
- 403 – Authentication/authorization error
- 404 – Payment not found in this organization + environment
- 500 – Server error
Receive Errors
Within the payment object, the error field may contain:
- receive_failed
- expired
- rejected