Send Payments
Pay outbound Lightning invoices and Lightning Addresses programmatically from any Amboss wallet.
Pay an outbound Lightning invoice or Lightning Address from one of your wallets.
payment.transaction.create_send(input: CreateSendTransactionInput) → PaymentsTransaction
Two send paths
Exactly one of request or address must be provided:
| Path | Field | Use when |
|---|---|---|
| BOLT11 invoice | request: { bolt11 } | You have an invoice from the recipient. Amount and description are encoded in the invoice. |
| Lightning Address | address: { lightning_address, amount } | You only have a Lightning Address ([email protected]). You specify how much to send. |
Input fields
| Field | Type | Required | Notes |
|---|---|---|---|
wallet_id | UUID | yes | The wallet the funds come from |
request.bolt11 | string (1 – 2048) | one of | BOLT11 invoice string |
address.lightning_address | string (1 – 255) | one of | [email protected] format |
address.amount | string | with address | Positive integer in the wallet asset's base unit |
idempotency_key | string (1 – 255) | no | Replays return the original transaction |
metadata | string (JSON, ≤2048) | no | Sender-side annotation. The receiver-visible description lives on the BOLT11. |
Pay a BOLT11 invoice
mutation SendBolt11 {
payment {
transaction {
create_send(input: {
wallet_id: "5e4b1e2a-9f3c-4a5b-8c7d-1234567890ab"
request: { bolt11: "lnbc100u1p3xxxxxxxx..." }
idempotency_key: "payout-2026-06-01-42"
metadata: "{\"payout_id\":\"42\"}"
}) {
id
status
payment_hash
amount { full_amount }
}
}
}
}curl -X POST https://rails.amboss.tech/graphql \
-H "Content-Type: application/json" \
-H "x-api-key: $AMBOSS_API_KEY" \
-d '{
"query": "mutation($input: CreateSendTransactionInput!) { payment { transaction { create_send(input: $input) { id status payment_hash } } } }",
"variables": {
"input": {
"wallet_id": "5e4b1e2a-9f3c-4a5b-8c7d-1234567890ab",
"request": { "bolt11": "lnbc100u1p3xxxxxxxx..." },
"idempotency_key": "payout-2026-06-01-42"
}
}
}'import { GraphQLClient, gql } from "graphql-request";
const client = new GraphQLClient("https://rails.amboss.tech/graphql", {
headers: { "x-api-key": process.env.AMBOSS_API_KEY },
});
const CREATE_SEND = gql`
mutation CreateSend($input: CreateSendTransactionInput!) {
payment {
transaction {
create_send(input: $input) {
id
status
payment_hash
}
}
}
}
`;
const { payment } = await client.request(CREATE_SEND, {
input: {
wallet_id: walletId,
request: { bolt11: invoiceString },
idempotency_key: `payout-${payoutId}`,
metadata: JSON.stringify({ payout_id: payoutId }),
},
});Pay a Lightning Address
mutation SendToAddress {
payment {
transaction {
create_send(input: {
wallet_id: "5e4b1e2a-9f3c-4a5b-8c7d-1234567890ab"
address: {
lightning_address: "[email protected]"
amount: "50000"
}
idempotency_key: "tip-2026-06-01-alice"
}) {
id
status
}
}
}
}await client.request(CREATE_SEND, {
input: {
wallet_id: walletId,
address: {
lightning_address: "[email protected]",
amount: "50000", // base units
},
idempotency_key: `tip-${tipId}`,
},
});Lightning Address sends from Taproot Asset wallets are not yet supported. Use a BTC wallet for Lightning Address payouts, or send to a BOLT11 from a stablecoin wallet.
Network constraints
- Live wallets only accept invoices for the production network (mainnet
lnbc…). Invoices for testnet, mutinynet, or regtest are rejected withInvoice network … is not allowed for this wallet. - Sandbox wallets accept invoices on any network — useful for testing against your own infrastructure or public testnets.
- Amountless invoices are not yet supported. The BOLT11 must encode a positive amount.
- Expired invoices are rejected up front (
Invoice has already expired). - The wallet must have an attached node for the asset type. For Taproot Assets the node must have tapd capability.
Lifecycle
Send transactions follow the same status machine as receive:
PENDING → COMPLETED | FAILEDThe payment.completed and payment.failed webhooks fire on terminal transitions. The data.direction field on the envelope is "send". See Webhooks.
Inspecting a send
When a send terminates as FAILED, the failure reason is on the transaction itself — query error and events for the full picture:
query GetSend($id: String!) {
payment {
transaction {
find_one(id: $id) {
id
status
settle_amount { full_amount }
settled_at
exchange_rate
error
events {
event_type
message
details
created_at
}
}
}
}
}errorisnullon success and populated with a human-readable reason onFAILED(e.g. routing failure, insufficient liquidity, invoice already paid).eventsis the ordered state-transition log.detailscarries provider-specific context (route attempts, HTLC failures); use it when filing a support ticket.exchange_rateis set for Taproot Asset sends once settled,nullfor BTC.
Don't use settle_amount_sats. It is deprecated in favor of settle_amount, which carries both the value and the asset metadata. The deprecated field will be removed in a future release.
Idempotency
idempotency_key is highly recommended for sends — a retry without a key can result in a double payment. Replays with the same (wallet_id, idempotency_key) return the original transaction.
Concurrent requests with the same key are serialized:
A request with this idempotency_key is already in progressIf you omit idempotency_key, the server generates one internally per call (so each call is unique by definition). The safer pattern is for you to choose one tied to your business identifier (payout-${id}).
Sandbox testing
Set metadata.amb_sandbox_behavior to drive terminal state in sandbox:
{
wallet_id: walletId,
request: { bolt11: anySandboxInvoice },
metadata: JSON.stringify({ amb_sandbox_behavior: "complete" }),
}complete → payment.completed, fail → payment.failed. See Environments for the full table.