Human-in-the-loop API

Human approval for agents that act.

AskHuman pauses irreversible agent actions for a human Approve or Deny — magic link email, then a clean Resolution your agent can poll.

Live API at https://api.ask-human.dev

Approval loop · demo
Finance agent · treasury

Agent ready to wire $12,400 to Northwind Supplies (new payee).

Amount$12,400.00 USD
PayeeNorthwind Supplies
RiskNew vendor · first wire
POST /requests
{
  "summary": "Wire $12,400 to Northwind Supplies?",
  "payload": {
    "amount": 12400,
    "vendor": "Northwind Supplies",
    "new_payee": true
  },
  "principal": {
    "connector": "email",
    "contact": "cfo@acme.co"
  },
  "expires_in_seconds": 600
}
Creating request…

Magic link · no login

Wire $12,400 to Northwind Supplies?

  • Amount $12,400.00
  • Payee Northwind Supplies
  • Flag New payee
  • Expires in 9:42
GET /requests/:id
—
{
  "id": "req_nw_12400",
  "status": "pending",
  "decision": null
}

Agent polls until a terminal Decision arrives.

How it works

Four nouns. One loop.

AskHuman routes gated intent to a human and returns a terminal Decision your agent can trust.

  1. 01

    Request

    Gated intent waiting on a human. One Request, opaque payload, idempotent create.

  2. 02

    Notification

    Reach the principal with a CTA — email first, SMS second. Magic link, no account.

  3. 03

    Decision

    Approve, Deny, or Expire. Humans decide; the timer Expires if nobody acts.

  4. 04

    Resolution

    Decision delivered to the caller via poll, optional webhook. Retryable.

Use cases

Where agents need a human

Gate money movement, write tools, and outbound that shouldn’t auto-run.

Payments & transfers

Agent prepares a payout. Human Approves before money moves.

Write tools

Gate delete, deploy, purchase, or any tool you mark consequential — same Request → Notification → Decision → Resolution loop.

Customer-facing actions

Agent is about to email, refund, or change an account. Human confirms before it ships.

Quickstart for humans

Email arrives. You decide. Done.

No AskHuman account on the decide path. Open the magic link from askhuman@agentmail.to, Approve or Deny, and close the tab. If the timer hits first, the Request Expires — same Resolution path for the agent.

  • Magic-link token only — no login, no Edit UI in v1
  • Approve or Deny; Expire is the system outcome
  • Default window: 10 minutes (overridable per Request)

Quickstart for agents

Register. Get a key. POST a Request.

POST /clients is public. After a human Approves registration, poll GET /clients/:id for a one-time ask_live_… key. Then create Requests with Authorization: Bearer + Idempotency-Key. The magic link lives only in the Notification.

1 · Register client curl
curl -sS -X POST https://api.ask-human.dev/clients \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "my-agent",
    "principal": { "connector": "email", "contact": "you@example.com" }
  }'

# Human Approves the registration email, then:
# curl -sS https://api.ask-human.dev/clients/<client-id>
# → api_key shown once
2 · Create Request (Bearer) curl
curl -sS -X POST https://api.ask-human.dev/requests \
  -H 'Authorization: Bearer ask_live_…' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: demo-001' \
  -d '{
    "summary": "Wire $12,400 to Northwind Supplies?",
    "payload": { "amount": 12400, "vendor": "Northwind Supplies" },
    "principal": { "connector": "email", "contact": "cfo@acme.co" },
    "expires_in_seconds": 600
  }'
3 · Resolve (poll) curl
curl -sS https://api.ask-human.dev/requests/<request-id> \
  -H 'Authorization: Bearer ask_live_…'

# When terminal, response includes Decision:
# approve | deny | expire
# Optional: set callback_url on create for a webhook.

Prefer trying it live? Open the production API · base URL constant for links only; the homepage demo runs entirely in your browser.

API peek

Small surface. Clear contracts.

POST /clients

Register a client (public). Human Approves → one-time ask_live_… key via GET /clients/:id.

POST /requests

Create a Request. Requires Bearer + Idempotency-Key. Returns 201 (or 200 on replay).

GET /requests/:id

Poll until Decision is terminal. Same Bearer client that created it.

GET /a/:token

Human decide page — Approve / Deny. Token ≠ request id. No Bearer.

POST /clients/:id/revoke

Revoke your own key (Bearer of that client).

Payload is opaque JSON. AskHuman does not interpret your vertical logic. Connectors in v1: email, SMS. Pass principal on each Request — no saved profiles.

Ship agents. Gate the consequential step.

Register a client against the live API, or replay the demo above offline.

curl -sS -X POST https://api.ask-human.dev/clients \
  -H 'Content-Type: application/json' \
  -d '{"name":"my-agent","principal":{"connector":"email","contact":"you@example.com"}}'