Pause your agent and text a human in one API call, instead of building a webhook server, response page, and SMS infrastructure yourself.
No credit card required.
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_hours": 4,
"timeout_default": "Reject",
}
)
# returns immediately
pause_id = resp.json()["pause_id"]
Works with
Every team building AI agents that need human approval ends up writing the same infrastructure — Twilio setup, webhook handlers, response pages, token auth, state storage, timeout workers. Every time.
# Twilio client, Redis for state, JWT for tokens...
from twilio.rest import Client
import hmac, hashlib, redis, jwt, json
from time import time
client = Client(TWILIO_SID, TWILIO_TOKEN)
r = redis.Redis()
@app.post("/send-approval")
async def send_approval(req):
token = jwt.encode({"id": req.pause_id,
"exp": time() + 14400}, SECRET)
r.setex(f"pause:{token}", 14400,
json.dumps({"id": req.pause_id, "used": False}))
client.messages.create(
body=f"{req.message}\n\nRespond: {BASE_URL}/r/{token}",
from_=TWILIO_FROM, to=req.recipient
)
@app.post("/respond/{token}")
async def handle_response(token, choice):
data = r.get(f"pause:{token}")
if not data: raise HTTPException(400)
pause = json.loads(data)
if pause["used"]: raise HTTPException(410)
db.execute("UPDATE pauses SET status='responded'...")
requests.post(pause["webhook"], json={"choice": choice})
r.delete(f"pause:{token}")
# Plus: response page HTML, timeout jobs, audit log,
# HMAC verification, replay protection, retry logic...
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.
requests.post to a human approving on their phone.
POST, it works.
Your agent calls one endpoint. PausePoint handles delivery, the response page, timeouts, retries, and the audit log.
Your agent sends the recipient, message, and options. PausePoint returns a pause_id immediately. Block-poll or use a webhook — your choice.
POST /v1/pausereturns immediatelyA text arrives with a tap-to-respond link. No app. No login. Works globally. Email and Slack on paid plans.
A mobile-optimized page shows the question and choices. Under 10 seconds from SMS to decision. No technical knowledge needed.
Poll GET /v1/pause/{id} or receive a signed webhook. Every event written to the immutable audit log automatically.
Pure REST. No SDK to install. Drop into any agent codebase in eight lines.
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"
}'
# Then poll for the response, or register a webhook.
curl https://api.pausepoint.dev/v1/pause/$PAUSE_ID \
-H "Authorization: Bearer pp_live_..."
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 to production?",
"options": ["Deploy", "Abort"],
"timeout_default": "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();
// Poll, or register a webhook for the response event.
while (true) {
const r = await fetch(`https://api.pausepoint.dev/v1/pause/${pause_id}`, {
headers: { "Authorization": "Bearer pp_live_..." },
}).then(r => r.json());
if (r.status === "responded") return r.response_choice;
await new Promise(r => setTimeout(r, 5000));
}
package main
import (
"bytes"
"encoding/json"
"net/http"
)
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_...")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
// Decode pause_id from resp.Body, then poll or register webhook.
require "net/http"
require "json"
uri = URI("https://api.pausepoint.dev/v1/pause")
req = Net::HTTP::Post.new(uri,
"Authorization" => "Bearer pp_live_...",
"Content-Type" => "application/json")
req.body = {
recipient: "+1 (312) 847-1928",
channel: "sms",
message: "Deploy build #4712 to production?",
options: ["Deploy", "Abort"],
timeout_default: "Abort",
}.to_json
resp = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
pause_id = JSON.parse(resp.body).fetch("pause_id")
# Then poll GET /v1/pause/:id, or register a webhook.
SMS-first delivery, signed webhooks, immutable audit logs, and a hosted response page — out of the box.
LangChain, LangGraph, CrewAI, AutoGen, n8n, or raw requests.post(). If it can make an HTTP call, it works. No decorator, no import, no framework constraint.
POST https://api.pausepoint.dev/v1/pauseAverage SMS response time is under 3 minutes. Email and Slack available on paid plans. WhatsApp on Enterprise.
Set timeout_default and your agent continues automatically if no one responds. 24h on Free, up to 30 days on Pro.
The human taps a link, sees your question, taps their answer. No login, no app, nothing to build or host on your side.
Every pause, response, timeout, and cancellation recorded with timestamp, actor, and full context. Query, export, and satisfy EU AI Act Article 14 compliance requirements automatically.
Receive pause.responded, pause.timed_out, pause.cancelled events. HMAC-SHA256 signed with replay protection built in.
The PausePoint MCP server lets Claude Code create pause requests, poll for responses, and query audit logs — without writing any HTTP code. Add it to your mcp.json and it's available as a native tool.
create_pause_requestpoll_pause_requestcancel_pause_requestlist_pause_requestsget_audit_log{
"servers": {
"pausepoint": {
"command": "python",
"args": ["mcp_server/server.py"],
"env": {
"PAUSEPOINT_API_KEY": "pp_live_..."
}
}
}
}
"Before proceeding, use PausePoint to ask +1 (312) 847-1928 via SMS whether to approve the $500 transfer. Options: Approve, Reject. Default to Reject after 2 hours."
Four shipped patterns. Four irreversible decisions a human still owns.
"Wire $8,400 to Meridian Supplies?"
The finance agent prepares a transfer. Before any money moves, PausePoint texts the CFO. One tap approves. No response in 4 hours — automatically rejected and logged.
"Send this campaign to 340 contacts?"
The outreach agent drafts and stages a campaign. The founder reviews on their phone and approves before a single message is sent. Brand safety by default.
"Purge 14,000 records from staging?"
The cleanup agent identifies deletion candidates. Before the query runs, it texts the data engineer. Irreversible actions stay reversible until a human says go.
"Sign and submit this contract?"
The contract agent prepares an agreement. Legal reviews the summary on their phone. One tap, and the signing workflow proceeds. Compliance logged automatically.
We were reinventing the Twilio webhook loop on every new agent deployment. PausePoint replaced 400 lines of infrastructure with one API call — in a Thursday afternoon.
Build and test. No credit card.
Start freeProduction agents that need real approvals.
Get startedHigh-volume with Slack and priority support.
Get startedNeed unlimited pauses, WhatsApp, or an SLA? Talk to us about Enterprise →
No. PausePoint handles all SMS delivery infrastructure. You pass a phone number and message — we handle the rest. You never touch Twilio credentials.
Set timeout_default in your pause request (e.g. "Reject") and that option fires automatically when the timeout expires. If no default is set, the pause becomes timed_out — your agent handles it however it wants.
Yes — PausePoint is a pure REST API. requests.post() is all you need. No SDK to install, no decorator, no framework constraint. See the integrations section above for copy-pasteable code.
Each pause generates a unique HMAC-SHA256 signed token encoding the pause ID and expiry timestamp. It is single-use — the moment a human submits, the token is permanently invalidated. API keys are stored as SHA-256 hashes, never in plain text.
Yes. Register a webhook endpoint when you create the pause and receive a signed pause.responded event the instant the human taps their answer. HMAC-SHA256 signature included in every payload. Retry logic is built in.
Not yet — today it's a pure REST API. A Python SDK wrapping the polling loop into a single blocking call is on the roadmap. The REST API will never be deprecated.
Start with PausePoint
Start with 50 free pauses per month. No credit card. No infrastructure to run. First pause in under two minutes.