LDK Server exposes a gRPC API over HTTP/2 with TLS. This guide covers transport, authentication, and provides an index of all available RPCs. For field-level details on each request and response, refer to the proto definitions, which are the canonical reference and include links to the underlying LDK Node documentation.
- Protocol: gRPC over HTTP/2 with TLS (self-signed by default)
- Default address:
127.0.0.1:3536 - Content-Type:
application/grpc+proto - Service name:
api.LightningNode - Full RPC path format:
/api.LightningNode/<MethodName>
Each request needs a hex-encoded v2 macaroon in the macaroon header:
macaroon: <hex-encoded-request-macaroon>
Keep your original macaroon private. The client uses it to make a token for each request, as described below. All requests use TLS.
You can add caveats to make a restricted copy of your macaroon without contacting the server. A caveat limits its permissions, allowed methods, or expiry time. Added caveats can only reduce access. See Restrictions for examples.
The Rust client, CLI, and MCP handle request binding automatically. They keep your macaroon private and send a copy tied to the request's method, body, and time.
Custom clients must add one final caveat:
request = <unix-seconds> <RpcMethod> <body-sha256>
Use Unix time in seconds, a method name such as OnchainSend, and the lowercase SHA-256 hash
of the exact gRPC body, including its five-byte frame header. Rust clients can use
macaroon::bind_macaroon_to_request.
Client and server clocks must be within 60 seconds. The token cannot authorize a different request, but the same request can still be replayed while the token is valid.
See Request proof format for exact encoding rules and an example.
A caveat is a condition that limits what a macaroon can do. All caveats must pass:
| Caveat | Meaning |
|---|---|
permissions = node:read,payments:read |
Allow only these permissions |
method = GetNodeInfo |
Allow this RPC method and GetPermissions |
time-before = 1800000000 |
Expire at this Unix time in seconds |
Added caveats can only reduce access. They cannot restore permissions or extend the expiry time.
GetPermissions ignores method restrictions, but still requires a valid, unexpired macaroon.
Derive a restricted copy without contacting the server:
ldk-server-cli derive-macaroon "$MACAROON" \
--caveat 'permissions = node:read' \
--caveat 'method = GetNodeInfo' \
--caveat "time-before = $EXPIRY_UNIX_SECONDS"The command prints a hex token. Rust clients can use macaroon::derive_macaroon.
Give the copy to the application and keep the original private.
Use CreateMacaroon to give each client a token you can revoke separately. New tokens keep
all the caller's restrictions. Revoking the caller's token does not revoke these new tokens.
Copies made with derive-macaroon share the original token's ID. Revoking that ID blocks
all those copies. The server cannot list copies made locally.
Revocation and expiry block new requests. Existing event streams stay open until the client disconnects or the server stops. Reconnecting requires a valid token.
See Macaroon Management for the RPCs and Operations for storage and recovery.
Choose the permissions each client needs, or use admin by itself for full access.
The CLI also has readonly, invoice, and admin presets.
RPCs with no permission mapping return UNIMPLEMENTED, even for admin tokens.
| Permission | Access |
|---|---|
node:read |
Node information, balances, and pathfinding scores |
onchain:receive |
Create on-chain receive addresses |
onchain:send |
Send on-chain funds or bump an on-chain payment fee |
invoices:create |
Create BOLT11/BOLT12 invoices and incoming refund requests |
payments:read |
Read payments, forwarded payments, and forwarding statistics |
payments:claim |
Claim or fail held BOLT11 payments |
payments:send |
Send BOLT11, BOLT12, spontaneous, unified, and refund payments; splice out |
channels:read |
List channels |
channels:manage |
Open, configure, cooperatively close, splice funds into channels, or bump pending splice fees |
channels:force_close |
Force-close channels |
peers:read |
List peers |
peers:manage |
Connect or disconnect peers |
messages:sign |
Sign messages and create BOLT12 payer proofs |
messages:verify |
Verify message signatures |
graph:read |
Read network graph data |
utilities:read |
Decode invoices and offers |
events:read |
Subscribe to the event stream |
macaroons:manage |
Create, list, and revoke macaroons within your permissions |
MCP provides token management through create_macaroon, list_macaroons, revoke_macaroon,
and get_permissions.
The server auto-generates a self-signed ECDSA P-256 certificate on first startup, stored at
<storage_dir>/tls.crt. Clients must pin this certificate (not rely on system trust roots)
since it is self-signed.
For the Rust client library, pass the PEM contents to LdkServerClient::new(). For other
languages, configure your gRPC channel to trust the server's certificate file.
The canonical API definitions live in ldk-server-grpc/src/proto/:
| File | Contents |
|---|---|
api.proto |
All RPC request/response messages and documentation |
types.proto |
Shared types (Payment, Channel, Peer, etc.) |
events.proto |
Event envelope and event types for streaming |
error.proto |
Error response definitions |
Any standard protoc toolchain can generate clients from these proto files. The proto directory
path is ldk-server-grpc/src/proto/. For Rust specifically, the ldk-server-client crate
provides a ready-made async client.
Errors are returned as standard gRPC status codes:
| gRPC Code | Meaning |
|---|---|
INVALID_ARGUMENT (3) |
Malformed request or invalid parameters |
PERMISSION_DENIED (7) |
Missing permission or a caveat that does not pass |
FAILED_PRECONDITION (9) |
Lightning operation error (e.g., insufficient balance, no route) |
INTERNAL (13) |
Server-side bug |
UNAUTHENTICATED (16) |
Missing, invalid, or revoked macaroon |
The grpc-message trailer contains a human-readable error description.
All RPCs are unary (single request, single response) unless noted otherwise.
| RPC | Description |
|---|---|
GetNodeInfo |
Node ID, best block, sync timestamps, listening/announcement addresses, alias, URIs, server version |
GetBalances |
On-chain, Lightning channel, and claimable balance breakdown |
| RPC | Description |
|---|---|
OnchainReceive |
Generate a new on-chain funding address |
OnchainSend |
Send to a Bitcoin address (with optional fee rate and send-all mode) |
OnchainBumpFee |
Raise the fee of an unconfirmed outbound on-chain payment using RBF |
OnchainBumpFee replaces a payment's transaction while preserving its payment ID and recipient
amount. Use the payment_id from ListPayments. The optional fee_rate_sat_per_vb sets the new
total fee rate in sat/vB; omit it to use an automatic rate. The response contains the replacement
txid. Confirmed, inbound, Lightning, and channel funding payments are not eligible.
| RPC | Description |
|---|---|
Bolt11Receive |
Create an invoice (fixed or variable amount) with automatic claim |
Bolt11Send |
Pay a BOLT11 invoice (with optional routing config) |
Bolt11SendUnderpaying |
Send part of the amount for a fixed-amount BOLT11 invoice |
Note
Bolt11SendUnderpaying sends one part of a multi-part payment (MPP) for a fixed-amount
BOLT11 invoice. Other nodes must send compatible partial payments for the same invoice
until the combined amount equals the invoice amount. Without those payments, the
receiver holds the incomplete MPP payment and eventually fails it.
These RPCs support a manual claim/fail workflow for held payments. See Hodl Invoice Lifecycle below.
| RPC | Description |
|---|---|
Bolt11ReceiveForHash |
Create an invoice for a given payment hash (manual claim required) |
Bolt11ClaimForId |
Claim a held payment by its payment ID and preimage |
Bolt11FailForId |
Reject a held payment by its payment ID |
Requires at least one [[liquidity.lsps_client]] entry for an LSPS2-capable LSP. The LSP opens
a channel just-in-time when the invoice is paid.
| RPC | Description |
|---|---|
Bolt11ReceiveViaJitChannel |
Create a fixed-amount invoice with JIT channel opening |
Bolt11ReceiveVariableAmountViaJitChannel |
Create a variable-amount invoice with JIT channel opening |
Bolt11ReceiveViaJitChannelForHash |
Create a fixed-amount invoice with JIT channel opening for a given payment hash (manual claim required) |
Bolt11ReceiveVariableAmountViaJitChannelForHash |
Create a variable-amount invoice with JIT channel opening for a given payment hash (manual claim required) |
| RPC | Description |
|---|---|
Bolt12Receive |
Create a BOLT12 offer (fixed or variable amount) |
Bolt12Send |
Pay a BOLT12 offer (with optional quantity, payer note, routing config) |
Bolt12SendRefund |
Create a BOLT12 refund that this node will pay |
Bolt12ReceiveRefund |
Request an incoming payment for a BOLT12 refund |
Bolt12CreatePayerProof |
Create a BOLT 12 payer proof from a successful payment |
| RPC | Description |
|---|---|
SpontaneousSend |
Send a keysend payment to a node ID |
UnifiedSend |
Pay a BIP 21 URI, BIP 353 Human-Readable Name, BOLT11 invoice, or BOLT12 offer |
| RPC | Description |
|---|---|
OpenChannel |
Open a new outbound channel (with optional push amount and fee config) |
CloseChannel |
Cooperatively close a channel |
ForceCloseChannel |
Force-close a channel unilaterally |
SpliceIn |
Add on-chain funds to an existing channel |
SpliceOut |
Remove funds from a channel back on-chain |
BumpChannelFundingFee |
Raise the fee of a pending splice transaction |
UpdateChannelConfig |
Update forwarding fees and CLTV expiry delta |
ListChannels |
List all channels with balances and configuration |
Note
BumpChannelFundingFee supports pending splices only. It preserves the splice amount and
destination, and LDK Node selects the fee rate. General channel-opening fee bumps and
caller-selected splice fee rates are not supported.
Call it on the node that contributed to the splice, using the channel's user_channel_id and
counterparty_node_id. A channel with no pending splice returns an error. An empty response means
the fee bump has started; use channel events to follow its progress.
The automatic increase can be below Bitcoin Core 29's minimum relay fee increase. Check that the replacement transaction reaches the mempool; a successful RPC does not guarantee relay or confirmation.
| RPC | Description |
|---|---|
GetPaymentDetails |
Get details for a specific payment by ID |
ListPayments |
List all payments (paginated) |
GetForwardedPaymentDetails |
Get a stored forwarded payment by its ID |
GetForwardedPaymentTrackingMode |
Get the configured forwarding history tracking mode |
GetChannelForwardingStats |
Get forwarding statistics for a channel |
ListChannelForwardingStats |
List channel forwarding statistics (paginated) |
ListChannelPairForwardingStats |
List channel-pair forwarding statistics (paginated) |
ListForwardedPayments |
List forwarded payments (paginated) |
See Pagination below for how to page through results.
| RPC | Description |
|---|---|
ConnectPeer |
Connect to a peer (optionally persist the connection) |
DisconnectPeer |
Disconnect from a peer and remove it from the peer store |
ListPeers |
List all connected peers |
| RPC | Description |
|---|---|
SignMessage |
Sign a message with the node's private key |
VerifySignature |
Verify a signature against a message and public key |
| RPC | Description |
|---|---|
GraphListChannels |
List all known short channel IDs in the network graph |
GraphGetChannel |
Get channel details by short channel ID |
GraphListNodes |
List all known node IDs in the network graph |
GraphGetNode |
Get node details by node ID |
| RPC | Description |
|---|---|
ExportPathfindingScores |
Export the router's pathfinding score cache |
DecodeInvoice |
Decode a BOLT11 invoice and return its parsed fields |
DecodeOffer |
Decode a BOLT12 offer and return its parsed fields |
| RPC | Description |
|---|---|
SubscribeEvents |
Server-streaming. Subscribe to real-time payment and channel events |
SubscribeEvents returns a stream of EventEnvelope messages. Each envelope contains one of:
| Event | When |
|---|---|
PaymentReceived |
An inbound payment was received and auto-claimed |
PaymentSuccessful |
An outbound payment succeeded |
PaymentFailed |
An outbound payment failed |
PaymentClaimable |
A hodl invoice payment arrived and is waiting to be claimed or failed |
PaymentForwarded |
A payment was routed through this node |
ChannelStateChanged |
A channel changed state (pending, ready, open failed, closed) |
SpliceNegotiated |
A channel splice was negotiated and the funding transaction is pending confirmation |
SpliceNegotiationFailed |
A channel splice negotiation round failed |
Warning
SubscribeEvents is a best-effort stream of new events. Events are not persisted for
subscribers, cannot be replayed after reconnecting, and have no client acknowledgement.
Acceptance by the server's broadcast channel does not guarantee that a client received or
processed an event.
Events are broadcast to all currently connected subscribers. The server uses a bounded broadcast channel (capacity 1024), so a slow subscriber that falls behind will miss events. Disconnected clients also miss events and receive only new events after reconnecting. If the server cannot read data required to construct a payment event, it logs the error and skips that event so the event queue can continue processing.
Use events as notifications. After reconnecting, reconcile recoverable state with APIs such as
GetPaymentDetails, ListPayments, ListForwardedPayments, and ListChannels. Some event fields
cannot be recovered through these APIs.
| RPC | Description |
|---|---|
CreateMacaroon |
Create a macaroon and return its private hex token in token |
ListMacaroons |
List IDs, names, permissions, and caveats, without secrets |
RevokeMacaroon |
Revoke a macaroon by ID |
GetPermissions |
Show the caller's ID, name, usable permissions, and caveats |
The first three RPCs require macaroons:manage or admin. You can only create or revoke
tokens whose permissions you have. The last unrestricted admin token cannot be revoked.
Metrics are served as a plain HTTP GET endpoint (not gRPC):
GET /metrics
Returns Prometheus-format text. Requires [metrics] enabled = true in the config. Supports
optional Basic Auth. See Configuration for setup.
Subscribe with SubscribeEvents before you send a BOLT 12 payment. Events are not replayed.
When PaymentSuccessful arrives, retain its payment_id, payment_preimage, and
bolt12_invoice. Pass these values to Bolt12CreatePayerProof. The request can also select the
optional invoice fields that the proof discloses. Payment history APIs cannot recover all the
inputs required to create a proof if this event is missed. Save these values before processing
other events.
The bolt12_invoice field is absent for static-invoice payments. These asynchronous payments
cannot produce payer proofs.
Hodl invoices allow you to inspect and conditionally accept incoming payments:
- Subscribe: Call
SubscribeEventsbefore you create or share the invoice. Events are not replayed. - Create the invoice: Generate a new payment hash. Call
Bolt11ReceiveForHash,Bolt11ReceiveViaJitChannelForHashorBolt11ReceiveVariableAmountViaJitChannelForHashwith this hash. Never reuse a payment hash. Reuse is unsafe and can cause loss of funds. - Handle each payment: Save the payment ID from each
PaymentClaimableevent. A payer can pay the same invoice more than once. Each payment has a separate event and payment ID. - Decide before
claim_deadline:- Accept an expected payment: Check the event's
claimable_amount_msatagainst the amount you expect. CallBolt11ClaimForIdwith its payment ID, preimage, and the event's claimable amount. - Reject an unexpected payment: Call
Bolt11FailForIdwith its payment ID. Reject duplicate and late payments instead of ignoring or claiming them.
- Accept an expected payment: Check the event's
The claim request's optional amount is passed to LDK Node for a lower-bound check against its stored payment amount, less any skimmed fee. It is not an exact amount check or a request to claim that many millisatoshis. A larger supplied amount passes this check; omitting it skips the check. Always validate the event's amount before you claim the payment.
The payment is held in a pending state until you claim it, fail it, or its claim_deadline is
reached. PaymentClaimable notifications are best-effort and are not replayed. If you miss the
event or do not act before the deadline, LDK Node automatically fails the HTLC backward and the
payment can no longer be claimed. Keep the subscriber healthy and resolve reported persistence
errors before accepting further payments.
ListPayments, ListForwardedPayments, ListChannelForwardingStats, and
ListChannelPairForwardingStats support cursor-based pagination:
- Make the first request without a
page_token. The server controls the page size. - If the response includes a
next_page_token, pass it aspage_tokenin the next request. - When
next_page_tokenis absent, you have reached the end of the results.
The page token is one opaque string. Do not parse or modify it. Results are ordered by creation time (most recent first).
The CLI --number-of-payments option combines multiple pages. It does not set the gRPC page size.