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:

PathFieldUse when
BOLT11 invoicerequest: { bolt11 }You have an invoice from the recipient. Amount and description are encoded in the invoice.
Lightning Addressaddress: { lightning_address, amount }You only have a Lightning Address ([email protected]). You specify how much to send.
Saved destinationdestination: { payment_destination_id, amount }You saved the recipient as a payment destination. You specify how much to send.

Input fields

FieldTypeRequiredNotes
wallet_idUUIDyesThe wallet the funds come from
request.bolt11string (1 – 2048)one ofBOLT11 invoice string
address.lightning_addressstring (1 – 255)one of[email protected] format
address.amountstringwith addressPositive integer in the wallet asset's base unit
destination.payment_destination_idUUIDone ofA saved payment destination
destination.amountstringwith destinationPositive integer in the wallet asset's base unit
idempotency_keystring (1 – 255)noReplays return the original transaction
metadatastring (JSON, ≤2048)noSender-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 with Invoice 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 | FAILED

The 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
        }
      }
    }
  }
}
  • error is null on success and populated with a human-readable reason on FAILED (e.g. routing failure, insufficient liquidity, invoice already paid).
  • events is the ordered state-transition log. details carries provider-specific context (route attempts, HTLC failures); use it when filing a support ticket.
  • exchange_rate is set for Taproot Asset sends once settled, null for 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 progress

If 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" }),
}

completepayment.completed, failpayment.failed. See Environments for the full table.

Next steps