Receive Payments
Receive Bitcoin and stablecoin payments via Lightning. Generate BOLT11 invoices, render QR codes, and track status through webhooks.
Generate a Lightning invoice the payer can pay. The mutation returns a BOLT11 payment_request you render as a QR code or lightning: link, plus a transaction record whose status you can track via webhooks.
payment.transaction.create_receive(input: CreateReceiveTransactionInput) → PaymentsTransaction
Input fields
| Field | Type | Required | Notes |
|---|---|---|---|
wallet_id | UUID | yes | The wallet that will receive the funds |
amount | string | yes | Positive integer in the wallet asset's base unit (sats for BTC, micro-units for stablecoins) |
description | string (≤640 chars) | no | Encoded in the BOLT11; visible to the payer |
expires_in_seconds | int (1 – 2,592,000) | no | Invoice expiry. Defaults to 10 minutes |
idempotency_key | string (1 – 255 chars) | no | Replays return the original invoice instead of creating a new one |
metadata | string (JSON, ≤2048 chars) | no | Application metadata; round-tripped on webhooks |
Create an invoice
mutation CreateReceive {
payment {
transaction {
create_receive(input: {
wallet_id: "5e4b1e2a-9f3c-4a5b-8c7d-1234567890ab"
amount: "100000"
description: "Order #42"
expires_in_seconds: 3600
idempotency_key: "order-42-attempt-1"
metadata: "{\"order_id\":\"42\"}"
}) {
id
status
payment_request
payment_hash
expires_at
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: CreateReceiveTransactionInput!) { payment { transaction { create_receive(input: $input) { id status payment_request payment_hash expires_at amount { full_amount } } } } }",
"variables": {
"input": {
"wallet_id": "5e4b1e2a-9f3c-4a5b-8c7d-1234567890ab",
"amount": "100000",
"description": "Order #42",
"expires_in_seconds": 3600,
"idempotency_key": "order-42-attempt-1",
"metadata": "{\"order_id\":\"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_RECEIVE = gql`
mutation CreateReceive($input: CreateReceiveTransactionInput!) {
payment {
transaction {
create_receive(input: $input) {
id
status
payment_request
payment_hash
expires_at
}
}
}
}
`;
const { payment } = await client.request(CREATE_RECEIVE, {
input: {
wallet_id: walletId,
amount: "100000",
description: `Order #${orderId}`,
expires_in_seconds: 3600,
idempotency_key: `order-${orderId}-attempt-${attempt}`,
metadata: JSON.stringify({ order_id: orderId }),
},
});
// Show payment.transaction.create_receive.payment_request to the customerExample response:
{
"data": {
"payment": {
"transaction": {
"create_receive": {
"id": "tx_01HX9YQK7P8MVZ3FN4G2RWS6CD",
"status": "PENDING",
"payment_request": "lnbc1m1p0...",
"payment_hash": "3b6e7d...",
"expires_at": "2026-06-02T13:30:00.000Z",
"amount": { "full_amount": "100000" }
}
}
}
}
}Render payment_request as a QR code (or a lightning: link). Once paid, the transaction moves to COMPLETED and a payment.completed webhook fires.
Lifecycle
Each transition emits the matching webhook: payment.completed, payment.expired, payment.failed. See Webhooks for the payload shape.
Idempotency
If you set idempotency_key, replaying the same (wallet_id, idempotency_key) pair returns the original invoice rather than creating a new one. This makes it safe to retry from your side without orphaning invoices.
Concurrent requests with the same key are serialized; if a second call arrives while the first is still in-flight, it returns:
A request with this idempotency_key is already in progressSandbox testing
In sandbox environments, drive deterministic state transitions via the metadata flag:
{
amount: "100000",
wallet_id: walletId,
metadata: JSON.stringify({
amb_sandbox_behavior: "complete", // 'complete' | 'fail' | 'expire'
order_id: orderId,
}),
}complete→payment.completedfires after a short delayfail→payment.failedexpire(default) → invoice expires naturally
Use this in integration tests to exercise every branch without a live Lightning node.
Inspecting a transaction
Webhooks are the recommended path, but you can also poll a transaction directly. find_one returns the full PaymentsTransaction including the event timeline, exchange rate, and the failure reason when applicable:
query GetTransaction($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
}
}
}
}
}| Field | When populated | Notes |
|---|---|---|
error | status: FAILED | Human-readable reason the payment terminated. null on success. |
events | always | Ordered timeline of state transitions. event_type mirrors the webhook (payment.pending, payment.completed, …). details is a JSON string with route/provider-specific context. Useful for support tickets and post-mortems. |
exchange_rate | Taproot Asset wallets | The asset→sats rate used at settlement, as a decimal string. null for BTC and null until settlement for assets. |
settle_amount | status: COMPLETED | Use this. Pair with full_amount to render the settled value. |
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.
Listing transactions
Use payment.transaction.find_many for history views, reconciliation, or pagination. wallet_id and environment_id are mutually exclusive scopes; filter narrows by direction, status, or date range:
query ListTransactions {
payment {
transaction {
find_many(input: {
environment_id: "81b73615-ddf3-46e3-943a-467c3e442e04"
filter: {
direction: RECEIVE
status: COMPLETED
date_range: { from: "2026-06-01T00:00:00Z", to: "2026-06-30T23:59:59Z" }
}
page: { limit: 50, offset: 0 }
}) {
total_count
pagination { limit offset }
list {
id
status
direction
amount { full_amount }
settled_at
wallet_id
}
}
}
}
}list returns SimplePaymentsTransaction — a subset of the full record. Fetch any single row with find_one(id) to get events, error, payment_hash, payment_request, and exchange_rate.