Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/ElementsProject/paypercall

Charge for HTTP APIs on a pay-per-call basis with Bitcoin and Lightning :zap:
https://github.com/ElementsProject/paypercall

apis bitcoin lightning lightning-charge micropayments nanopayments pay-per-call

Last synced: 2 months ago
JSON representation

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

Awesome Lists containing this project

README

        

# paypercall

[![npm release](https://img.shields.io/npm/v/paypercall.svg)](https://www.npmjs.com/package/paypercall)
[![MIT license](https://img.shields.io/github/license/shesek/paypercall.svg)](https://github.com/shesek/paypercall/blob/master/LICENSE)
[![Pull Requests Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com)
[![IRC](https://img.shields.io/badge/chat-on%20freenode-brightgreen.svg)](https://webchat.freenode.net/?channels=lightning-charge)

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 `paypercall` 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](https://github.com/ElementsProject/lightning-charge).

## Install

```bash
$ npm install paypercall
```

## Server Setup

### As a middleware

`paypercall` 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:

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

app.use(require('body-parser').urlencoded())

app.post('/sms', pay(0.1, 'USD'), (req, res, next) =>
twi.messages.create({ from: 'paypercall', to: req.body.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'))
```

See [`ifpaytt`](https://github.com/shesek/ifpaytt) for a more full-fledged application using `paypercall` as a middleware.

### As a reverse proxy

Alternatively, you can develop your HTTP server with no payments awareness
and use `paypercall` as a reverse proxy to handle payments.
Below is an example using a python app:

#### app.py
```python
from flask import Flask, request
from twilio.rest 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 }

@app.run(Port=4001)
```

Run the python app and the `paypercall` proxy:

```bash
$ FLASK_APP=app.py 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 `paypercall` reverse proxy running on port 4000 (charging on a per-call basis).

## Paying for API calls

Users can access `paypercall`-enabled API endpoints in three steps:

1. Send an empty request (no body) to the `paypercall`-enabled endpoint to get the BOLT11 payment request and the `X-Token` header:

```bash
$ curl -i -X POST http://localhost:4000/sms

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

lnbcrt8925560p1pdfh7n2pp54g5avyupe70l988h30u0hy8agpj2z7qsveu7ejhys97j98rgez0...
```

2. Make the payment:

```bash
$ lightning-cli pay lnbcrt8925560p1pdfh7n2pp54g5avyupe70l988h30u0hy8agpj2z7qsveu7ejhys97j98rgez0...
```

3. Send the request again, this time with the request body and with the `X-Token` header echoed back:

```bash
$ 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

{"success":true,"sid":"SMf34fe622a8fe7565fc15be3ce8bc437e"}
```

## Documentation

### Middleware

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

Returns a new payment middleware factory. `options` can contain the following fields:

- `chargeUrl`: Lightning Charge server URL (optional, defaults to `http://localhost:9112`)
- `chargeToken`: Lightning Charge access token (**required**)
- `dbPath`: Path to sqlite database (optional, defaults to `./paypercall.db`)
- `currency`: Default currency if none is specified (optional, defaults to `BTC`)
- `secret`: Secret key used for HMAC tokens (optional, generated based on `chargeToken` 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)

```js
const payware = pay(amount[, currency])
```

Returns an express middleware that requires a payment of `amount` units of `currency`
(or the default currency if none provided) before letting requests pass through.

Can be used as following:

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

// charge requests to a specific route
app.post('/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)
app.post('/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

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

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

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

Example
$ payperclick -t myAccessToken -u http://upstream-server.com/ \
-y '{ POST /sms: 0.0001 BTC, PUT /page/:id: 0.0002 BTC }'
```

## License
MIT