Python SDK for the Sesame human-in-the-loop approval API
Project description
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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sesame_sdk-0.1.2.tar.gz.
File metadata
- Download URL: sesame_sdk-0.1.2.tar.gz
- Upload date:
- Size: 8.8 kB
- Tags: Source
- Uploaded using 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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
96e855396f293d97234593692b4d26ec47a2eb01727b4a7291eea637ac26b9ae
|
|
| MD5 |
7b7bd81fbdd5f1225ce5db01b71332ac
|
|
| BLAKE2b-256 |
a88c79fd4af3b1044f26902bd42d7a2bb6bcc7c6cd39c4ce310a7fe095084d2a
|
File details
Details for the file sesame_sdk-0.1.2-py3-none-any.whl.
File metadata
- Download URL: sesame_sdk-0.1.2-py3-none-any.whl
- Upload date:
- Size: 11.2 kB
- Tags: Python 3
- Uploaded using 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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
05bce34423acf226aa0eed21fb96ab5debddf695217eaac4f0e7181c5fb8c396
|
|
| MD5 |
13db41742cb754cef4150767aef52b68
|
|
| BLAKE2b-256 |
349d058c4782c11ddbd0b17ab319654c0fb2e60b8cdaa86febe072c040bf6f8a
|