Machine-to-machine API

API for machines & AI agents

A small REST surface so an autonomous agent — a robot, a Home Assistant automation, a langgraph node, an n8n flow — can sign itself up, get an API key and start collecting Bitcoin Lightning payments for the hardware it controls. No browser, no human in the loop.

Base URL & auth

https://iotpay.botrift.com is the production base URL. All responses are JSON; all timestamps are ISO 8601 UTC.

Authenticate every request except POST /api/v1/accounts with Authorization: Bearer lib_xxx. Keys are issued by the signup endpoint and returned exactly once — store them in your secrets manager immediately.

CORS is open for browser-based agents. Preflight (OPTIONS) is supported on every endpoint.

30-second quickstart

Three calls: create account, prove the key works, post an event.

1. Create a machine account
curl -X POST https://iotpay.botrift.com/api/v1/accounts \
  -H "Content-Type: application/json" \
  -d '{"label":"my-coffee-bot","lightning_address":"you@getalby.com"}'
2. Get your account info
curl https://iotpay.botrift.com/api/v1/accounts/me \
  -H "Authorization: Bearer lib_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
3. Create an asset
curl -X POST https://iotpay.botrift.com/api/v1/assets \
  -H "Authorization: Bearer lib_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"name":"Coffee machine","price_sats":1500}'
4. Provision the Lightning payment link / QR (first call MUST be POST)
curl -X POST https://iotpay.botrift.com/api/v1/assets/<asset_id>/payment-link \
  -H "Authorization: Bearer lib_xxxxxxxx"
5. Download these docs as PDF
curl -L -o iot-lightning-bridge-api.pdf https://iotpay.botrift.com/api/public/docs.pdf

Endpoints

POST
/api/v1/accounts
public
Create a machine account, returns api_key
POST
/api/v1/auth/exchange
public
Swap an api_key for a GUI session token (login as the bot)
GET
/api/v1/accounts/me
Bearer
Current account info
POST
/api/v1/accounts/me/rotate-key
Bearer
Issue a new key, invalidate the old one
GET
/api/v1/assets
Bearer
List your assets
POST
/api/v1/assets
Bearer
Create an asset (name, price_sats)
GET
/api/v1/assets/{id}
Bearer
Fetch a single asset
POST
/api/v1/assets/{id}/payment-link
Bearer
Provision the LNURL-pay link & QR
GET
/api/v1/assets/{id}/payment-link
Bearer
Fetch the existing LNURL-pay link
GET
/api/v1/assets/{id}/payments
Bearer
List payments for an asset
GET
/api/public/events
Bearer
List recent events for your account
POST
/api/public/events
Bearer
Append an event (paid / action / error / custom)
GET
/api/public/events/{id}
Bearer
Get a single event
GET
/api/public/docs.pdf
public
Download these API docs as a PDF

Asset CRUD, signed outbound webhooks and scoped read-only keys are on the roadmap.

Monitor a bot from the GUI

Accounts provisioned via POST /api/v1/accounts have no email or password — they're identified purely by their api_key. To watch a bot's assets, payments and stats in the dashboard, log in with the API key:

  1. Open /login and switch to the API key tab.
  2. Paste the lib_… key you stored at signup.
  3. The server calls POST /api/v1/auth/exchange behind the scenes and saves a 24h session token.
  4. You land on the same dashboard as an email-signed-up user — Assets, Payments, Settings all work identically.

You can also do the exchange yourself (e.g. for embedded dashboards):

Exchange API key → session token
curl -X POST https://iotpay.botrift.com/api/v1/auth/exchange \
  -H "Content-Type: application/json" \
  -d '{"api_key":"lib_xxxxxxxxxxxxxxxx"}'
# → { "token": "<pb-jwt>", "record": { ... }, "expires_in": 86400 }

The token is a standard PocketBase auth token. Save it under the pb_auth_iot localStorage key, or send it as Authorization: <token> on PocketBase requests. Tokens expire after 24h — re-exchange with the API key to refresh.

Rate limits

60 requests per minute per API key. Exceeding the limit returns 429 with a Retry-After header (seconds).

5 signups per hour per IP on POST /api/v1/accounts. Build your fleet provisioning around this — one key per agent, not one key per request.

Errors

StatusCodeMeaning
400invalid_body / invalid_jsonValidation failed on the request body or query.
401missing_token / invalid_token / invalid_keyNo Authorization header, malformed key, or unknown key.
403asset_not_ownedYou tried to act on a resource that belongs to another account.
404asset_not_foundThe referenced resource does not exist.
409duplicate_eventAn event with the same external_id already exists. Treat as success.
429rate_limitedToo many requests. Inspect Retry-After and back off.
500lookup_failed / backend_unavailableTransient backend error. Retry with exponential backoff.

Every error body is { "error": "code", "message": "..." }. Treat unknown codes the same as a 500.