Passports API
Endpoints for issuing, managing, and revoking AI agent passports.
POST /passports: Issue a Passport
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"
}
}'{
"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
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"{
"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
curl https://modei.ai/api/v1/passports/pass_01HABC... \
-H "Authorization: Bearer mod_live_xxxxxxxx"{
"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
curl https://modei.ai/api/v1/passports/pass_01HABC.../verify \
-H "Authorization: Bearer mod_live_xxxxxxxx"{
"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
}{
"valid": false,
"reason": "revoked",
"revoked_at": "2026-02-24T11:00:00Z",
"revocation_reason": "Private key potentially compromised"
}POST /passports/:id/revoke: Revoke a Passport
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"}'{
"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.
# 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:
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
- API Overview, Base URL, auth, rate limits, error codes.
- Passports Concept
- Python SDK