Passports are cryptographically signed JWTs that prove an agent's identity and authorization. They are the core trust primitive in STACK - any service can verify a passport without calling STACK's API by using the public JWKS endpoint. Passports are signed with EdDSA (Ed25519), have a default TTL of 15 minutes (hard max: 1 hour), and support delegation chains up to 4 hops deep.
All endpoints except POST /v1/passports/verify and the GET /v1/.well-known/jwks.json JWKS endpoint require an operator-scoped bearer token.
Issue a new passport JWT for a registered agent. The passport embeds the agent's identity, service scopes, identity claims, optional opaque authority references, and accountability settings in a stk namespace within the JWT payload.
{
"agent_id": "agt_7kx9m2nq4p",
"ttl_seconds": 900,
"scopes": [
{
"service_connection_id": "svc_conn_abc123",
"scopes": ["read:messages", "write:messages"],
"allow_data_from": ["guestbook"]
}
],
"identity_claim_ids": ["clm_9xm3kR7wL2"],
"authority_binding_ids": ["abn_tax_filing"],
"intent": {
"summary": "Process and respond to customer support emails",
"services": ["slack", "gmail"],
"will_delegate": false,
"estimated_duration_seconds": 1800
},
"checkpoint_interval_seconds": 300
}A grant may use ["*"] as standing operator policy. Before signing, STACK replaces it with the exact active service names currently granted to the agent. The Passport never contains a wildcard, and a service connected later does not change an existing Passport.
curl -X POST https://api.getstack.run/v1/passports/issue \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk_live_op_abc123" \
-d '{
"agent_id": "agt_7kx9m2nq4p",
"ttl_seconds": 600,
"intent": {
"summary": "Process support messages",
"services": ["slack"]
}
}'{
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...",
"jti": "ppt_9xm3kR7wL2",
"expires_at": "2026-04-15T10:40:00.000Z"
}The decoded JWT uses a stk namespace for all STACK-specific claims. The sub field is the agent ID.
{
"iss": "https://api.getstack.run",
"sub": "agt_7kx9m2nq4p",
"iat": 1713174600,
"exp": 1713175200,
"jti": "ppt_9xm3kR7wL2",
"stk": {
"operator_id": "op_abc123",
"agent_id": "agt_7kx9m2nq4p",
"agent_name": "invoice-processor",
"services": [
{
"service_id": "svc_123",
"service_name": "slack",
"scopes": ["read:messages"],
"credential_ref": "cred_ref_abc",
"connection_id": "scon_a1b2c3d4",
"allow_data_from": ["guestbook"]
}
],
"identity_claims": [
{
"claim_id": "clm_9xm3kR7wL2",
"provider": "bankid_se",
"layer": "humanity",
"claim_type": "verified_human",
"assurance_level": "high",
"verified_at": 1713174000,
"expires_at": 1744710000,
"humanity_verified": true
}
],
"authority_refs": [
{
"binding_id": "abn_tax_filing",
"binding_version": 1,
"binding_claim_id": "pc_...",
"binding_digest": "sha256:...",
"receiver_id": "rcv_tax_agency",
"receiver_profile_version_id": "apv_...",
"expires_at": 1713175100
}
],
"delegation_depth": 0,
"session_id": "sess_abc123",
"accountability": "enforced",
"intent_summary": "Process customer support emails",
"intent_services": ["slack", "gmail"],
"checkpoint_interval": 300
}
}Each authority_refs entry pins the active binding version, signed claim, digest, receiver profile, and expiry. It contains no principal name, proof material, mandate text, disclosed fact, or native evidence. Runtime routes resolve the reference against live binding, proof, receiver, key, approval, and revocation state before a protected action. See Authority API.
Verify a passport token and return its decoded claims. This endpoint is unauthenticated - no API key is required. It checks the EdDSA signature, expiration, and revocation status. Optionally pass a service_id to verify the passport grants access to a specific service.
{
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...",
"service_id": "svc_123"
}curl -X POST https://api.getstack.run/v1/passports/verify \
-H "Content-Type: application/json" \
-d '{
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9..."
}'{
"valid": true,
"jti": "ppt_9xm3kR7wL2",
"agent_id": "agt_7kx9m2nq4p",
"expires_at": "2026-04-15T10:40:00.000Z",
"claims": {
"operator_id": "op_abc123",
"agent_id": "agt_7kx9m2nq4p",
"agent_name": "invoice-processor",
"services": [],
"identity_claims": [],
"delegation_depth": 0,
"session_id": "sess_abc123"
}
}The verify endpoint does not require authentication. Any service can verify a passport by posting the token. For fully offline verification, use the JWKS endpoint to fetch STACK's public keys and verify the EdDSA signature locally.
Immediately revoke an active Passport. The next STACK-verified call rejects it. Offline signature-only verifiers must call the online verify endpoint or honor expiry.
{
"jti": "ppt_9xm3kR7wL2",
"reason": "Agent compromised"
}{
"success": true,
"jti": "ppt_9xm3kR7wL2",
"cascaded_count": 0,
"revoked_claims_count": 0
}Create a delegated passport from an existing one. The child passport inherits the parent's identity chain but can only have equal or narrower scopes. Maximum delegation depth is 4 hops.
{
"parent_passport_token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...",
"child_agent_id": "agt_3fh8j1kw6r",
"scopes": [
{
"service_connection_id": "svc_conn_abc123",
"scopes": ["read:messages"],
"allow_data_from": ["guestbook"]
}
],
"ttl_seconds": 300
}{
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...",
"jti": "ppt_5nK2xW8mR4",
"expires_at": "2026-04-15T10:35:00.000Z"
}Refresh an existing passport token. Returns a new JWT with a fresh TTL while preserving the same scopes, claims, and delegation chain.
{
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...",
"ttl_seconds": 900
}{
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...",
"jti": "ppt_8rW4mK9xN1",
"expires_at": "2026-04-15T10:55:00.000Z"
}Submit a checkpoint for an active passport. Checkpoints report what the agent has been doing - which services were used, how many actions taken, and whether any delegation occurred. Required at regular intervals for agents in enforced accountability mode.
Standard-mode agents cannot submit checkpoints. Logged and enforced agents can.
{
"services_used": ["slack", "gmail"],
"tool_calls": [
{ "service": "slack", "method": "postMessage", "target": "#support" },
{ "service": "gmail", "method": "send" }
],
"actions_count": 5,
"delegated_to": [],
"summary": "Responded to 3 support tickets, sent 2 follow-up emails"
}Returns the checkpoint record with any flags raised by the accountability engine.
Submit a final checkout report when the agent is done using the passport. This is the end-of-session report that triggers the review process for agents in enforced mode. The checkout compares the agent's declared intent against its actual activity.
Standard-mode agents cannot submit a checkout.
{
"services_used": ["slack", "gmail"],
"tool_calls": [
{ "service": "slack", "method": "postMessage" }
],
"actions_count": 12,
"delegated_to": [],
"summary": "Completed support ticket processing session"
}For agents in enforced mode, the checkout triggers an automated review. If critical flags are raised (e.g., undeclared services, missed checkpoints), the agent may be blocked from receiving new passports until an operator approves the review.
Retrieve the full accountability report for a passport, including all checkpoints, the checkout summary, any raised flags, and the review status.
curl https://api.getstack.run/v1/passports/ppt_9xm3kR7wL2/report \
-H "Authorization: Bearer sk_live_op_abc123"List passport checkout reviews that need operator attention. Supports filtering by status and pagination.
curl "https://api.getstack.run/v1/passports/reviews?status=pending&limit=10" \
-H "Authorization: Bearer sk_live_op_abc123"Submit an approval or block decision for a passport checkout review.
{
"decision": "approved",
"notes": "Reviewed activity log, all actions within expected scope",
"block_future": false
}Approving is a governance action: with decision: "approved" and a Bearer credential (API key or OAuth token, including agentic MCP sessions) the call returns 403 GOVERNANCE_APPROVAL_REQUIRED with an approval id. A human approves at /governance/approvals in the dashboard, then the same call is retried with theX-Governance-Approval header.decision: "blocked" is tightening and never steps up; dashboard sessions decide directly. Full protocol: /docs/api/security-events.
List all currently active (non-expired, non-revoked) passports for your operator account. Supports filtering by agent or session.
[
{
"jti": "ppt_9xm3kR7wL2",
"agent_id": "agt_7kx9m2nq4p",
"session_id": "sess_abc123",
"delegation_depth": 0,
"parent_passport_id": null,
"identity_claim_ids": ["clm_9xm3kR7wL2"],
"authority_refs": [{
"binding_id": "abn_tax_filing",
"binding_version": 1,
"binding_claim_id": "pc_...",
"binding_digest": "sha256:...",
"receiver_id": "rcv_tax_agency",
"receiver_profile_version_id": "apv_...",
"expires_at": 1713175100
}],
"intent_summary": "Process support messages",
"intent_services": ["slack"],
"intent_refs": [],
"mission_ids": [],
"estimated_duration_seconds": 1800,
"checkpoint_interval_seconds": 300,
"checkpoint_count": 1,
"last_checkpoint_at": "2026-04-15T10:35:00.000Z",
"issued_at": "2026-04-15T10:30:00.000Z",
"expires_at": "2026-04-15T10:45:00.000Z"
}
]POST /v1/passports/revoke-agent/:agentId - Revoke all active passports for a specific agent.
curl -X POST https://api.getstack.run/v1/passports/revoke-agent/agt_7kx9m2nq4p \
-H "Authorization: Bearer sk_live_op_abc123" \
-H "Content-Type: application/json" \
-d '{ "reason": "Agent compromised" }'POST /v1/passports/revoke-session/:sessionId - Revoke all active passports within a specific session.
curl -X POST https://api.getstack.run/v1/passports/revoke-session/sess_abc123 \
-H "Authorization: Bearer sk_live_op_abc123" \
-H "Content-Type: application/json" \
-d '{ "reason": "Session terminated" }'POST /v1/passports/revoke-all - Revoke every active passport for your entire operator account. Requires explicit confirmation.
{
"confirm": true,
"reason": "Emergency: suspected key compromise"
}{
"success": true,
"revoked_count": 7
}The revoke-all endpoint is an emergency action. It marks every active Passport in the account as revoked, so the next STACK-verified call rejects it. Offline signature-only verification cannot see the change and may accept the token until its signed expiry.
Public endpoint (no authentication required) that returns STACK's Ed25519 public keys in JWKS format. Use this to verify passport signatures offline without calling the verify endpoint.
curl https://api.getstack.run/v1/.well-known/jwks.json