Python SDK for the Modei REST API — manage agent passports, gates, and enforcement policies.
Project description
modei-python
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file modei_python-1.0.0.tar.gz.
File metadata
- Download URL: modei_python-1.0.0.tar.gz
- Upload date:
- Size: 23.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2a00742a1b4325f67c4e27372d36a34acdc74069d4eea15b2826ecb9cefae916
|
|
| MD5 |
fdef35775a5334e3c3299a8bdc3562aa
|
|
| BLAKE2b-256 |
6579d7435728e9988368fcb2e2a4f440a902476bac56c19807a1e3705499ed10
|
File details
Details for the file modei_python-1.0.0-py3-none-any.whl.
File metadata
- Download URL: modei_python-1.0.0-py3-none-any.whl
- Upload date:
- Size: 19.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b6f5eb560c699fcaa3af71423565e566bea3140b59c9e0e664ef5fce70b93696
|
|
| MD5 |
9b843318bfca33062d695e76b0aa8bc2
|
|
| BLAKE2b-256 |
78a130dfe593736ed21f6df42e5374bdae75ca327dd844d8a88728f0c3e8f80f
|