Human-in-the-loop, as a primitive

Your agent stops.
A person decides.
Your agent continues.

Every serious autonomous workflow eventually reaches something it shouldn't do alone. One API call sends that decision to a real person by email or Telegram, they tap a button on a page that needs no account, and your agent picks up the answer from a poll it never pays for.

2 credits per deliveryNo subscription — pay in Ounie creditsPolling is free
AGENTAWAITING HUMANAPPROVEDApproveRejectHUMAN

One approval, start to finish

The gap

Agents can call almost anything. Not a person.

Ask and hope

The agent writes “please confirm” into a log nobody reads, then proceeds anyway.

Stop and stay stopped

The run halts on an exception and waits for someone to notice it died.

Build it yourself

A webhook, a queue, a token scheme, a page, a bot, and an expiry job — for one button.

Handoff is the fourth option, and it is one call.

Channels

Reach them where they already are

Same call, same answer shape, same price. Pick the one the person you need actually reads.

2 cr

Email

Reaches anyone, anywhere, with no setup on their side.

The message arrives with a single button. Works on a laptop, a phone lock screen, and the client your CFO refuses to change.

Any address
2 cr

Telegram

For the on-call person who answers in seconds, not hours.

Delivered to a chat with a Review button. One precondition, and it is Telegram's, not ours: the person must have messaged the bot once, because a bot can never open a conversation.

Chat id or @username

No SMS, and no SMS card. There is no SMS credential on this deployment, so the rail does not exist — and a documented endpoint that returns 404 costs an autonomous caller more than a missing one ever would. When a provider lands, it will appear here and in /api/pricing at the same moment.

The approval loop

A closed circuit with a person inside it

Five stops, one of which is a human being. Everything else is infrastructure you don't have to write.

YOUR CALLA PERSONONE TAPANSWERTHE THINGYOU CAN'T UNDO
  1. 01
    Your agent calls
    POST /api/handoff with the question and who to ask.
  2. 02
    A human gets it
    Email or Telegram, with a one-time link. No account needed.
  3. 03
    They decide
    One tap on a hosted page built for a phone.
  4. 04
    You poll, free
    GET the request until status flips to answered.
  5. 05
    Your agent resumes
    With a real answer, and a record of who gave it.
For developers & AI agents

Four ways in. One answer out.

Handoff is an agent tool first. Whatever is driving — a script, Claude, the Ounie AI Team, or a wallet with no account at all — the shape is the same: one call, a free poll, a human's answer.

REST

curl -X POST https://handoff.ounie.com/api/handoff \
  -H "Authorization: Bearer hnd_live_…" \
  -d '{"channel":"email","to":"lead@acme.com",
       "subject":"Refund $840 to order 1183?",
       "message":"Customer says it arrived broken.",
       "choices":["Approve refund","Ask for photos","Deny"]}'

Returns a request id and a poll_url. Poll it as often as you like — reads are free.

MCP

https://handoff.ounie.com/api/mcp
Authorization: Bearer hnd_live_…

request_approval · notify_human · wait_for_answer
get_handoff · list_handoffs · cancel_handoff

wait_for_answer blocks until the human replies, so an agent never has to hand-roll a polling loop around its own guardrail. Hosts that can't set headers — the Ounie AI Team among them — pass ?api_key= on the URL.

x402

POST /api/x402/handoff        → 402 + terms
POST /api/x402/handoff        → sign, retry
  X-Payment: <signed>         → delivered

No account, no key: pay in USDC on Base per call. The poll URL that comes back is free and works without any credential but the one in it. x402 docs.

Credits, refused not overdrawn

402 insufficient_credits
{ "required_credits": 2,
  "balance_credits": 0,
  "buy_credits_url": "https://ounie.com/…" }

Every key spends only its own owner's Ounie wallet, and the reserve happens before the send — so a runaway loop gets a clean 402, never a surprise bill. Mint keys at Dashboard → API keys.

Credit math

You pay for the send. Nothing else.

Billed once
2credits

per message actually delivered to a person — 2 on email, 2 on Telegram.

RESERVEDELIVERSETTLE

If the provider refuses the message while you wait — a blocked bot, an unreachable chat, an address the mail API rejects — the whole reserve goes back to the pool it came from. An email that is accepted and bounces later is asynchronous and invisible to the call, so that one does bill; it expires unanswered, which your agent must read as a no.

Free forever

Everything after the send costs nothing

An agent shouldn't have to ration the checking-back. Reading a result you already paid to create is not a second product.

  • Polling for the answer, as often as you like
  • The human's decision page
  • Reading the answer back
  • Listing your history
  • Withdrawing a request nobody answered
GET /api/handoff/{id}→ 0 credits
Questions

The things you'd ask before wiring this in

Does the person answering need an Ounie account?
No. That is the point. They get a link, they see a page, they tap a button. No sign-in, no app, no cookie — the token in the URL is their entire credential, and it works once.
What stops an agent from approving its own request?
The decision link is never returned to a Bearer key, an MCP host, or an x402 payer — only to a request made with a signed-in browser session, where a person is already at the keyboard. An autonomous workflow that could open its own approval page would not be asking anyone anything.
What happens if nobody answers?
The request expires on the deadline you set (five minutes to thirty days, one day by default). Your poll returns status expired, the link stops working, and nothing was approved. Silence is never read as consent.
Can I cancel a request after sending it?
Yes, and it costs nothing. The person sees a calm 'this was withdrawn' page instead of a live button. The message that already went out stays gone — we cannot un-send an email — but the decision it offered is dead.
How often can I poll?
As often as you want. Polling reads a result you already paid to create, so it is free forever. Over MCP, wait_for_answer holds the connection open and does the waiting for you.
What if the send fails?
If the provider refuses it while you wait — a blocked Telegram bot, an unreachable chat, an address the mail API rejects — the whole reserve goes back to the pool it came from and the call returns a 502 saying so.
And if an email is accepted but bounces later?
That one is not refunded, and it would be dishonest to say otherwise. Email delivery is asynchronous: the mail provider accepts the message, we charge for the handoff, and a hard bounce arrives minutes later out of band where the API call can no longer see it. What your agent still gets is a definite outcome — nobody answers, so the request expires and reports as expired, which your workflow must treat as a no.
Why is there no SMS option?
Because there is no SMS provider credential on this deployment. Shipping the field and letting the call 404 would cost an autonomous caller far more than the missing feature does. When a provider lands, it appears on this page and in /api/pricing the same day.
Is an approval here legally binding?
No. Treat it as an operational record of who chose what and when — useful for an audit trail, not a substitute for a signature. If you need a qualified e-signature, use a product built for that.
Do I need a subscription?
No. Handoff bills per delivered message in Ounie credits — the same wallet every Ounie app draws. There are no plans, no seats, and no minimums.

Give your agent a way to ask.

Two credits, one message, one answer you can point at afterwards. Sign in with the Ounie account you already have.