Skip to main content

gatewerk

Python SDK for Gatewerk — the open-source human oversight station for AI agents.

Install

pip install gatewerk

Quick Start

from gatewerk import create_client

gw = create_client(
    api_key="gw_key_...",
    url="https://api.gatewerk.com",
)

# Submit a review request
review = gw.reviews.create(
    "email-review",
    payload={"to": "ceo@acme.com", "subject": "Q4 Report", "body": draft},
    callback_url="https://my-agent.com/webhook",
    priority="high",
)
print(review.id)      # gw_rev_...
print(review.status)  # pending

Async Support

from gatewerk import create_async_client

async with create_async_client(api_key="gw_key_...") as gw:
    review = await gw.reviews.create("email-review", payload={...})
    feedback = await gw.feedback.query(template="email-review")

Framework integrations

Framework Install Status
LangGraph pip install gatewerk[langgraph] available
CrewAI pip install gatewerk[crewai] available

LangGraph in 30 seconds:

from gatewerk import create_client
from gatewerk.integrations.langgraph import gatewerk_interrupt

gw = create_client(api_key="gw_key_...")

def gated_node(state):
    decision = gatewerk_interrupt(gw, template="refund_approval", payload={...})
    return {"approved": decision.approved}

See gatewerk/integrations/langgraph/README.md for the full guide, including the polling alternative (await_decision), async variants, and the LangGraph re-execution caveat.

CrewAI in 30 seconds:

from crewai import Agent, Task, Crew
from gatewerk import create_client
from gatewerk.integrations.crewai import GatewerkApprovalTool

gw = create_client(api_key="gw_key_...")
approval_tool = GatewerkApprovalTool(gw, template="refund_approval")

agent = Agent(role="Customer Support", goal="...", tools=[approval_tool])
Crew(agents=[agent], tasks=[Task(description="...", agent=agent, expected_output="...")]).kickoff()

The tool pauses the agent, routes the request to the Gatewerk dashboard, and returns "APPROVED", "REJECTED", or "CHANGES_REQUESTED: ..." once a human decides. See gatewerk/integrations/crewai/README.md for the full guide.

Resources

Resource Methods
gw.reviews create() get() list() decide() retry() update() cancel_request() versions() create_token() list_auto_paginate()
gw.chains create() get() get_for_review()
gw.notes create() get() list() list_auto_paginate() update() delete() pin() unpin() tags()
gw.templates list() get() create() update() delete() stats()
gw.feedback query()
gw.audit query()
gw.stats get()
gw.webhooks verify() deliveries()
gw.key_info() Introspect API key scopes

Typed Responses

All methods return Pydantic models:

from gatewerk import Review, ReviewList, Template, FeedbackList

review = gw.reviews.get("gw_rev_...")
review.id              # str
review.status          # str
review.payload         # dict[str, Any]
review.current_version # int
review.auto_approved   # bool | None

Auto-Pagination

# Iterate all reviews without managing offsets
for review in gw.reviews.list_auto_paginate(status="pending"):
    print(review.id)

# Async
async for review in gw.reviews.list_auto_paginate(status="pending"):
    print(review.id)

Retry & Resilience

The SDK automatically retries on transient errors (429, 500, 502, 503, 504) with exponential backoff and jitter. Rate limit Retry-After headers are respected.

# Customize retry behavior
gw = create_client(
    api_key="gw_key_...",
    max_retries=5,   # default: 2, set 0 to disable
    timeout=60.0,    # default: 30s
)

Error Handling

from gatewerk import (
    GatewerkError,        # Base — all errors
    InvalidRequestError,  # 400
    AuthenticationError,  # 401
    ForbiddenError,       # 403
    NotFoundError,        # 404
    ConflictError,        # 409
    RateLimitError,       # 429 (includes .retry_after)
)

try:
    review = gw.reviews.get("gw_rev_nonexistent")
except NotFoundError as e:
    print(e.message)      # "Review not found"
    print(e.status_code)  # 404
    print(e.code)         # "review_not_found"
except RateLimitError as e:
    print(e.retry_after)  # seconds until retry

Webhook Verification

Every delivery carries two signature headers. Verify either depending on whether you need replay protection.

v1 (authenticity only, no replay protection)

The SDK's gw.webhooks.verify() helper accepts the v1 X-Webhook-Signature header:

# In your Flask/FastAPI webhook handler
payload = gw.webhooks.verify(
    raw_body=request.body,
    signature_header=request.headers["X-Webhook-Signature"],
    secret="whsec_...",
)
# payload is a trusted dict: {"event": "review.decided", ...}

v2 (replay-safe; recommended for new integrations)

The X-Webhook-Signature-V2 header carries t=<unix-seconds>,v1=<hex> where hex = HMAC(f"{t}.{body}", secret). Parse, enforce freshness, then constant-time compare. No SDK helper yet — follow the manual pattern:

import hmac
import hashlib
import time

def verify_v2(raw_body: bytes, header: str, secret: str, tolerance_seconds: int = 300) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    ts = int(parts["t"])
    received_hex = parts["v1"]

    # Freshness: reject replays outside the tolerance window.
    if abs(time.time() - ts) > tolerance_seconds:
        return False

    expected_hex = hmac.new(
        secret.encode(),
        f"{ts}.{raw_body.decode()}".encode(),
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(expected_hex, received_hex)

assert verify_v2(
    request.body,
    request.headers["X-Webhook-Signature-V2"],
    "whsec_...",
)

Receivers should also dedup on X-Webhook-Id (stable across retries) to survive the legitimate retry flow. A v2-verified payload MAY still be a legitimate retry; the header id is the idempotency key.

Logging

The SDK logs via Python's standard logging module under the gatewerk logger:

import logging
logging.getLogger("gatewerk").setLevel(logging.DEBUG)

Environment Variables

Variable Description
GATEWERK_API_KEY API key (fallback if not passed to create_client)
GATEWERK_URL API URL (default: http://localhost:3100)

License

Apache-2.0

Metadata

Release files for gatewerk 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for gatewerk 0.1.1
File Size Uploaded
gatewerk-0.1.1.tar.gz 47.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for gatewerk 0.1.1
File Interpreter ABI Platform
gatewerk-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 109.2 kB

Release files / gatewerk-0.1.1.tar.gz

Download URL gatewerk-0.1.1.tar.gz
Size 47.1 kB
Tags Source
SHA-256 checksum
How to use checksums
0dca12c7bddceb390298891980ee9d34c69a699cc1fea5ed3fe982963486b18f
BLAKE2b-256 checksum
How to use checksums
5823ec0617c4bbe84260845e7c39e80361c1cddd414f3cdbb95afe19b001a1af
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 18, 2026.

Transparency log

Release files / gatewerk-0.1.1-py3-none-any.whl

Download URL gatewerk-0.1.1-py3-none-any.whl
Size 62.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
262de9bb3a0c6a0e985fa133c4bf0bc9e6186fc9e9a07abe7317c331dc2e2c50
BLAKE2b-256 checksum
How to use checksums
be45b7213ec54808d1aff2ef03dc9c8944441f12644f02b6f1e63f5b394f78ab
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 18, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

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