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)
--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 (default: 0)
--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 | string | string | body |
amt | int64 | string | body |
amt_msat | int64 | string | body |
payment_hash | bytes | string | body |
payment_hash_string | 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.FeeLimit
Field | gRPC Type | REST Type |
---|---|---|
fixed | int64 | string |
fixed_msat | int64 | string |
percent | int64 | string |
lnrpc.SendRequest.DestCustomRecordsEntry
Field | gRPC Type | REST Type |
---|---|---|
key | uint64 | unknown |
value | bytes | unknown |
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 |
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 |
lnrpc.MPPRecord
Field | gRPC Type | REST Type |
---|---|---|
payment_addr | bytes | string |
total_amt_msat | int64 | string |
lnrpc.AMPRecord
Field | gRPC Type | REST Type |
---|---|---|
root_share | bytes | string |
set_id | bytes | string |
child_index | uint32 | integer |
lnrpc.Hop.CustomRecordsEntry
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 |
AMP_REQ | 30 |
AMP_OPT | 31 |