Need help with paypercall?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

129 Stars 8 Forks MIT License 23 Commits 5 Opened issues


Charge for HTTP APIs on a pay-per-call basis with Bitcoin and Lightning :zap:

Services available


Need anything else?

Contributors list


npm release MIT license Pull Requests Welcome IRC

Charge for HTTP APIs on a pay-per-call basis with Bitcoin and Lightning.

Want to require a payment when users take some programmatic action, such as sending an SMS or running imaging processing? That's what

is for.

Available as an express middleware (where a node.js app makes charges directly) or as a reverse proxy (where a reverse proxy requires payment before providing access to an app).

Powered by :zap: Lightning Charge.


$ npm install paypercall

Server Setup

As a middleware

can be used as an express middleware to charge payments directly in your node.js apps. Below is an example app that charges 0.1 USD to send SMS messages:


const pay = require('paypercall')({ chargeUrl: ..., chargeToken: ... })
    , twi = require('twilio')(twilioSid, twilioToken)
    , app = require('express')()

app.use(require('body-parser').urlencoded())'/sms', pay(0.1, 'USD'), (req, res, next) => twi.messages.create({ from: 'paypercall', to:, body: req.body.message }) .then(msg => res.send({ success: true, sid: msg.sid })) .catch(next))

app.listen(4000, _ => console.log('HTTP server running on localhost:4000'))


for a more full-fledged application using

as a middleware.

As a reverse proxy

Alternatively, you can develop your HTTP server with no payments awareness and use

as a reverse proxy to handle payments. Below is an example using a python app:

from flask import Flask, request
from import Client as Twilio

app = Flask(name) twi = Twilio(twilioSid, twilioToken)

@app.route("/sms", methods=['POST']) def sms(): msg = twi.messages.create(from='paypercall', to=request.form['to'], body=request.form['message']) return { 'success': True, 'sid': msg.sid }

Run the python app and the

$ flask run
* Running on http://localhost:4001/

$ paypercall --charge-token mySecretToken --upstream-url http://localhost:4001
--port 4000 --rates-yaml '{ POST /sms: 0.1 USD }' HTTP reverse proxy running on http://localhost:4000, proxying to http://localhost:4001

You will now have the python app running on port 4001 (providing API calls free of charge) and the

reverse proxy running on port 4000 (charging on a per-call basis).

Paying for API calls

Users can access

-enabled API endpoints in three steps:
  1. Send an empty request (no body) to the

    -enabled endpoint to get the BOLT11 payment request and the
    $ curl -i -X POST http://localhost:4000/sms

    HTTP/1.1 402 Payment Required Content-Type: application/vnd.lightning.bolt11 X-Token: lmbdmJeoSQ0ZCB5egtnph.af1eupleFBVuhN2vrbRuDLTlsnnUPYRzDWdL5HtWykY


  2. Make the payment:

    $ lightning-cli pay lnbcrt8925560p1pdfh7n2pp54g5avyupe70l988h30u0hy8agpj2z7qsveu7ejhys97j98rgez0...
  3. Send the request again, this time with the request body and with the

    header echoed back:
    $ curl -i -X POST http://localhost:4000/sms \
      -H 'X-Token: lmbdmJeoSQ0ZCB5egtnph.af1eupleFBVuhN2vrbRuDLTlsnnUPYRzDWdL5HtWykY' \
      -t to=+972-789456123 \
      -d message='I got lightning working and all I got was this sms!'

    HTTP/1.1 200 OK Content-Type: application/json




const pay = require('paypercall')(options)

Returns a new payment middleware factory.

can contain the following fields:
  • chargeUrl
    : Lightning Charge server URL (optional, defaults to
  • chargeToken
    : Lightning Charge access token (required)
  • dbPath
    : Path to sqlite database (optional, defaults to
  • currency
    : Default currency if none is specified (optional, defaults to
  • secret
    : Secret key used for HMAC tokens (optional, generated based on
    by default)
  • invoiceExp
    : How long should invoices be payable for (optional, defaults to 1 hour)
  • accessExp
    : How long should paid access tokens remain valid for (optional, defaults to 1 hour)
const payware = pay(amount[, currency])

Returns an express middleware that requires a payment of

units of
(or the default currency if none provided) before letting requests pass through.

Can be used as following:

const pay = require('paypercall')({ chargeToken: 'myToken', currency: 'EUR' })
    , app = require('express')

// charge requests to a specific route'/sms', pay(0.15), (req, res) => { /* send SMS */ })

// charge all requests to /paid-apis/* app.use('/paid-apis', pay(0.25))

// dynamic pricing (should only be based on the method and path)'/ocr/:type', (req, res, next) => { pay(getPriceForType(req.params.type))(req, res, (err) => { if (err) return next(err) // payment succesfull, run OCR // (the paid invoice is accessible at req.invoice) }) })

Reverse proxy

$ paypercall --help

Charge for HTTP APIs on a pay-per-call basis with Bitcoin and Lightning

Usage $ paypercall [options]

Options -c, --charge-url lightning charge server url [default: http://localhost:9112] -t, --charge-token lightning charge access token [required]

-u, --upstream-url <url>    the upstream server to reverse proxy [required]
-r, --rates-path <path>     path to YAML file mapping from endpoints to rates [default: ./rates.yaml]
-y, --rates-yaml <yaml>     YAML string to use instead of reading from {rates-path}
-x, --currency <name>       default rate currency if none is specified [default: BTC]
-d, --db-path <path>        path to store sqlite database [default: ./payperclick.db]

--invoice-expiry <sec>      how long should invoices be payable for [default: 1 hour]
--access-expiry <sec>       how long should paid access tokens remain valid for [default: 1 hour]
--token-secret <secret>     secret key used for HMAC tokens [default: generated based on {charge-token}]

-p, --port <port>           http server port [default: 4000]
-i, --host <host>           http server listen address [default:]
-e, --node-env <env>        nodejs environment mode [default: production]
-h, --help                  output usage information
-v, --version               output version number

Example $ payperclick -t myAccessToken -u
-y '{ POST /sms: 0.0001 BTC, PUT /page/:id: 0.0002 BTC }'



We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.