sesame-sdk
Python SDK for the Sesame human-in-the-loop approval API.
Drop an approval gate in front of any sensitive operation in your backend. Sesame triggers a request that a human approves (via Telegram + push), and your code blocks until the decision lands — or reacts asynchronously via a webhook.
pip install sesame-sdk
Requires Python 3.12+. Runtime deps: httpx, pydantic.
Configuration
The SDK needs one thing — your API key. Create one in the
Sesame dashboard (API Keys), then set
SESAME_API_KEY (or pass api_key=) and you're done; it reaches the hosted
Sesame broker automatically.
from sesame_sdk import Sesame
client = Sesame() # reads SESAME_API_KEY
client = Sesame(api_key="sk_live_...") # ...or pass it explicitly
Self-hosting / local dev — ignore unless you run your own broker
Only if you host Sesame yourself do you need a URL. Override the default
(https://getsesame.dev) via the SESAME_BROKER_URL env var or the base_url=
argument:
client = Sesame(api_key="sk_live_...", base_url="http://localhost:8000")
Gate a function with @require_approval
The wrapped function only runs if a human approves. Denied/expired raises
ApprovalDenied; no decision before timeout raises ApprovalTimeout.
from sesame_sdk import require_approval, ApprovalDenied
@require_approval(
"payments.refund",
summary=lambda amount, **_: f"Refund ${amount/100:.2f} to customer",
timeout=300,
)
def issue_refund(amount: int, customer_id: str) -> None:
stripe.Refund.create(amount=amount, customer=customer_id)
try:
issue_refund(4200, customer_id="cus_123")
except ApprovalDenied:
log.warning("refund rejected by operator")
summary may be a static string or a callable receiving the wrapped function's
arguments. Omit it for a sensible default built from the action and function name.
Pass client=Sesame(...) to use a specific client; otherwise a module-level default
is built lazily from the environment.
Trigger and wait explicitly
from sesame_sdk import Sesame
client = Sesame()
approval = client.approvals.trigger(
action="db.delete",
summary="Delete 1,204 rows from prod.orders",
reason="GDPR erasure request #882",
context={"table": "orders", "rows": 1204},
)
approval.wait(timeout=300) # blocks on the broker's long-poll until decided
if approval.approved:
run_deletion()
else:
print("decision:", approval.status) # "denied" or "expired"
Receive decisions via webhook
When you pass a callback_url, the broker POSTs to it on every terminal decision.
Verify the signature before trusting the body — verify_webhook recomputes the
HMAC-SHA256 over the raw request body and rejects stale timestamps.
Flask
from flask import Flask, request, abort
from sesame_sdk import verify_webhook, WebhookVerificationError
app = Flask(__name__)
WEBHOOK_SECRET = os.environ["SESAME_WEBHOOK_SECRET"]
@app.post("/sesame/webhook")
def sesame_webhook():
try:
payload = verify_webhook(request.headers, request.get_data(), WEBHOOK_SECRET)
except WebhookVerificationError:
abort(400)
# payload: {"approval_id", "action", "status", "decided_at", "requester_label", "dedup_key"?}
handle_decision(payload["approval_id"], payload["status"])
return "", 204
FastAPI
from fastapi import FastAPI, Request, Response, HTTPException
from sesame_sdk import verify_webhook, WebhookVerificationError
app = FastAPI()
@app.post("/sesame/webhook")
async def sesame_webhook(request: Request):
raw = await request.body() # must be the exact bytes the broker signed
try:
payload = verify_webhook(request.headers, raw, WEBHOOK_SECRET)
except WebhookVerificationError:
raise HTTPException(status_code=400, detail="bad signature")
handle_decision(payload["approval_id"], payload["status"])
return Response(status_code=204)
Exceptions
All inherit from ApprovalError:
ApprovalDenied— terminaldenied/expired(carries.approval_id,.status)ApprovalTimeout— no decision before the caller's timeoutSesameAuthError— broker rejected the API key (HTTP 401)NotFoundError— unknown approval id (HTTP 404)WebhookVerificationError— bad/missing signature, stale timestamp, or bad JSON
Notes
This SDK is synchronous for v1. An async client may be added later; until then, run
approval.wait() in a worker thread if you need to avoid blocking an event loop.
Metadata
Release files for sesame-sdk 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sesame_sdk-0.1.2.tar.gz | 8.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sesame_sdk-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 20.0 kB
Release files / sesame_sdk-0.1.2.tar.gz
| Download URL | sesame_sdk-0.1.2.tar.gz |
|---|---|
| Size | 8.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
96e855396f293d97234593692b4d26ec47a2eb01727b4a7291eea637ac26b9ae
|
|
BLAKE2b-256 checksum How to use checksums |
a88c79fd4af3b1044f26902bd42d7a2bb6bcc7c6cd39c4ce310a7fe095084d2a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.1 {"installer":{"name":"uv","version":"0.11.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / sesame_sdk-0.1.2-py3-none-any.whl
| Download URL | sesame_sdk-0.1.2-py3-none-any.whl |
|---|---|
| Size | 11.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
05bce34423acf226aa0eed21fb96ab5debddf695217eaac4f0e7181c5fb8c396
|
|
BLAKE2b-256 checksum How to use checksums |
349d058c4782c11ddbd0b17ab319654c0fb2e60b8cdaa86febe072c040bf6f8a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.1 {"installer":{"name":"uv","version":"0.11.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|