SendPayment
danger
This RPC is deprecated and will be removed in a future version.
Deprecated, use routerrpc.SendPaymentV2. SendPayment dispatches a bi-directional streaming RPC for sending payments through the Lightning Network. A single RPC invocation creates a persistent bi-directional stream allowing clients to rapidly send payments through the Lightning Network with a single persistent connection.
Source: lightning.proto
gRPC
info
This is a bidirectional-streaming RPC
rpc SendPayment (stream SendRequest) returns (stream SendResponse);
REST
HTTP Method | Path |
---|---|
POST | /v1/channels/transaction-stream |
Code Samples
- gRPC
- REST
- Shell
- Javascript
- Python
const fs = require('fs');
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const GRPC_HOST = 'localhost:10009'
const MACAROON_PATH = 'LND_DIR/data/chain/bitcoin/regtest/admin.macaroon'
const TLS_PATH = 'LND_DIR/tls.cert'
const loaderOptions = {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
};
const packageDefinition = protoLoader.loadSync('lightning.proto', loaderOptions);
const lnrpc = grpc.loadPackageDefinition(packageDefinition).lnrpc;
process.env.GRPC_SSL_CIPHER_SUITES = 'HIGH+ECDSA';
const tlsCert = fs.readFileSync(TLS_PATH);
const sslCreds = grpc.credentials.createSsl(tlsCert);
const macaroon = fs.readFileSync(MACAROON_PATH).toString('hex');
const macaroonCreds = grpc.credentials.createFromMetadataGenerator(function(args, callback) {
let metadata = new grpc.Metadata();
metadata.add('macaroon', macaroon);
callback(null, metadata);
});
let creds = grpc.credentials.combineChannelCredentials(sslCreds, macaroonCreds);
let client = new lnrpc.Lightning(GRPC_HOST, creds);
let request = {
dest: <bytes>,
dest_string: <string>,
amt: <int64>,
amt_msat: <int64>,
payment_hash: <bytes>,
payment_hash_string: <string>,
payment_request: <string>,
final_cltv_delta: <int32>,
fee_limit: <FeeLimit>,
outgoing_chan_id: <uint64>,
last_hop_pubkey: <bytes>,
cltv_limit: <uint32>,
dest_custom_records: <DestCustomRecordsEntry>,
allow_self_payment: <bool>,
dest_features: <FeatureBit>,
payment_addr: <bytes>,
};
let call = client.sendPayment({});
call.on('data', function(response) {
// A response was received from the server.
console.log(response);
});
call.on('status', function(status) {
// The current status of the stream.
});
call.on('end', function() {
// The server has closed the stream.
});
call.write(request);
// Console output:
// {
// "payment_error": <string>,
// "payment_preimage": <bytes>,
// "payment_route": <Route>,
// "payment_hash": <bytes>,
// }
import codecs, grpc, os
# Generate the following 2 modules by compiling the lightning.proto with the grpcio-tools.
# See https://github.com/lightningnetwork/lnd/blob/master/docs/grpc/python.md for instructions.
import lightning_pb2 as lnrpc, lightning_pb2_grpc as lightningstub
GRPC_HOST = 'localhost:10009'
MACAROON_PATH = 'LND_DIR/data/chain/bitcoin/regtest/admin.macaroon'
TLS_PATH = 'LND_DIR/tls.cert'
# create macaroon credentials
macaroon = codecs.encode(open(MACAROON_PATH, 'rb').read(), 'hex')
def metadata_callback(context, callback):
callback([('macaroon', macaroon)], None)
auth_creds = grpc.metadata_call_credentials(metadata_callback)
# create SSL credentials
os.environ['GRPC_SSL_CIPHER_SUITES'] = 'HIGH+ECDSA'
cert = open(TLS_PATH, 'rb').read()
ssl_creds = grpc.ssl_channel_credentials(cert)
# combine macaroon and SSL credentials
combined_creds = grpc.composite_channel_credentials(ssl_creds, auth_creds)
# make the request
channel = grpc.secure_channel(GRPC_HOST, combined_creds)
stub = lightningstub.LightningStub(channel)
# Define a generator that returns an Iterable of SendRequest objects.
def request_generator():
# Initialization code here.
while True:
# Parameters here can be set as arguments to the generator.
request = lnrpc.SendRequest(
dest=<bytes>,
dest_string=<string>,
amt=<int64>,
amt_msat=<int64>,
payment_hash=<bytes>,
payment_hash_string=<string>,
payment_request=<string>,
final_cltv_delta=<int32>,
fee_limit=<FeeLimit>,
outgoing_chan_id=<uint64>,
last_hop_pubkey=<bytes>,
cltv_limit=<uint32>,
dest_custom_records=<DestCustomRecordsEntry>,
allow_self_payment=<bool>,
dest_features=<FeatureBit>,
payment_addr=<bytes>,
)
yield request
# Do things between iterations here.
request_iterable = request_generator()
for response in stub.SendPayment(request_iterable):
print(response)
# {
# "payment_error": <string>,
# "payment_preimage": <bytes>,
# "payment_route": <Route>,
# "payment_hash": <bytes>,
# }
- Javascript
- Python
const fs = require('fs');
const request = require('request');
const REST_HOST = 'localhost:8080'
const MACAROON_PATH = 'LND_DIR/data/chain/bitcoin/regtest/admin.macaroon'
let requestBody = {
dest: <string>, // <bytes> (base64 encoded)
dest_string: <string>, // <string>
amt: <string>, // <int64>
amt_msat: <string>, // <int64>
payment_hash: <string>, // <bytes> (base64 encoded)
payment_hash_string: <string>, // <string>
payment_request: <string>, // <string>
final_cltv_delta: <integer>, // <int32>
fee_limit: <object>, // <FeeLimit>
outgoing_chan_id: <string>, // <uint64>
last_hop_pubkey: <string>, // <bytes> (base64 encoded)
cltv_limit: <integer>, // <uint32>
dest_custom_records: <object>, // <DestCustomRecordsEntry>
allow_self_payment: <boolean>, // <bool>
dest_features: <array>, // <FeatureBit>
payment_addr: <string>, // <bytes> (base64 encoded)
};
let options = {
url: `https://${REST_HOST}/v1/channels/transaction-stream`,
// Work-around for self-signed certificates.
rejectUnauthorized: false,
json: true,
headers: {
'Grpc-Metadata-macaroon': fs.readFileSync(MACAROON_PATH).toString('hex'),
},
form: JSON.stringify(requestBody),
}
request.post(options, function(error, response, body) {
console.log(body);
});
// Console output:
// {
// "payment_error": <string>, // <string>
// "payment_preimage": <string>, // <bytes>
// "payment_route": <object>, // <Route>
// "payment_hash": <string>, // <bytes>
// }
// --------------------------
// Example with websockets:
// --------------------------
const WebSocket = require('ws');
const fs = require('fs');
const REST_HOST = 'localhost:8080'
const MACAROON_PATH = 'LND_DIR/data/chain/bitcoin/regtest/admin.macaroon'
let ws = new WebSocket(`wss://${REST_HOST}/v1/channels/transaction-stream?method=POST`, {
// Work-around for self-signed certificates.
rejectUnauthorized: false,
headers: {
'Grpc-Metadata-Macaroon': fs.readFileSync(MACAROON_PATH).toString('hex'),
},
});
let requestBody = {
dest: <bytes>, // <bytes> (base64 encoded)
dest_string: <string>, // <string>
amt: <int64>, // <int64>
amt_msat: <int64>, // <int64>
payment_hash: <bytes>, // <bytes> (base64 encoded)
payment_hash_string: <string>, // <string>
payment_request: <string>, // <string>
final_cltv_delta: <int32>, // <int32>
fee_limit: <FeeLimit>, // <FeeLimit>
outgoing_chan_id: <uint64>, // <uint64>
last_hop_pubkey: <bytes>, // <bytes> (base64 encoded)
cltv_limit: <uint32>, // <uint32>
dest_custom_records: <DestCustomRecordsEntry>, // <DestCustomRecordsEntry>
allow_self_payment: <bool>, // <bool>
dest_features: <FeatureBit>, // <FeatureBit>
payment_addr: <bytes>, // <bytes> (base64 encoded)
};
ws.on('open', function() {
ws.send(JSON.stringify(requestBody));
});
ws.on('error', function(err) {
console.log('Error: ' + err);
});
ws.on('message', function(body) {
console.log(body);
});
// Console output:
// {
// "payment_error": <string>, // <string>
// "payment_preimage": <string>, // <bytes>
// "payment_route": <object>, // <Route>
// "payment_hash": <string>, // <bytes>
// }
import base64, codecs, json, requests
REST_HOST = 'localhost:8080'
MACAROON_PATH = 'LND_DIR/data/chain/bitcoin/regtest/admin.macaroon'
TLS_PATH = 'LND_DIR/tls.cert'
url = f'https://{REST_HOST}/v1/channels/transaction-stream'
macaroon = codecs.encode(open(MACAROON_PATH, 'rb').read(), 'hex')
headers = {'Grpc-Metadata-macaroon': macaroon}
data = {
'dest': base64.b64encode(<bytes>),
'dest_string': <string>,
'amt': <int64>,
'amt_msat': <int64>,
'payment_hash': base64.b64encode(<bytes>),
'payment_hash_string': <string>,
'payment_request': <string>,
'final_cltv_delta': <int32>,
'fee_limit': <FeeLimit>,
'outgoing_chan_id': <uint64>,
'last_hop_pubkey': base64.b64encode(<bytes>),
'cltv_limit': <uint32>,
'dest_custom_records': <DestCustomRecordsEntry>,
'allow_self_payment': <bool>,
'dest_features': <FeatureBit>,
'payment_addr': base64.b64encode(<bytes>),
}
r = requests.post(url, headers=headers, stream=True, data=json.dumps(data), verify=TLS_PATH)
for raw_response in r.iter_lines():
json_response = json.loads(raw_response)
print(json_response)
# {
# "payment_error": <string>,
# "payment_preimage": <bytes>,
# "payment_route": <Route>,
# "payment_hash": <bytes>,
# }
$ lncli sendpayment --help
NAME:
lncli sendpayment - Send a payment over lightning.
USAGE:
lncli sendpayment [command options] dest amt payment_hash final_cltv_delta pay_addr | --pay_req=R [--pay_addr=H]
CATEGORY:
Payments
DESCRIPTION:
Send a payment over Lightning. One can either specify the full
parameters of the payment, or just use a payment request which encodes
all the payment details.
If payment isn't manually specified, then only a payment request needs
to be passed using the --pay_req argument.
If the payment *is* manually specified, then the following arguments
need to be specified in order to complete the payment:
For invoice with keysend,
--dest=N --amt=A --final_cltv_delta=T --keysend
For invoice without payment address:
--dest=N --amt=A --payment_hash=H --final_cltv_delta=T
For invoice with payment address:
--dest=N --amt=A --payment_hash=H --final_cltv_delta=T --pay_addr=H
OPTIONS:
--pay_req value a zpay32 encoded payment request to fulfill
--fee_limit value maximum fee allowed in satoshis when sending the payment (default: 0)
--fee_limit_percent value percentage of the payment's amount used as the maximum fee allowed when sending the payment (default: 0)
--timeout value the maximum amount of time we should spend trying to fulfill the payment, failing after the timeout has elapsed (default: 1m0s)
--cancelable if set to true, the payment loop can be interrupted by manually canceling the payment context, even before the payment timeout is reached. Note that the payment may still succeed after cancellation, as in-flight attempts can still settle afterwards. Canceling will only prevent further attempts from being sent
--cltv_limit value the maximum time lock that may be used for this payment (default: 0)
--last_hop value pubkey of the last hop (penultimate node in the path) to route through for this payment
--outgoing_chan_id value short channel id of the outgoing channel to use for the first hop of the payment; can be specified multiple times in the same command
--force, -f will skip payment request confirmation
--allow_self_payment allow sending a circular payment to self
--data value attach custom data to the payment. The required format is: <record_id>=<hex_value>,<record_id>=<hex_value>,.. For example: --data 3438382=0a21ff. Custom record ids start from 65536.
--inflight_updates if set, intermediate payment state updates will be displayed. Only valid in combination with --json.
--max_parts value the maximum number of partial payments that may be used (default: 16)
--json if set, payment updates are printed as json messages. Set by default on Windows because table formatting is unsupported.
--max_shard_size_sat value the largest payment split that should be attempted if payment splitting is required to attempt a payment, specified in satoshis (default: 0)
--max_shard_size_msat value the largest payment split that should be attempted if payment splitting is required to attempt a payment, specified in milli-satoshis (default: 0)
--amp if set to true, then AMP will be used to complete the payment
--time_pref value (optional) expresses time preference (range -1 to 1) (default: 0)
--dest value, -d value the compressed identity pubkey of the payment recipient
--amt value, -a value number of satoshis to send (default: 0)
--payment_hash value, -r value the hash to use within the payment's HTLC
--final_cltv_delta value the number of blocks the last hop has to reveal the preimage (default: 0)
--pay_addr value the payment address of the generated invoice
--keysend will generate a pre-image and encode it in the sphinx packet, a dest must be set [experimental]
Messages
lnrpc.SendRequest
Source: lightning.proto
Field | gRPC Type | REST Type | REST Placement |
---|---|---|---|
dest | bytes | string | body |
dest_string deprecated | string | string | body |
amt | int64 | string | body |
amt_msat | int64 | string | body |
payment_hash | bytes | string | body |
payment_hash_string deprecated | string | string | body |
payment_request | string | string | body |
final_cltv_delta | int32 | integer | body |
fee_limit | FeeLimit | object | body |
outgoing_chan_id | uint64 | string | body |
last_hop_pubkey | bytes | string | body |
cltv_limit | uint32 | integer | body |
dest_custom_records | DestCustomRecordsEntry[] | object | body |
allow_self_payment | bool | boolean | body |
dest_features | FeatureBit[] | array | body |
payment_addr | bytes | string | body |
lnrpc.SendResponse
Source: lightning.proto
Field | gRPC Type | REST Type |
---|---|---|
payment_error | string | string |
payment_preimage | bytes | string |
payment_route | Route | object |
payment_hash | bytes | string |
Nested Messages
lnrpc.AMPRecord
Field | gRPC Type | REST Type |
---|---|---|
root_share | bytes | string |
set_id | bytes | string |
child_index | uint32 | integer |
lnrpc.FeeLimit
Field | gRPC Type | REST Type |
---|---|---|
fixed | int64 | string |
fixed_msat | int64 | string |
percent | int64 | string |
lnrpc.Hop
Field | gRPC Type | REST Type |
---|---|---|
chan_id | uint64 | string |
chan_capacity | int64 | string |
amt_to_forward | int64 | string |
fee | int64 | string |
expiry | uint32 | integer |
amt_to_forward_msat | int64 | string |
fee_msat | int64 | string |
pub_key | string | string |
tlv_payload | bool | boolean |
mpp_record | MPPRecord | object |
amp_record | AMPRecord | object |
custom_records | CustomRecordsEntry[] | object |
metadata | bytes | string |
blinding_point | bytes | string |
encrypted_data | bytes | string |
total_amt_msat | uint64 | string |
lnrpc.Hop.CustomRecordsEntry
Field | gRPC Type | REST Type |
---|---|---|
key | uint64 | unknown |
value | bytes | unknown |
lnrpc.MPPRecord
Field | gRPC Type | REST Type |
---|---|---|
payment_addr | bytes | string |
total_amt_msat | int64 | string |
lnrpc.Route
Field | gRPC Type | REST Type |
---|---|---|
total_time_lock | uint32 | integer |
total_fees | int64 | string |
total_amt | int64 | string |
hops | Hop[] | array |
total_fees_msat | int64 | string |
total_amt_msat | int64 | string |
first_hop_amount_msat | int64 | string |
custom_channel_data | bytes | string |
lnrpc.SendRequest.DestCustomRecordsEntry
Field | gRPC Type | REST Type |
---|---|---|
key | uint64 | unknown |
value | bytes | unknown |
Enums
lnrpc.FeatureBit
Name | Number |
---|---|
DATALOSS_PROTECT_REQ | 0 |
DATALOSS_PROTECT_OPT | 1 |
INITIAL_ROUING_SYNC | 3 |
UPFRONT_SHUTDOWN_SCRIPT_REQ | 4 |
UPFRONT_SHUTDOWN_SCRIPT_OPT | 5 |
GOSSIP_QUERIES_REQ | 6 |
GOSSIP_QUERIES_OPT | 7 |
TLV_ONION_REQ | 8 |
TLV_ONION_OPT | 9 |
EXT_GOSSIP_QUERIES_REQ | 10 |
EXT_GOSSIP_QUERIES_OPT | 11 |
STATIC_REMOTE_KEY_REQ | 12 |
STATIC_REMOTE_KEY_OPT | 13 |
PAYMENT_ADDR_REQ | 14 |
PAYMENT_ADDR_OPT | 15 |
MPP_REQ | 16 |
MPP_OPT | 17 |
WUMBO_CHANNELS_REQ | 18 |
WUMBO_CHANNELS_OPT | 19 |
ANCHORS_REQ | 20 |
ANCHORS_OPT | 21 |
ANCHORS_ZERO_FEE_HTLC_REQ | 22 |
ANCHORS_ZERO_FEE_HTLC_OPT | 23 |
ROUTE_BLINDING_REQUIRED | 24 |
ROUTE_BLINDING_OPTIONAL | 25 |
AMP_REQ | 30 |
AMP_OPT | 31 |