Skip to main content

FiGuard Python SDK — pre-flight spend authorization for AI agents

Project description

FiGuard Python SDK

PyPI version Python License

Pre-flight spend authorization for AI agents. Stop your agent from overspending before it happens.

Install

# Core (sync client only)
pip install figuard

# With framework integrations
pip install figuard[langchain]      # LangChain + LangGraph
pip install figuard[crewai]         # CrewAI
pip install figuard[openai]         # OpenAI function calling
pip install figuard[openai-agents]  # OpenAI Agents SDK
pip install figuard[anthropic]      # Anthropic tool_use
pip install figuard[async]          # AsyncFiGuardClient (aiohttp)
pip install figuard[all]            # everything above

Requires Python 3.9+.

Quickstart

from figuard import FiGuardClient, FiGuardDeniedException

client = FiGuardClient(api_key="ab_live_...")

# 1. Create a budget for your user's session
budget = client.create_budget(
    user_id="user_123",
    total_limit=500.00,
    expires_at="2024-12-31T23:59:59Z",
)

# 2. Pre-authorize every spend before it happens
try:
    result = client.authorize(
        session_token=budget.primary_token.session_token,
        agent_id="agent_flight_booker",
        action_type="PURCHASE",
        description="NYC to LAX flight",
        requested_quantity=299.00,
        idempotency_key="txn-abc-001",  # required — use a stable unique key
    ).raise_if_denied()

    # 3. Execute the real transaction, then confirm
    external_tx_id = payment_processor.charge(299.00)
    client.confirm_event(result.event_id, confirmed_quantity=299.00,
                         external_transaction_id=external_tx_id)

except FiGuardDeniedException as e:
    print(f"Spend denied: {e.denial_reason}")
    # e.g. INSUFFICIENT_FUNDS, BUDGET_PAUSED, ANOMALY_DETECTED

Async (LangChain / CrewAI / OpenAI Agents)

import asyncio
from figuard import AsyncFiGuardClient

async def run_agent():
    async with AsyncFiGuardClient(api_key="ab_live_...") as client:
        budget = await client.create_budget(
            user_id="user_123",
            total_limit=500.00,
            expires_at="2024-12-31T23:59:59Z",
        )

        result = await client.authorize(
            session_token=budget.primary_token.session_token,
            agent_id="langchain_agent",
            action_type="PURCHASE",
            description="Hotel booking",
            requested_quantity=189.00,
            idempotency_key="hotel-booking-001",
        )

        if result.is_authorized:
            await client.confirm_event(result.event_id, confirmed_quantity=189.00)

Allocation-based budgets

Allocations let you ring-fence spend by category and enforce item-type rules:

budget = client.create_budget(
    user_id="user_123",
    total_limit=500.00,
    expires_at="2024-12-31T23:59:59Z",
    allocations=[
        {
            "category": "flights",
            "allowedCategories": ["flight", "airline"],
            "limit": 300.00,
            "enforcementMode": "STRICT",
            "forbiddenItemTypes": ["gift_card", "upgrade"],
        },
        {
            "category": "hotels",
            "allowedCategories": ["hotel", "accommodation"],
            "limit": 200.00,
            "enforcementMode": "CATEGORY_CONSTRAINED",
        },
    ],
)

# claimedCategory must match one of allowedCategories
result = client.authorize(
    session_token=budget.primary_token.session_token,
    agent_id="travel_agent",
    action_type="PURCHASE",
    description="Flight to NYC",
    requested_quantity=250.00,
    idempotency_key="flight-nyc-001",
    claimed_category="flight",
    claimed_item_type="economy_ticket",
)

Payment lifecycle

# Authorize reserves funds — money has not moved yet
result = client.authorize(...).raise_if_denied()

# Confirm when payment succeeds — finalizes the spend
client.confirm_event(result.event_id, confirmed_quantity=249.00)

# Fail when the payment processor declines — releases the reservation
client.fail_event(result.event_id, reason="PAYMENT_DECLINED")

# Void if the action is cancelled before payment
client.void_event(result.event_id, reason="USER_CANCELLED")

Anomaly detection

Enable per-budget anomaly detection to auto-pause budgets when a single request is statistically unusual:

budget = client.create_budget(
    user_id="user_123",
    total_limit=2000.00,
    expires_at="2024-12-31T23:59:59Z",
    anomaly_detection_enabled=True,
    # optional: dedicated URL for anomaly alerts
    # anomaly_alert_webhook_url="https://your-service.com/alerts",
)

When a request exceeds mean × multiplier (default 3×) and at least 5 prior transactions exist, the budget is auto-paused and an ANOMALY_DETECTED webhook fires. Resume after review:

budget = client.resume_budget(
    budget_id,
    override_reason="Reviewed — legitimate bulk purchase",
    override_by="ops-team",
)

Error handling

from figuard import (
    FiGuardDeniedException,   # decision == DENIED (not an HTTP error)
    FiGuardApiError,          # 4xx / 5xx from the API
    FiGuardConnectionError,   # network failure after all retries
)

try:
    result = client.authorize(...).raise_if_denied()
except FiGuardDeniedException as e:
    print(e.denial_reason)    # e.g. "INSUFFICIENT_FUNDS"
    print(e.denial_message)   # human-readable explanation
    # if denial_reason == "ENTITY_ALREADY_AUTHORIZED":
    #   e.original_event_id   # UUID of the existing event
except FiGuardApiError as e:
    print(e.status_code, e.message)
except FiGuardConnectionError as e:
    print("Network failure:", e)

The SDK automatically retries 5xx responses up to 3 times with exponential backoff (1s, 2s, 4s). 4xx errors are never retried.

Ledger and reporting

# Paginated spend history
page = client.get_ledger(budget_id, page=0, size=20, decision="CONFIRMED")
for event in page.events:
    print(event.id, event.decision, event.confirmed_quantity)

# Causal spend tree (which agent triggered which spend)
tree = client.get_spend_tree(budget_id)
for root in tree.roots:
    print(root.event.agent_id, len(root.children), "child events")

Configuration

client = FiGuardClient(
    api_key="ab_live_...",
    base_url="https://api.figuard.io",  # override for self-hosted
    timeout=30,                          # per-request timeout in seconds
)

Security notes

  • The raw session_token is returned once on create_budget() and never again. Store it securely — treat it like a password.
  • The SDK logs only the first 8 characters of the session token. The full token never appears in logs.
  • idempotency_key is required on every authorize() call. Use a stable unique key per logical spend intent so retries are safe.

Framework integrations

Each integration is an optional extra. Install only what you need.

LangChain / LangGraph

pip install figuard[langchain]
from figuard.integrations.langchain import FiGuardCallbackHandler, FiGuardToolGuard

# Option A — callback handler: guards every tool in an AgentExecutor
executor = AgentExecutor(
    agent=agent,
    tools=tools,
    handle_tool_error=True,   # required — sends denial to the LLM
    callbacks=[FiGuardCallbackHandler(
        client=client,
        session_token=budget.primary_token.session_token,
        tool_category_map={"book_flight": "flight", "book_hotel": "hotel"},
        ignore_tools={"search_web"},   # skip authorization for read-only tools
    )],
)

# Option B — tool guard: wraps a single tool in-place, hard enforcement
FiGuardToolGuard(
    tool=book_flight_tool,
    client=client,
    session_token=budget.primary_token.session_token,
    category="flight",
    amount_key="price",
)

FiGuardCallbackHandler raises ToolException on denial — the LLM receives the denial reason and can try an alternative. FiGuardToolGuard patches tool._run directly so the tool never runs regardless of AgentExecutor configuration.

CrewAI

pip install figuard[crewai]
from figuard.integrations.crewai import FiGuardCrewGuard

FiGuardCrewGuard(
    tool=book_flight_tool,
    client=client,
    session_token=budget.primary_token.session_token,
    category="flight",
    amount_key="price",
)
travel_agent = Agent(role="Travel Coordinator", tools=[book_flight_tool])

OpenAI Agents SDK

pip install figuard[openai-agents]
from agents import function_tool
from figuard.integrations.openai_agents import guarded_function_tool

@function_tool
@guarded_function_tool(
    client=client,
    session_token=budget.primary_token.session_token,
    category="flight",
    amount_key="price",
)
def book_flight(destination: str, price: float) -> str:
    """Book a flight to the specified destination."""
    ...

Apply @guarded_function_tool as the inner decorator (before @function_tool) so FiGuard wraps the raw function and has access to all kwargs.

OpenAI Function Calling

pip install figuard[openai]
import json
from figuard.integrations.openai import guarded_openai_function

@guarded_openai_function(
    client=client,
    session_token=budget.primary_token.session_token,
    category="flight",
)
def book_flight(destination: str, amount: float) -> str:
    ...

# Dispatch in your tool call loop:
for tool_call in response.choices[0].message.tool_calls:
    if tool_call.function.name == "book_flight":
        result = book_flight(**json.loads(tool_call.function.arguments))

Anthropic Tool Use

pip install figuard[anthropic]
from figuard.integrations.anthropic import guarded_anthropic_tool

@guarded_anthropic_tool(
    client=client,
    session_token=budget.primary_token.session_token,
    category="flight",
)
def book_flight(destination: str, amount: float) -> str:
    ...

# Dispatch in your tool use loop (Anthropic passes block.input as a dict):
for block in response.content:
    if block.type == "tool_use" and block.name == "book_flight":
        result = book_flight(**block.input)

Denial handling across all integrations

When a tool call is denied, each integration handles it differently:

Integration Denial behavior
FiGuardCallbackHandler Raises ToolException — LLM receives denial reason
FiGuardToolGuard Returns denial string — LLM receives denial reason
FiGuardCrewGuard Returns denial string — LLM receives denial reason
guarded_function_tool Returns denial string — LLM receives denial reason
guarded_openai_function Returns denial string — return as tool result to the model
guarded_anthropic_tool Returns denial string — return in tool_result block to Claude

The denial string format: "FiGuard DENIED: <code> — <message>", e.g.:

FiGuard DENIED: INSUFFICIENT_FUNDS — flight allocation has $0.00 remaining

License

Apache 2.0 — see LICENSE for details.

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

figuard-0.4.0.tar.gz (70.2 kB view details)

Uploaded Source

Built Distribution

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

figuard-0.4.0-py3-none-any.whl (48.8 kB view details)

Uploaded Python 3

File details

Details for the file figuard-0.4.0.tar.gz.

File metadata

  • Download URL: figuard-0.4.0.tar.gz
  • Upload date:
  • Size: 70.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.3

File hashes

Hashes for figuard-0.4.0.tar.gz
Algorithm Hash digest
SHA256 f0e8a10bafe8c84ca7d847ccc588b0580837928d4c9756a93b3ccdd3acdcdab2
MD5 086e63d0d73956a63face6a1454b195e
BLAKE2b-256 1237f8ad4c760798f86794cbf4d2960a5e46770a87983a09d375d381c6048eab

See more details on using hashes here.

File details

Details for the file figuard-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: figuard-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 48.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.3

File hashes

Hashes for figuard-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5c3220650cbb56de1e373e54b5f1884bea93177df4877314a1a1007a769cb964
MD5 7ad09142de967865d5890cd920bd26c7
BLAKE2b-256 023584ab286dd735f89016ad0a1cc9e6339b16f722293afd5120e594d56e7d33

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