Send Payments
Pay outbound Lightning invoices, Lightning Addresses, and saved payment destinations programmatically from any Amboss wallet.
Pay an outbound Lightning invoice, Lightning Address, or saved payment destination from one of your wallets.
payment.transaction.create_send(input: CreateSendTransactionInput) → PaymentsTransaction
Equivalent nested GraphQL syntax:
mutation {
payment {
transaction {
create_send(input: { … }) { … }
}
}
}Using TypeScript? payments.transactions.send in the SDK handles both BOLT11 and Lightning Address sends, picks the node endpoint automatically, and streams live progress.
Three send paths
Exactly one of request, address, or destination 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. |
| Saved destination | destination: { payment_destination_id, amount } | You saved the recipient as a payment destination. 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 |
destination.payment_destination_id | UUID | one of | A saved payment destination |
destination.amount | string | with destination | 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. This applies to saved destinations too, since they resolve to Lightning Addresses.
Pay a saved destination
For recipients you pay repeatedly, save the Lightning Address as a payment destination once and send by id:
mutation SendToDestination {
payment {
transaction {
create_send(input: {
wallet_id: "5e4b1e2a-9f3c-4a5b-8c7d-1234567890ab"
destination: {
payment_destination_id: "c2f9d8e1-4b6a-4f3c-9d2e-0987654321fe"
amount: "50000"
}
idempotency_key: "payout-2026-07-03-alice"
}) {
id
status
}
}
}
}await client.request(CREATE_SEND, {
input: {
wallet_id: walletId,
destination: {
payment_destination_id: destinationId,
amount: "50000", // base units
},
idempotency_key: `payout-${payoutId}`,
},
});The transaction records the payment_destination_id, keeping payout history linked to the saved destination.
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.