Skip to main content

Python SDK for the Kora authorization engine — deterministic spend authorization for AI agents

Project description

Kora Python SDK

Python SDK for the Kora authorization engine. Handles Ed25519 signing, nonce generation, canonical JSON serialization, idempotent retry, and offline seal verification.

Installation

pip install kora-sdk

Or install from source:

pip install -e sdk/python

Requirements: Python 3.9+, PyNaCl >= 1.5.0, requests >= 2.28.0

Quick Start

from kora import Kora

# Initialize with the secret key returned from agent creation
kora = Kora("kora_agent_sk_...")

# Authorize a spend
auth = kora.authorize(
    mandate="mandate_abc123",
    amount=50_00,        # EUR 50.00
    currency="EUR",
    vendor="aws",
    category="compute",  # required if mandate has category_allowlist
)

if auth.approved:
    print(f"Approved: {auth.decision_id}")
    print(f"Daily remaining: {auth.limits_after_approval['daily_remaining_cents']}")
else:
    print(f"Denied: {auth.reason_code}")
    print(f"Hint: {auth.denial.hint}")

Usage

Authorize a Spend

from kora import Kora

kora = Kora(
    "kora_agent_sk_...",
    base_url="http://localhost:8000",  # default
    ttl=300,          # default TTL in seconds
    max_retries=2,    # automatic idempotent retry on network error
)

result = kora.authorize(
    mandate="mandate_abc123",
    amount=50_00,
    currency="EUR",
    vendor="aws",
    category="compute",
)

Result Properties

result.approved        # bool — True if APPROVED
result.decision        # "APPROVED" or "DENIED"
result.decision_id     # UUID of the authorization decision
result.reason_code     # "OK", "DAILY_LIMIT_EXCEEDED", etc.
result.executable      # bool — True if payment can be executed
result.is_valid        # bool — True if TTL has not expired
result.is_enforced     # bool — True if enforcement_mode == "enforce"
result.enforcement_mode  # "enforce" or "log_only"

# On denial:
result.denial.hint            # Human-readable suggestion
result.denial.actionable      # Machine-readable corrective values
result.denial.failed_check    # Which pipeline step failed

# On approval:
result.limits_after_approval  # Remaining daily/monthly budget

# Evaluation trace:
result.evaluation_trace.steps        # List of pipeline step results
result.evaluation_trace.total_duration_ms  # Total evaluation time

# Notary seal:
result.notary_seal.signature    # Ed25519 signature (base64)
result.notary_seal.public_key_id
result.notary_seal.algorithm    # "Ed25519"

# Trace URL (for debugging denials):
result.trace_url  # e.g. http://localhost:8000/v1/authorizations/<id>/trace

Handle Denials

result = kora.authorize(
    mandate="mandate_abc123",
    amount=999_99,
    currency="EUR",
    vendor="aws",
)

if not result.approved:
    print(f"Denied: {result.reason_code}")
    print(f"Hint: {result.denial.hint}")

    # Machine-readable corrective values
    if result.reason_code == "DAILY_LIMIT_EXCEEDED":
        available = result.denial.actionable["available_cents"]
        print(f"Available budget: {available} cents")

    if result.reason_code == "VENDOR_NOT_ALLOWED":
        allowed = result.denial.actionable["allowed_vendors"]
        print(f"Allowed vendors: {allowed}")

    # Full trace URL for debugging
    print(f"Trace: {result.trace_url}")

Verify Notary Seal (Offline)

from base64 import b64decode

# Kora's public key (from your deployment)
kora_public_key = b64decode("...")

is_valid = kora.verify_seal(result, kora_public_key)
print(f"Seal valid: {is_valid}")

Simulation Mode

Test denial scenarios without affecting state. Requires an admin key with simulation_access=true.

result = kora.authorize(
    mandate="mandate_abc123",
    amount=100,
    currency="EUR",
    vendor="aws",
    simulate="DAILY_LIMIT_EXCEEDED",
    admin_key="kora_admin_...",
)

assert result.simulated is True
assert result.decision == "DENIED"
assert result.reason_code == "DAILY_LIMIT_EXCEEDED"
assert result.notary_seal is None  # no seal in simulation

OpenAI Function Tool Schema

Generate an OpenAI-compatible function tool definition for use with LLM agents:

tool = kora.as_tool("mandate_abc123")
# Returns:
# {
#     "type": "function",
#     "function": {
#         "name": "kora_authorize_spend",
#         "description": "Authorize a spend against a Kora mandate...",
#         "parameters": {
#             "type": "object",
#             "properties": {
#                 "amount_cents": {"type": "integer", "description": "..."},
#                 "currency": {"type": "string", "description": "..."},
#                 "vendor_id": {"type": "string", "description": "..."},
#             },
#             "required": ["amount_cents", "currency", "vendor_id"]
#         }
#     }
# }

# With category enum constraint:
tool = kora.as_tool("mandate_abc123", category_enum=["compute", "api_services"])

Use with OpenAI:

import openai

client = openai.OpenAI()
response = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Buy $50 of AWS compute"}],
    tools=[kora.as_tool("mandate_abc123")],
)

Agent Self-Correction Pattern

from kora import Kora

kora = Kora("kora_agent_sk_...")

# First attempt — too large
auth = kora.authorize(mandate="mandate_abc123", amount=999_99, currency="EUR", vendor="aws")

if not auth.approved and auth.reason_code == "DAILY_LIMIT_EXCEEDED":
    # Read the actionable hint
    available = auth.denial.actionable["available_cents"]
    print(f"Budget available: {available} cents, retrying...")

    # Retry with corrected amount
    auth = kora.authorize(mandate="mandate_abc123", amount=available, currency="EUR", vendor="aws")
    print(f"Second attempt: {auth.decision}")  # APPROVED

API Reference

Kora(key_string, base_url=None, ttl=300, max_retries=2)

Parameter Type Default Description
key_string str required Agent secret key (kora_agent_sk_...)
base_url str http://localhost:8000 Kora API base URL
ttl int 300 Default TTL for decisions (seconds)
max_retries int 2 Automatic retries on network error

kora.authorize(**kwargs) -> AuthorizationResult

Parameter Type Required Description
mandate str yes Mandate ID
amount int yes Amount in cents
currency str yes 3-letter currency code
vendor str yes Vendor identifier
category str no Spending category
simulate str no Force denial reason code (simulation mode)
admin_key str no Admin key for simulation access

kora.verify_seal(result, public_key) -> bool

Verify the Ed25519 notary seal offline.

kora.as_tool(mandate, category_enum=None) -> dict

Generate OpenAI function tool schema.

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

kora_sdk-1.1.0.tar.gz (20.9 kB view details)

Uploaded Source

Built Distribution

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

kora_sdk-1.1.0-py3-none-any.whl (14.8 kB view details)

Uploaded Python 3

File details

Details for the file kora_sdk-1.1.0.tar.gz.

File metadata

  • Download URL: kora_sdk-1.1.0.tar.gz
  • Upload date:
  • Size: 20.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.1

File hashes

Hashes for kora_sdk-1.1.0.tar.gz
Algorithm Hash digest
SHA256 6404251557dce9b7b8c358a0fdb6af8ea2ecd7431c48a7c4a906cfa593c5fc7e
MD5 24d08a85d1f7ff3ed69ebbaacae4db9f
BLAKE2b-256 9107c84c9389e5366539524cbc61e424794f9e7e6f7c7ec974c15c3d9882e9e5

See more details on using hashes here.

File details

Details for the file kora_sdk-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: kora_sdk-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 14.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.1

File hashes

Hashes for kora_sdk-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 748cc2caa8cac616f04df0cbe786b9e7a63ec14e873e798e2e083e4143dfc526
MD5 25431553be42f7aa23c0c87202768c63
BLAKE2b-256 436c21c7eeafed35889154bb387e0ec53d10ccf84053aa4a478def8add43c61e

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