Modei
PricingDocsBlog

Documentation

Passport-Only Enforcement

You don't need a gate to enforce constraints. Issue a passport with guardrails, then call POST /api/enforce before each action. The enforcement layer evaluates all constraints and returns a signed allow, request_hold, or block decision, no gate infrastructure required.

··

Zero-infrastructure path

Issue a passport → call POST /api/enforce before each action → get enforced constraints immediately. No gate setup, no infrastructure, no server-side changes needed.

When to Use This Pattern

Spend caps on your own agents

Enforce daily/monthly spending limits on an agent you control, without building gate infrastructure.

Rate limits without a proxy

Limit how often your agent calls an external API, tracked per passport with window counters.

Domain restrictions

Allow your agent to only call specific domains, the enforcement layer evaluates core:scope:domain_allowlist on every action.

Action allowlists

Restrict your agent to specific actions, great for least-privilege configurations in agent pipelines.

Human approval workflows

Actions above a spend threshold get request_hold, your agent pauses and waits for human review.

Budget tracking

Monitor how much an agent has spent this week/month via get_cumulative_state, without any billing infrastructure.

Step 1: Issue a passport with constraints

Constraints are embedded in the passport at issuance. You can set them via the API, the SDK, or the dashboard.

python
import httpx
import os

client = httpx.Client(
    base_url="https://modei.ai/api/v1",
    headers={"Authorization": f"Bearer {os.environ['MODEI_API_KEY']}"}
)

response = client.post("/passports", json={
    "issuer_id": "iss_your_issuer_id",
    "agent_id": "my-agent-001",
    "agent_name": "Autonomous Research Agent",
    "permissions": ["web:search", "web:fetch", "documents:read"],
    "trust_tier": "L1",
    "expires_in_days": 30,
    "constraints": {
        # Spend caps
        "core:cost:max_per_action": 500,        # $5.00 max per single action
        "core:cost:max_cumulative": 10000,       # $100.00/day max total
        "core:cost:cumulative_window": "daily",

        # Rate limits
        "core:rate:max_per_hour": 200,
        "core:rate:max_per_day": 1000,

        # Domain restriction
        "core:scope:domain_allowlist": [
            "api.openai.com",
            "api.anthropic.com",
            "serpapi.com"
        ],

        # Approval for large transactions
        "core:cost:approval_threshold": 2000,    # Require approval above $20
    }
})
response.raise_for_status()
passport = response.json()

# Save the private key immediately, never shown again
print(f"Passport ID: {passport['id']}")
print(f"Private Key: {passport['private_key']}")  # Save to secrets manager!

Critical: Save your Private Key RIGHT NOW

The private key is returned exactly once and is never stored on Modei servers. Copy it immediately and save it to a secrets manager (1Password, Bitwarden, AWS Secrets Manager). It cannot be recovered.

typescript
const response = await fetch("https://modei.ai/api/v1/passports", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.MODEI_API_KEY}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    issuer_id: 'iss_your_issuer_id',
    agent_id: 'my-agent-001',
    agent_name: 'Autonomous Research Agent',
    permissions: ['web:search', 'web:fetch', 'documents:read'],
    trust_tier: 'L1',
    expires_in_days: 30,
    constraints: {
      'core:cost:max_per_action': 500,         // $5.00 max per action
      'core:cost:max_cumulative': 10000,        // $100.00/day max
      'core:cost:cumulative_window': 'daily',
      'core:rate:max_per_hour': 200,
      'core:scope:domain_allowlist': ['api.openai.com', 'serpapi.com'],
      'core:cost:approval_threshold': 2000,    // Require approval > $20
    },
  })
});

const passport = await response.json();

// CRITICAL: save the private key immediately, never shown again
await storeSecret('agents/my-agent-001/key', passport.private_key);

Step 2: Call enforce before each action

Before your agent does anything that has a cost or could violate constraints, call POST /api/enforce. This is typically a millisecond-level call, add it to your agent's action wrapper.

python
import httpx
import os

PASSPORT_ID = os.environ["PASSPORT_ID"]
API_KEY = os.environ["MODEI_API_KEY"]

async def enforce(action: str, cost_cents: int = 0, target: str = None) -> dict:
    """Call before any agent action. Returns decision dict."""
    async with httpx.AsyncClient() as client:
        resp = await client.post(
            "https://modei.ai/api/v1/enforce",
            headers={"Authorization": f"Bearer {API_KEY}"},
            json={
                "passport_id": PASSPORT_ID,
                "action": action,
                "cost_cents": cost_cents,
                "target": target
            }
        )
    result = resp.json()
    return result

async def search_the_web(query: str):
    # Check constraints before executing
    decision = await enforce(
        action="web:search",
        cost_cents=2,            # $0.02 per search
        target="serpapi.com"
    )
    
    if decision["decision"] == "block":
        raise Exception(f"Action blocked: {decision['reason']}")
    
    if decision["decision"] == "request_hold":
        # Wait for human approval
        await request_approval(decision["approval_request_id"])
        return
    
    # allow, proceed with the action
    return await do_web_search(query)


async def make_api_call(endpoint: str, cost_cents: int):
    decision = await enforce(
        action="api:call",
        cost_cents=cost_cents,
        target=endpoint
    )
    
    match decision["decision"]:
        case "allow":
            return await call_api(endpoint)
        case "block":
            print(f"Blocked: {decision.get('detail', decision['reason'])}")
            return None
        case "request_hold":
            print(f"Needs approval (request ID: {decision.get('approval_request_id')})")
            return None
cURL example
curl -X POST https://modei.ai/api/v1/enforce \
  -H "Authorization: Bearer mod_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "passport_id": "pass_01HABC...",
    "action": "web:fetch",
    "cost_cents": 2,
    "target": "https://serpapi.com/search"
  }'

Step 3: Monitor cumulative state

Check your agent's current spend and rate counters at any time:

bash
# Get current state
GET /api/passports/{passport_id}/state
Authorization: Bearer mod_your_key

# Response:
{
  "passport_id": "pass_01HABC...",
  "daily_cost_cents": 4250,
  "daily_cost_limit_cents": 10000,
  "daily_requests": 127,
  "daily_request_limit": 1000,
  "window_resets_at": "2026-02-25T00:00:00Z"
}
python
# Reset daily counters (e.g., for testing)
async def reset_agent_daily_counters():
    async with httpx.AsyncClient() as client:
        resp = await client.post(
            f"https://modei.ai/api/v1/passports/{PASSPORT_ID}/state/reset",
            headers={"Authorization": f"Bearer {API_KEY}"},
            json={"window_type": "daily"}
        )
    return resp.json()

Complete Agent Wrapper Pattern

python
import httpx
import os
from functools import wraps

class ConstrainedAgent:
    """Wrapper that enforces constraints on every action."""
    
    def __init__(self, passport_id: str, api_key: str):
        self.passport_id = passport_id
        self.api_key = api_key
    
    async def enforce(self, action: str, cost_cents: int = 0, target: str = None):
        async with httpx.AsyncClient() as client:
            resp = await client.post(
                "https://modei.ai/api/v1/enforce",
                headers={"Authorization": f"Bearer {self.api_key}"},
                json={
                    "passport_id": self.passport_id,
                    "action": action,
                    "cost_cents": cost_cents,
                    "target": target
                }
            )
        return resp.json()
    
    async def execute(self, action: str, cost_cents: int, target: str, fn):
        """Enforce constraints then execute function."""
        decision = await self.enforce(action, cost_cents, target)
        
        if decision["decision"] == "allow":
            return await fn()
        elif decision["decision"] == "request_hold":
            raise SuspendError(
                f"Action requires approval: {decision.get('approval_request_id')}"
            )
        else:
            raise BlockError(
                f"Action blocked: {decision.get('detail', decision['reason'])}"
            )

# Usage
agent = ConstrainedAgent(
    passport_id=os.environ["PASSPORT_ID"],
    api_key=os.environ["MODEI_API_KEY"]
)

# All these calls check constraints first:
result = await agent.execute("web:search", 2, "serpapi.com",
    lambda: search_web("AI agent trust"))

result = await agent.execute("documents:write", 10, "notion.so",
    lambda: write_document("Summary", content))

When to Add a Gate

Passport-only enforcement is ideal for agents you control. If you need to verify agents from outside your organization, or if you want to expose an API that other agents can discover and use, you need a gate.

Passport-only ✓

  • Your agent, your enforcement
  • Budget tracking and spend caps
  • Rate limiting without a proxy
  • Quick start, zero infrastructure

Add a gate when ✓

  • Verifying agents from other orgs
  • Exposing a service for agent discovery
  • Bilateral metering and settlement
  • L3 proof-of-possession required

Related