Skip to main content

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 — terminal denied/expired (carries .approval_id, .status)
  • ApprovalTimeout — no decision before the caller's timeout
  • SesameAuthError — 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)

Source distribution for sesame-sdk 0.1.2
File Size Uploaded
sesame_sdk-0.1.2.tar.gz 8.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sesame-sdk 0.1.2
File Interpreter ABI Platform
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}

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page