Skip to main content

Python SDK for the Modei REST API and self-issued passport workflows.

Project description

modei-python

PyPI version License: MIT

Python SDK for the Modei REST API. Manage agent passports, gates, and enforcement policies programmatically.

The MCP server (for Claude Desktop, Cursor, etc.) is the separate TypeScript package: modei-mcp on npm.


Installation

pip install modei-python

Usage

from modei import ModeiClient

client = ModeiClient(api_key="mod_live_xxx")

# List all gates
gates = client.list_gates()

# Create a gate
gate = client.create_gate(name="My API", gate_id="gate_my-api")

# Issue a passport
passport = client.issue_passport(
    "gate_my-api",
    agent_id="agent-001",
    permissions=["read", "write"],
    expires_in="7d",
)

# Check authorization
result = client.check_gate("gate_my-api", action="read", passport_id=passport["passport_id"])
print(result["allowed"])  # True

# Enforce with constraints
enforcement = client.enforce_action(
    passport_id=passport["passport_id"],
    action="write",
    cost_cents=500,
)
print(enforcement["decision"])  # "PERMIT"

client.close()

Async Usage

import asyncio
from modei import AsyncModeiClient

async def main():
    async with AsyncModeiClient(api_key="mod_live_xxx") as client:
        gates = await client.list_gates()
        for gate in gates:
            passports = await client.list_passports(gate["gate_id"])
            print(f"{gate['name']}: {len(passports)} passports")

asyncio.run(main())

Both clients support context managers for automatic cleanup:

with ModeiClient(api_key="mod_live_xxx") as client:
    gates = client.list_gates()

API Coverage

Gates

client.list_gates()
client.get_gate("gate_my-api")
client.create_gate(name="My API", gate_id="gate_my-api")
client.update_gate("gate_my-api", name="Updated Name")
client.delete_gate("gate_my-api")

Passports

client.list_passports("gate_my-api")
client.get_passport("gate_my-api", "pp_xxx")
client.issue_passport("gate_my-api", agent_id="agent-001", permissions=["read"])
client.revoke_passport("gate_my-api", "pp_xxx")
client.reissue_passport("pp_xxx", accept_catalog_version=2)

Attestations

client.list_attestations("gate_my-api", limit=50)
client.record_attestation("gate_my-api", passport_id="pp_xxx", permission="read", tool_name="search", result="allowed")

Permission Catalog

client.get_catalog("gate_my-api")
client.create_catalog("gate_my-api", permissions=[...])
client.publish_catalog("gate_my-api", change_summary="Added search permission")
client.list_catalog_versions("gate_my-api")
client.get_catalog_version("gate_my-api", version=1)
client.get_catalog_impact("gate_my-api")

Gate Check

client.check_gate("gate_my-api", action="read", passport_id="pp_xxx")
client.authorize_dry_run(gate_id="gate_my-api", passport={"..."}, requested_permission="read")

Constraints

client.get_constraints("pp_xxx")
client.set_constraints("pp_xxx", {"read": {"core:rate:max_per_minute": 100}})
client.list_constraint_types(category="cost")
client.list_constraint_templates(category="security")
client.apply_constraint_template("pp_xxx", "conservative-agent")
client.create_constraint_template(slug="my-template", name="My Template", constraints={...})

Enforcement (CEL)

client.enforce_action(passport_id="pp_xxx", action="write", cost_cents=500)
client.list_enforcement_attestations("pp_xxx", decision="BLOCK")
client.get_enforcement_attestation("enf_xxx")
client.verify_enforcement_attestation("enf_xxx")

Anonymous Access

client.get_anonymous_policy("gate_my-api")
client.set_anonymous_policy("gate_my-api", enabled=True, allowed_actions=["read"])
client.get_anonymous_log("gate_my-api")

Commerce

client.discover_services("flights:search", max_price_cents=100, sort="price_asc")
client.issue_consumption_attestation(passport_id="pp_xxx", gate_id="gate_my-api", action="flights:search", outcome="success")
client.generate_settlement(gate_id="gate_my-api", period_type="monthly", period_start="2025-01-01", period_end="2025-01-31")
client.list_settlements(gate_id="gate_my-api", status="pending")
client.get_settlement("stl_xxx")
client.update_settlement_status("stl_xxx", "invoiced")
client.get_sla_compliance("gate_my-api", period_start="2025-01-01", period_end="2025-01-31")

Cumulative State

client.get_cumulative_state("pp_xxx")
client.reset_cumulative_state("pp_xxx", window_type="daily")

API Keys

client.list_api_keys()
client.create_api_key(name="My Key", scopes=["gates:read", "passports:write"])
client.revoke_api_key("key_xxx")

Cryptographic Verification

Local verification utilities for Ed25519 signatures and RFC 8785 content hashing:

from modei import verify_attestation_signature, verify_content_hash, compute_content_hash

valid = verify_attestation_signature(
    attestation_json='{"gate_id":"gate_my-api",...}',
    signature_b64="base64-sig...",
    public_key_b64="base64-key...",
)

matches = verify_content_hash(catalog_snapshot, expected_hash)
hash_hex = compute_content_hash({"key": "value"})

Error Handling

from modei import (
    ModeiError,
    AuthenticationError,
    AuthorizationError,
    NotFoundError,
    RateLimitError,
    ValidationError,
    ConflictError,
)

try:
    client.get_gate("gate_nonexistent")
except NotFoundError as e:
    print(f"Not found: {e}")
    print(f"Status: {e.status_code}")  # 404
except RateLimitError as e:
    print(f"Rate limited, retry after: {e.retry_after}s")
except ModeiError as e:
    print(f"API error: {e} (HTTP {e.status_code})")
Exception HTTP Status
AuthenticationError 401
AuthorizationError 403
NotFoundError 404
ConflictError 409
ValidationError 400, 422
RateLimitError 429
ModeiError All other errors

Environment Variables

Variable Required Default Description
MODEI_API_KEY Yes Your Modei API key
MODEI_API_URL No https://modei.ai API base URL (override for local dev)

You can also pass these directly to the client:

client = ModeiClient(api_key="mod_live_xxx", base_url="http://localhost:3000")

Documentation

Full documentation at modei.ai/docs


License

MIT — Standard Logic Co.

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

modei_python-1.1.0a2.tar.gz (69.0 kB view details)

Uploaded Source

Built Distribution

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

modei_python-1.1.0a2-py3-none-any.whl (45.2 kB view details)

Uploaded Python 3

File details

Details for the file modei_python-1.1.0a2.tar.gz.

File metadata

  • Download URL: modei_python-1.1.0a2.tar.gz
  • Upload date:
  • Size: 69.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for modei_python-1.1.0a2.tar.gz
Algorithm Hash digest
SHA256 147ecac37c283864d20ec003f36eaf632c8d7dd486d7ed2301c7c6e957100306
MD5 b871d8609cfa51e2cf3cfa81ccaeab4e
BLAKE2b-256 1eae8bda231666b59237206c9628b8ae704fa23e0e081212adf62d98d42a669c

See more details on using hashes here.

File details

Details for the file modei_python-1.1.0a2-py3-none-any.whl.

File metadata

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

File hashes

Hashes for modei_python-1.1.0a2-py3-none-any.whl
Algorithm Hash digest
SHA256 4d5b589fe1acd74a55af0cdcae3dcbeba390673c72aacc19b3254a66c8225407
MD5 a78fa6f323c4a55ec0a6cddb9c17e9c2
BLAKE2b-256 820b2e07c8f9becd84206f51798407f044436302a204e124eff1455be3665173

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