Modei
PricingDocsBlog

Documentation

Passports API

Endpoints for issuing, managing, and revoking AI agent passports.

··

POST /passports: Issue a Passport

bash
curl -X POST https://modei.ai/api/v1/passports \
  -H "Authorization: Bearer mod_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "issuer_id": "iss_01HXYZ...",
    "agent_id": "research-bot-001",
    "agent_name": "Research Bot",
    "permissions": ["web:search", "web:fetch", "documents:read"],
    "expires_in_days": 30,
    "trust_tier": "L2",
    "metadata": {
      "environment": "production",
      "spawned_by": "orchestrator"
    }
  }'
201 Created
{
  "passport_id": "pass_01HABC...",
  "agent_id": "research-bot-001",
  "agent_name": "Research Bot",
  "issuer_id": "iss_01HXYZ...",
  "permissions": ["web:search", "web:fetch", "documents:read"],
  "trust_tier": "L2",
  "public_key": "ed25519:ABC123...",
  "private_key": "ed25519_private:XYZ789...",
  "expires_at": "2026-03-26T10:00:00Z",
  "created_at": "2026-02-24T10:00:00Z",
  "status": "active",
  "metadata": {
    "environment": "production",
    "spawned_by": "orchestrator"
  }
}

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.

GET /passports: List Passports

bash
curl https://modei.ai/api/v1/passports \
  -H "Authorization: Bearer mod_live_xxxxxxxx" \
  -G \
  --data-urlencode "issuer_id=iss_01HXYZ..." \
  --data-urlencode "status=active" \
  --data-urlencode "limit=50" \
  --data-urlencode "offset=0"
200 OK
{
  "items": [
    {
      "passport_id": "pass_01HABC...",
      "agent_id": "research-bot-001",
      "agent_name": "Research Bot",
      "trust_tier": "L2",
      "status": "active",
      "expires_at": "2026-03-26T10:00:00Z",
      "created_at": "2026-02-24T10:00:00Z"
    }
  ],
  "total": 42,
  "limit": 50,
  "offset": 0
}

Query params: issuer_id, status (active|revoked|expired), trust_tier, limit, offset

GET /passports/:id: Get a Passport

bash
curl https://modei.ai/api/v1/passports/pass_01HABC... \
  -H "Authorization: Bearer mod_live_xxxxxxxx"
200 OK
{
  "passport_id": "pass_01HABC...",
  "agent_id": "research-bot-001",
  "agent_name": "Research Bot",
  "issuer_id": "iss_01HXYZ...",
  "issuer_domain": "acmecorp.com",
  "permissions": ["web:search", "web:fetch"],
  "trust_tier": "L2",
  "public_key": "ed25519:ABC123...",
  "status": "active",
  "expires_at": "2026-03-26T10:00:00Z",
  "created_at": "2026-02-24T10:00:00Z",
  "last_used_at": "2026-02-24T14:30:00Z",
  "use_count": 248,
  "metadata": {}
}

GET /passports/:id/verify: Verify a Passport

bash
curl https://modei.ai/api/v1/passports/pass_01HABC.../verify \
  -H "Authorization: Bearer mod_live_xxxxxxxx"
200 OK, Valid
{
  "valid": true,
  "passport_id": "pass_01HABC...",
  "agent_id": "research-bot-001",
  "trust_tier": "L2",
  "expires_at": "2026-03-26T10:00:00Z",
  "is_expired": false,
  "is_revoked": false
}
200 OK, Invalid
{
  "valid": false,
  "reason": "revoked",
  "revoked_at": "2026-02-24T11:00:00Z",
  "revocation_reason": "Private key potentially compromised"
}

POST /passports/:id/revoke: Revoke a Passport

bash
curl -X POST https://modei.ai/api/v1/passports/pass_01HABC.../revoke \
  -H "Authorization: Bearer mod_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Task complete, passport no longer needed"}'
200 OK
{
  "passport_id": "pass_01HABC...",
  "status": "revoked",
  "revoked_at": "2026-02-24T15:00:00Z",
  "reason": "Task complete, passport no longer needed"
}

Programmatic issuance from CI / unattended agents

When you call create_passport through an MCP client (Claude Code, Cursor, Windsurf, etc.), the client will typically prompt the operator before executing, that's why your CI run may surface "No approval received". Modei's server does not gate this call; the prompt comes from the client's default policy for non-readonly tools.

For unattended issuance, take one of two paths that bypass the client-side prompt entirely:

Option A: REST with an API key

Issue an API key from the dashboard (or via create_api_key) with at least the passports:create scope, then POST to the REST endpoint shown above. The server accepts both Supabase sessions (browser wizard) and API-key bearer tokens.

bash
# CI / orchestrator
curl -X POST https://modei.ai/api/passports \
  -H "Authorization: Bearer mod_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_name": "ci-deploy-bot",
    "agent_type": "custom",
    "permissions": ["deploy:run"],
    "expires_in": "24h"
  }'

Option B: JSON-RPC against /api/mcp directly

The MCP server itself accepts an OAuth bearer token and dispatches tool calls without any approval gate. Calling it with curl / fetch takes the MCP client out of the loop:

bash
curl -X POST https://modei.ai/api/mcp \
  -H "Authorization: Bearer <oauth-access-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "create_passport",
      "arguments": {
        "issuer_id": "iss_...",
        "agent_id": "ci-deploy-bot",
        "permissions": ["deploy:run"],
        "expires_in": "24h"
      }
    }
  }'

The same applies to revoke_passport, which is annotated destructiveHint: true on purpose, clients should prompt for human approval on revocation. Use the REST or direct-RPC path above for incident-response automation.

Related