Give any AI agent a human checkpoint.
One API call pauses your agent, texts a person to approve or reject, and resumes the second they answer. You skip the webhook server, the Twilio account, the response page, and the timeout logic.
One POST in. A human decision out.
Your agent calls a single endpoint. PausePoint owns delivery, the response page, timeouts, retries, and the audit log, so the loop closes without any infrastructure on your side.
Send the pause
POST the recipient, message, and options. A pause_id comes back immediately.
A human gets pinged
An SMS lands with a one-tap link that opens in any phone's browser, no app or login required. Email and Slack on paid plans.
sms · email · slackThey tap a choice
A hosted page shows the question and the options. Under ten seconds from text to decision.
hosted response pageYour agent resumes
Poll the id or take a signed webhook. Every event is written to the immutable audit log.
GET /v1/pause/{id}Weeks of plumbing, or eight lines.
Every team adding human approval rebuilds the same stack: Twilio, webhook handlers, a response page, token auth, state, and timeout workers. That work is already done.
# Twilio, Redis for state, JWT for tokens...
from twilio.rest import Client
import hmac, hashlib, redis, jwt, json
client = Client(TWILIO_SID, TWILIO_TOKEN)
r = redis.Redis()
@app.post("/send-approval")
async def send_approval(req):
token = jwt.encode({"id": req.id,
"exp": time()+14400}, SECRET)
r.setex(f"pause:{token}", 14400, ...)
client.messages.create(
body=f"{req.msg}\n{BASE}/r/{token}",
from_=FROM, to=req.recipient)
@app.post("/respond/{token}")
async def handle(token, choice):
# verify token, check replay, update db,
# fire webhook, render page, timeout jobs,
# HMAC signing, retries... and on, and on.
import requests
resp = requests.post(
"https://api.pausepoint.dev/v1/pause",
headers={"Authorization": "Bearer pp_live_..."},
json={
"recipient": "+1 (312) 847-1928",
"channel": "sms",
"message": "Wire $8,400 to Meridian?",
"options": ["Approve", "Reject"],
"timeout_default": "Reject",
},
)
pause_id = resp.json()["pause_id"]
# PausePoint handles everything else.
Write it in what you already use.
There's no SDK to install and nothing new to learn. If your code can make an HTTP request, it can pause for a human.
curl -X POST https://api.pausepoint.dev/v1/pause \
-H "Authorization: Bearer pp_live_..." \
-H "Content-Type: application/json" \
-d '{
"recipient": "+1 (312) 847-1928",
"channel": "sms",
"message": "Deploy build #4712 to production?",
"options": ["Deploy", "Abort"],
"timeout_default": "Abort"
}'import requests, time
resp = requests.post(
"https://api.pausepoint.dev/v1/pause",
headers={"Authorization": "Bearer pp_live_..."},
json={"recipient": "+1 (312) 847-1928", "channel": "sms",
"message": "Deploy build #4712?", "options": ["Deploy", "Abort"]},
)
pause_id = resp.json()["pause_id"]
while True:
r = requests.get(f"https://api.pausepoint.dev/v1/pause/{pause_id}",
headers={"Authorization": "Bearer pp_live_..."}).json()
if r["status"] == "responded":
decision = r["response_choice"]; break
time.sleep(5)const resp = await fetch("https://api.pausepoint.dev/v1/pause", {
method: "POST",
headers: {
"Authorization": "Bearer pp_live_...",
"Content-Type": "application/json",
},
body: JSON.stringify({
recipient: "+1 (312) 847-1928",
channel: "sms",
message: "Deploy build #4712 to production?",
options: ["Deploy", "Abort"],
timeout_default: "Abort",
}),
});
const { pause_id } = await resp.json();body, _ := json.Marshal(map[string]interface{}{
"recipient": "+1 (312) 847-1928",
"channel": "sms",
"message": "Deploy build #4712 to production?",
"options": []string{"Deploy", "Abort"},
"timeout_default": "Abort",
})
req, _ := http.NewRequest("POST",
"https://api.pausepoint.dev/v1/pause", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer pp_live_...")
resp, _ := http.DefaultClient.Do(req)Everything around the pause, handled.
Delivery, a hosted response page, signed webhooks, and an immutable audit log. None of it is yours to build or run.
Pure REST. No SDK.
LangChain, CrewAI, AutoGen, or a raw requests.post(). If it can make an HTTP call, it works, with no decorator or import to wire in and nothing proprietary to adopt.
SMS-first delivery
A text on the lock screen, no app, no Twilio account on your side.
Signed webhooks
Take pause.responded the instant a human answers. HMAC-SHA256 on every payload, retries built in.
"choice": "Approve",
"X-Signature": sha256=9f2c…
Immutable audit log
Every pause, response, and timeout recorded with timestamp and actor: the record for EU AI Act Article 14.
Hosted response page
The human taps the link, sees the question, taps an answer. Nothing for you to host or style.
Timeout fallbacks
Set timeout_default and the agent continues on its own when nobody answers in time.
Built for decisions you can't undo.
An approval API sits in front of irreversible actions, so every credential, token, and event is handled like it matters.
API keys are kept only as SHA-256 hashes. We can't read yours back, and neither can anyone who reaches the database.
Each link is an HMAC-SHA256 token encoding the pause ID and expiry. It's invalidated the instant a human taps it.
Every webhook carries an HMAC signature with replay protection and automatic retries, so events arrive once and intact.
Append-only logging of every event with timestamp and actor: the compliance record for EU AI Act Article 14.
Every request and notification travels over TLS. Approval payloads aren't retained beyond what the audit log needs.
A separate pp_test_ key runs the full flow without touching live data or quotas.
Start free. Pay when it ships.
Prices in USD. Cancel anytime.
Build and test. No credit card.
Start free- 50 pauses / month
- SMS channel
- 24-hour max timeout
- Audit log access
Production agents that need real approvals.
Get started- 500 pauses / month
- SMS + Email channels
- 7-day max timeout
- Signed webhooks
- Audit log export
High volume, Slack, and priority support.
Get started- 5,000 pauses / month
- SMS + Email + Slack
- 30-day max timeout
- Webhooks + retry logic
- Priority support
Need unlimited pauses, WhatsApp, or an SLA? Talk to us about Enterprise →
Questions, answered.
Still stuck? Email us and we reply within a business day.
Do I need a Twilio account?
No. PausePoint handles all SMS delivery. You pass a phone number and a message; you never touch Twilio credentials.
What happens if nobody responds?
Set timeout_default (e.g. "Reject") and that option fires automatically when the window closes. With no default, the pause becomes timed_out and your agent decides what to do.
Does it work with LangGraph, CrewAI, AutoGen?
Yes. It's a pure REST API, and a single requests.post() is all you need. No SDK, no decorator, no framework constraint.
How are the response links secured?
Each pause generates a unique HMAC-SHA256 token encoding the pause ID and expiry. It's single-use: the moment a human submits, the token is permanently invalidated. API keys are stored only as SHA-256 hashes.
Can I get the decision by webhook instead of polling?
Yes. Register a webhook when you create the pause and receive a signed pause.responded event the instant the human answers. HMAC-SHA256 signature on every payload, retries built in.
Is there a Python SDK?
Not yet. Today it's a pure REST API. A thin SDK wrapping the polling loop into one blocking call is on the roadmap, and the REST API will never be deprecated.
Your agent, with a human in the loop.
50 free pauses a month. No credit card, no infrastructure to run. First call in under five minutes.