Skip to main content

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 client reads credentials from the environment, or you can pass them explicitly:

Env var Default Purpose
SESAME_API_KEY (required) sk_live_... API key
SESAME_BROKER_URL http://localhost:8000 Broker base URL
from sesame_sdk import Sesame

client = Sesame()                                  # from env
client = Sesame(api_key="sk_live_...", base_url="https://broker.example.com")

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sesame_sdk-0.1.0.tar.gz (8.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sesame_sdk-0.1.0-py3-none-any.whl (11.0 kB view details)

Uploaded Python 3

File details

Details for the file sesame_sdk-0.1.0.tar.gz.

File metadata

  • Download URL: sesame_sdk-0.1.0.tar.gz
  • Upload date:
  • Size: 8.6 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

Hashes for sesame_sdk-0.1.0.tar.gz
Algorithm Hash digest
SHA256 9f97e4a059d15656679a30a834b5d4934a9268894d53a03d5b718456242076ad
MD5 465dd204eeb4e2e21ffd8e72b1ebcff3
BLAKE2b-256 dcd6dcf89f0e5f53cf03ee01a96a7aec325721ba5d9e5dedc8f4109c94e99abc

See more details on using hashes here.

File details

Details for the file sesame_sdk-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: sesame_sdk-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 11.0 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

Hashes for sesame_sdk-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 04e635ba0bb5a235c10ae03a39d73adb5896e3ec7e8946ffa7dc515e7dda2b12
MD5 247006a2f4ce51c24554b129153f0731
BLAKE2b-256 44fc263c8ff2630b74e0dfcbbd59b73d65eb4e9149f5a92f85762bbae15e5a47

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page