Build with Lauther

Your web app,
in your pocket.

Lauther is the person's pocket, open to software that isn't on their phone. Your server or web app asks one request at a time — someone signs up, an order lands, a refund needs a yes — and each one is answered by the person. One HTTP call from the backend you already have, with no native app to ship.

A token from the app is all a personal project needs — Apps → + → New token. Registering a service, for the day your users should get these too, lives in the console and is a two-minute job.

The whole integration

A webhook to a chat channel tells you. This asks you.

Two calls cover what people reach for first. Everything else is the same shape.

# Someone signed up
curl -X POST https://api.lauther.id/v1/push \
  -H "Authorization: Bearer lpt_…" \
  -d '{"title":"New signup","message":"anna@example.com · plan: free"}'

→ {"ok":true,"id":"…","delivered":1}

# Ask before you refund — and wait for the tap
curl -X POST https://api.lauther.id/v1/approve \
  -H "Authorization: Bearer lpt_…" \
  -d '{"title":"Refund €49 to anna@example.com?",
       "message":"Order 1042 · 3 days old",
       "wait":25, "requireBiometric":true}'

→ {"ok":true,"response":"approve"}
Only a yes is a yes. A refusal comes back deny; a question nobody answered comes back without a response at all, so your code stops. Ask for a fingerprint and the answer records that a person gave it. The token goes in the header; body and URL forms exist for clients that can only paste a string.
If you write JavaScript

A package for you, and one for your agent

Both published, both a token away from working. Node 18 and up.

npm install lauther-client

// Tell someone something
await lauther.push({ title: "Order shipped" });

// Or ask, and wait for the answer
if (await lauther.ask("Deploy v2.4 to production?")) {
  await deploy();
}

→ true only when a person pressed Approve
Only a yes is a yes. A refusal and a silence both come back false, so an unanswered question reads as a stop. Zero dependencies, and the TypeScript types ship inside the package.

Your coding agent can ask before it acts

Add this to Claude Code, Cursor or Windsurf and the agent puts the question on your phone before it deploys, deletes or spends — then waits for your thumb.

// .mcp.json
{"mcpServers": {"lauther": {
  "command": "npx", "args": ["-y", "lauther-mcp"],
  "env": {"LAUTHER_TOKEN": "lpt_…"}
}}}

→ APPROVED after 34s. Confirmed by biometric.
It waits as long as you are away. The API holds a request for 25 seconds; past that the server keeps asking about the same notification, so a ten-minute wait puts one question on your phone rather than one every half minute. Ask for a fingerprint and the answer records that a person gave it.
What you can build

Six endpoints, a lot of ground

Human-in-the-loop for agents

One blocking call puts a real decision in front of a real person and returns their answer to your script. Built for AI agents, deploy pipelines and anything that spends money. POST /v1/approve

Sign-in without a password field

Two endpoints and a QR code. Each user arrives as a per-service alias and a random ID — everything you need to recognise a returning customer. POST /v1/pair/start

Step-up confirmation

Gate the expensive action behind a fingerprint. The response tells you it was confirmed biometrically, so you can log why you trusted it. POST /v1/identity/verify

Conversations, not just alerts

Point a notification at a page on your own site. The tap lands there already signed in, ready to answer with a real keyboard. POST /v1/push {path}

Broadcast to a crowd

Publish once, reach every subscriber, and let them stay anonymous to you. Ideal for a status page or an alert feed. POST /v1/topics/publish

Recognise them next time

Three routes home for a returning user — from the app, by the name they chose for you, or a fresh scan. Build all three and nobody gets stranded. POST /v1/session/claim

Fits what you run

Already speaks your stack

Lauther implements the Pushover message API, so anything that lets you change the server URL works the moment you point it here. Anything with a webhook field works as it is.

curlApprise Uptime KumaHome AssistantGrafana HealthchecksRadarr / SonarrOctoPrint Node-REDn8nZabbix GitHub ActionsJenkinsTrueNAS Proxmoxany webhook
One URL for the awkward cases. Where a tool sends its own fixed payload, POST /v1/hook/lpt_… accepts whatever arrives and makes sense of it — JSON, form-encoded or plain text. Same result, nothing to configure.
Weighing this against Pushover, ntfy or Gotify? There is a side-by-side comparison that names the cases where each of them is the better pick.
Working recipes on GitHub. lauther-examples carries copy-pasteable setups for curl, Python, Node, Home Assistant, Uptime Kuma and GitHub Actions — including a deploy pipeline that waits for your thumb before it ships.
Getting started

Three steps, about a minute

1

Install the app

Sign in with a link sent to your email, and you're in — the address is for sign-in and recovery only.

2

Mint a token

Apps → + → New token gives you an lpt_… string. Revoke or regenerate it any time.

3

Send something

Paste the curl above, or open the Workbench and let it build the request for you.

Running a registered service? The developer console lists your services, rotates a leaked key in one click — pairings and domain verification carry over — and retires a service you are done with.
The bigger picture

What your users get out of it

Every integration you ship lands in an app your users chose for themselves — one inbox, their own names, their own off switch. How it works from their side →