{"openapi":"3.1.0","info":{"title":"AgentSecrets.net API","summary":"Encrypted secrets vault for autonomous AI agents","description":"\nEncrypted secrets vault for autonomous AI agents. Agents can register and fetch credentials\nwithout a human in the loop; a human operator can be handed time-bounded, least-privilege\naccess to a vault through one delegation call.\n\n**Free.** There is no paid tier, no credit card and no trial. The limits reported by\n`GET /v1/info` are anti-abuse quotas, not billing limits.\n\n### Authenticating\n\nEvery authenticated endpoint accepts the token in any of these forms:\n\n| Where | Example |\n| --- | --- |\n| `Authorization` header | `Authorization: Bearer as_live_...` |\n| `X-API-Key` header | `X-API-Key: as_live_...` |\n| Query parameter | `?token=as_live_...` or `?api_key=as_live_...` |\n\nAPI tokens are never stored in a cookie. The browser dashboard authenticates with the\nHttpOnly `as_session` cookie plus the `X-CSRF-Token` header instead, and should read\n`GET /v1/auth/session` for its state.\n\nA token from `POST /v1/auth/register` never expires: an agent has no email, so an expired\ncredential with no recovery phrase would mean a permanently lost vault. A token from\n`POST /v1/auth/login` is valid for 24 hours, and a token delegated with\n`POST /v1/auth/tokens` always carries an explicit `ttl_seconds`. An expired token is\nrefused with HTTP 401 and `\"reason\": \"expired\"`, which is distinguishable from a revoked or\nunknown token (`\"reason\": \"revoked_or_unknown\"`).\n\nGet a token in one request — no credentials required:\n\n```bash\ncurl -s -X POST https://agentsecrets.net/v1/auth/register \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"username\":\"my_agent\",\"password\":\"a-strong-password\"}'\n```\n\n### Storing and reading a secret\n\n```bash\ncurl -s -X POST https://agentsecrets.net/v1/vault/secrets \\\n  -H \"Authorization: Bearer $TOKEN\" -H \"Content-Type: application/json\" \\\n  -d '{\"key\":\"STRIPE_KEY\",\"value\":\"sk_live_...\"}'\n\nexport STRIPE_KEY=$(curl -sf -H \"Authorization: Bearer $TOKEN\" \\\n  https://agentsecrets.net/v1/vault/secrets/STRIPE_KEY/raw)\n```\n\n### Scope restrictions\n\nA token carries a scope that is enforced on every call:\n\n* `full` — everything, including token management.\n* `read_only` — all reads, no writes or deletes.\n* `prefix:<str>` — read and write, but only for keys beginning with `<str>`.\n* `prefix:ro:<str>` — read-only within that prefix.\n\n### Delegating access\n\n`POST /v1/auth/tokens` is the single delegation primitive. It issues a token that is\nnarrower than the caller's own and always carries a deadline:\n\n```bash\ncurl -s -X POST https://agentsecrets.net/v1/auth/tokens \\\n  -H \"Authorization: Bearer $TOKEN\" -H \"Content-Type: application/json\" \\\n  -d '{\"scope\":\"prefix:ro:shared/\",\"ttl_seconds\":3600,\"name\":\"supervisor\"}'\n```\n\n`scope` defaults to `read_only` and `ttl_seconds` is required (clamped to 60..2592000).\nOnly a `full`-scope token may delegate, so a restricted token can never widen its own\nrights. The new token records the issuing token as its `parent_token_id`.\n\n### Connecting over MCP\n\n`GET /mcp/sse` (SSE) and `POST /mcp` (Streamable HTTP) both speak JSON-RPC. Connecting to\neither one **without** credentials and calling a vault method provisions a brand-new isolated\nvault rather than exposing an existing one; discovery methods (`initialize`, `tools/list`,\n`prompts/list`, `resources/list`) are answered without provisioning. See `skill.md` for client\nconfiguration.\n\n### Machine-readable files\n\n* [`/skill.md`](/skill.md) — what an agent should read first\n* [`/rules.md`](/rules.md) — operational and security rules\n* [`/llms.txt`](/llms.txt) — compact context for LLMs\n* [`/.well-known/mcp/server-card.json`](/.well-known/mcp/server-card.json) — MCP tool, prompt and resource inventory\n* [`/v1/ecosystem`](/v1/ecosystem) — index of everything above\n","contact":{"name":"AgentSecrets.net","url":"https://agentsecrets.net/","email":"support@agentsecrets.net"},"license":{"name":"MIT","url":"https://agentsecrets.net/legal"},"version":"0.3.0"},"servers":[{"url":"https://agentsecrets.net","description":"This deployment"}],"paths":{"/health":{"get":{"tags":["Health"],"summary":"Health Check","description":"Liveness probe used by the container orchestrator and by uptime monitors. Returns the service name, the environment it is running in, and the reported version. It does not touch the database, so a healthy answer means the process is up rather than that every dependency is reachable.","operationId":"health_check_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1":{"get":{"tags":["Discovery"],"summary":"API v1 Root Discovery","description":"Returns public API capabilities, status, and direct resource links.","operationId":"api_v1_root_v1_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/mcp/server-card.json":{"get":{"tags":["Discovery"],"summary":"MCP Static Server Card (SEP-1649)","description":"Static MCP capability declaration enabling instant indexing by registries (Smithery, Glama) without scanning.","operationId":"mcp_server_card__well_known_mcp_server_card_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/metrics":{"get":{"tags":["Monitoring"],"summary":"Prometheus Metrics (admin)","description":"Exposes real-time traffic, latency, status distributions, and server load metrics in Prometheus text format. Restricted to an account carrying the `is_admin` flag; every other caller, including anonymous scrapers, receives 404 rather than 403. Prometheus must therefore be configured to send credentials (Bearer token, X-API-Key or ?token=).","operationId":"prometheus_metrics_metrics_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]}},"/v1/system/metrics":{"get":{"tags":["Monitoring"],"summary":"System & Traffic Metrics (admin)","description":"Returns live system resource usage (CPU, RAM), request rates, top client IPs, user agents, and endpoint analytics in JSON. Restricted to an account carrying the `is_admin` flag; every other caller, including anonymous ones, receives 404 rather than 403.","operationId":"system_metrics_v1_system_metrics_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]}},"/v1/system/front-server-stats":{"get":{"tags":["Monitoring"],"summary":"Public Front-Server Statistics","description":"Public, unauthenticated aggregate counters of the front server: operations per minute, secrets stored, active agent sessions, uptime and payload limits. It carries no client data — no IP addresses, user agents, countries or per-caller breakdowns — unlike the admin-only `GET /v1/system/metrics`.","operationId":"front_server_stats_v1_system_front_server_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/legal":{"get":{"tags":["Ecosystem"],"summary":"Legal Information & Terms","description":"Returns licensing, terms of service, and privacy policy for AgentSecrets.net.","operationId":"legal_info_legal_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/auth/register":{"post":{"tags":["Authentication"],"summary":"Instant User & Agent Registration","description":"Instantly registers a human or autonomous AI agent with zero email, SMS, or KYC. Returns a 12-word recovery seed phrase.","operationId":"register_v1_auth_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserRegisterRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/auth/login":{"post":{"tags":["Authentication"],"summary":"User & Agent Login","description":"Authenticates with username and password and issues a fresh Bearer API token valid for 24 hours. Older tokens are left alone: expiry, not pruning, is what ends a login token's life.","operationId":"login_v1_auth_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserLoginRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/auth/tokens/rotate":{"post":{"tags":["Authentication"],"summary":"Rotate API Token","description":"Revokes current active full-access master tokens and issues a fresh Bearer API token. Scoped worker tokens are preserved.","operationId":"rotate_token_v1_auth_tokens_rotate_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenRotateResponse"}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]}},"/v1/auth/me":{"get":{"tags":["Authentication"],"summary":"Current User Profile & Status","description":"Returns authenticated user details and active secret statistics.","operationId":"get_me_v1_auth_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserMeResponse"}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]}},"/v1/auth/session":{"get":{"tags":["Authentication"],"summary":"Browser Session Status","description":"Returns the profile of the user behind the `as_session` browser cookie, using the same payload as `GET /v1/auth/me`. The dashboard calls this on load to find out whether the browser still holds a live session. Responds 401 when the cookie is absent, unknown or expired. Bearer API clients should call `/v1/auth/me`.","operationId":"get_session_v1_auth_session_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserMeResponse"}}}}}}},"/v1/auth/recover":{"post":{"tags":["Authentication"],"summary":"Account Recovery With Recovery Phrase","description":"Resets account password using the 12-word mnemonic seed phrase or recovery token issued during registration. Like login and registration, a successful recovery also signs the browser in: it creates a session row and sets the `as_session` / `as_csrf` cookies, so the dashboard redirect lands signed in.","operationId":"recover_account_v1_auth_recover_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserRecoverRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/auth/tokens":{"get":{"tags":["Authentication"],"summary":"List API Tokens","description":"Lists all active API tokens for the authenticated user, including scopes and prefixes.","operationId":"list_tokens_v1_auth_tokens_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/TokenResponse"},"type":"array","title":"Response List Tokens V1 Auth Tokens Get"}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]},"post":{"tags":["Authentication"],"summary":"Delegate a Time-Bounded Token","description":"The single delegation primitive: issues a token for a sub-agent, human operator or supervisor that is narrower than the caller's own and always carries a deadline. `scope` defaults to `read_only` (least privilege); `ttl_seconds` is required and is clamped to 60..2592000. The new token records provenance in `parent_token_id` — the calling token, or the account's principal token when the caller is a browser session. Only a token whose scope is exactly `full` may delegate, so a restricted token can never widen its own rights.","operationId":"create_scoped_token_v1_auth_tokens_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenCreateRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenMintResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]}},"/v1/auth/tokens/{token_id}":{"delete":{"tags":["Authentication"],"summary":"Revoke API Token","description":"Deactivates an active API token by ID.","operationId":"revoke_token_v1_auth_tokens__token_id__delete","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"token_id","in":"path","required":true,"schema":{"type":"string","title":"Token Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/auth/logout":{"post":{"tags":["Authentication"],"summary":"Log Out","description":"Revokes the server-side browser session referenced by the `as_session` cookie and clears both session cookies, so the dashboard cannot be reopened from this browser. The response shape is unchanged; the long-lived Bearer token itself is not revoked.","operationId":"logout_v1_auth_logout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/auth/profile/notes":{"get":{"tags":["Authentication"],"summary":"Get Agent Profile Notes & Useful Links","description":"Retrieves and decrypts the authenticated agent's personal profile notes, description, and useful reference links.","operationId":"get_user_notes_v1_auth_profile_notes_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserNotesResponse"}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]},"put":{"tags":["Authentication"],"summary":"Update Agent Profile Notes & Useful Links","description":"Encrypts (AES-256-GCM) and stores personal description, scratchpad notes, or reference links for the authenticated user/agent.","operationId":"update_user_notes_v1_auth_profile_notes_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserNotesUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserNotesResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]}},"/v1/account/password":{"post":{"tags":["Account"],"summary":"Change Account Password","description":"Replaces the account password after proving knowledge of the current one.","operationId":"change_password_v1_account_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]}},"/v1/account/session-policy":{"put":{"tags":["Account"],"summary":"Choose Browser Session Auto-Expiry","description":"Stores the session auto-expiry choice. 'browser_close' takes effect on the next\nsign-in, when the server issues a session cookie with no max-age; 'idle_5m' is\nenforced client-side by the dashboard's inactivity timer.","operationId":"set_session_policy_v1_account_session_policy_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionPolicyRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]}},"/v1/account":{"delete":{"tags":["Account"],"summary":"Delete Account","description":"Deletes the signed-in account. The target is always `current_user` — the account\nbehind the session cookie — never an id supplied by the client, so no caller can\ndelete another account.\n\n`account_vault` deletes the account, its secrets, tokens, notes and sessions;\nshares this account issued are removed (cascade) and shares it accepted stop\nlisting it as the acceptor.\n\n`account_vault_shares` additionally revokes the credentials minted for shares this\naccount accepted, so those shares are closed on both sides.","operationId":"delete_account_v1_account_delete","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountDeleteRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]}},"/v1/handoff":{"get":{"tags":["Handoff"],"summary":"List Handoff Relationships","description":"Returns the caller's relationships in both directions. `outgoing` lists every grant the caller issued, in any state, with a derived `status` (`pending`, `expired`, `accepted` or `revoked`) and the acceptor when there is one. `incoming` lists the live relationships the caller accepted — grants that are accepted, not revoked and still backed by a token — each with the vault it reaches and the token it runs on. A revoked relationship disappears from `incoming`; the grantor still sees it in `outgoing` as `revoked`.","operationId":"list_handoffs_v1_handoff_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HandoffListResponse"}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]},"post":{"tags":["Handoff"],"summary":"Mint a Single-Use Handoff Code","description":"Creates a code another entity can redeem to operate on this vault. The code is returned exactly once, never stored in the clear, and is valid for ten minutes. Redeeming it mints a delegated token that belongs to the **caller's** account with the requested `scope` and `ttl_seconds`, so the caller's own credential is never handed over. A code is not a credential: presenting it as a Bearer token is a 401. Only a token whose scope is exactly `full` may mint a handoff, exactly like `POST /v1/auth/tokens`, so a restricted delegation cannot widen itself this way.","operationId":"create_handoff_v1_handoff_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HandoffCreateRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HandoffCreateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]}},"/v1/handoff/accept":{"post":{"tags":["Handoff"],"summary":"Accept a Handoff Code","description":"Redeems a single-use `hs_...` code and returns a working delegated token for the grantor's vault. The token belongs to the grantor's account, carries the grant's scope and TTL, and is the acceptor's credential from then on. Accepting also marks the grantor's account as claimed by the acceptor. Any authenticated entity may accept: a Bearer token or a browser session cookie with its CSRF header. Unknown, expired, already-accepted and revoked codes all answer 404 with one message, so the endpoint cannot be used to probe codes; accepting your own code answers 409.","operationId":"accept_handoff_v1_handoff_accept_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HandoffAcceptRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HandoffAcceptResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]}},"/v1/handoff/{grant_id}":{"delete":{"tags":["Handoff"],"summary":"Revoke a Handoff Relationship","description":"Ends a handoff. Either side may revoke: the account that minted the code or the account that accepted it. Setting `revoked_at` also deactivates the token the grant minted, so dropping the relationship kills the credential with it — a delegated token cannot outlive the relationship it came from. Revoking twice is idempotent and answers the same thing; an unknown id, or one the caller is not part of, answers 404.","operationId":"revoke_handoff_v1_handoff__grant_id__delete","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"grant_id","in":"path","required":true,"schema":{"type":"string","title":"Grant Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HandoffRevokeResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/handoff/{grant_id}/record":{"delete":{"tags":["Handoff"],"summary":"Delete a Handoff Record","description":"Removes an ENDED grant from the issuer's own history. Revoking ends the access but keeps the row, so `outgoing` grows without bound and every code that was minted and forgotten stays in it forever; this is the way to clear those out.\n\nOnly the account that issued the grant may delete its record, and only once the grant is `revoked` or `expired` — a grant that still grants something answers 409, because deleting the row must never be a way to skip revoking the credential behind it. Revoke first, then delete.\n\nCredentials are untouched: the token the grant minted was already deactivated by the revoke, and `GET /v1/auth/tokens` lists active tokens only, so it is absent from that list before and after this call. An unknown id, or one issued by another account, answers 404.","operationId":"delete_handoff_record_v1_handoff__grant_id__record_delete","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"grant_id","in":"path","required":true,"schema":{"type":"string","title":"Grant Id"}}],"responses":{"200":{"description":"The record was removed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HandoffRecordDeletedResponse"}}}},"404":{"description":"No such grant, or it belongs to another account. The two are indistinguishable on purpose."},"409":{"description":"The grant is still `pending` or `accepted`, so it grants access. Revoke it first (DELETE /v1/handoff/{grant_id}), then delete the record."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/shared/vaults":{"get":{"tags":["Shared Vaults"],"summary":"Vaults Shared With This Session","description":"Lists the hand-off grants this signed-in account accepted that are still live: the grantor, the scope the code carried, when the credential expires and how many active secrets that vault holds. Read with the session cookie; a Bearer token is refused because it already has its own access.","operationId":"list_shared_vaults_v1_shared_vaults_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/SharedVaultResponse"},"type":"array","title":"Response List Shared Vaults V1 Shared Vaults Get"}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]}},"/v1/shared/vaults/{grant_id}/keys":{"get":{"tags":["Shared Vaults"],"summary":"Keys In A Vault Shared With This Session","description":"Lists the active keys of the vault a hand-off shared with this account, with the same metadata `/v1/vault/keys` returns and confined to the scope the code carried. The grantor's own credential is never involved.","operationId":"shared_vault_keys_v1_shared_vaults__grant_id__keys_get","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"grant_id","in":"path","required":true,"schema":{"type":"string","title":"Grant Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SecretMetaResponse"},"title":"Response Shared Vault Keys V1 Shared Vaults  Grant Id  Keys Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/shared/vaults/{grant_id}/secrets/{key}/raw":{"get":{"tags":["Shared Vaults"],"summary":"Read One Value From A Shared Vault","description":"Returns one value from the vault a hand-off shared with this account, as text/plain. A key outside the grant's scope answers 403 and a missing key answers a plain-text 404, exactly as the equivalent route on the owner's vault does.","operationId":"shared_vault_raw_v1_shared_vaults__grant_id__secrets__key__raw_get","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"grant_id","in":"path","required":true,"schema":{"type":"string","title":"Grant Id"}},{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":128,"title":"Key"}}],"responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/shared/vaults/{grant_id}/secrets":{"post":{"tags":["Shared Vaults"],"summary":"Store A Secret In A Shared Vault","description":"Creates or updates a key in the vault a hand-off shared with this account. The scope the code carried decides what happens: `full` may write anywhere in that vault, `prefix:<p>/` only under its prefix (403 outside it), and `read_only` / `prefix:ro:<p>/` are refused with 403. The grantor's own credential is never involved.","operationId":"shared_vault_create_v1_shared_vaults__grant_id__secrets_post","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"grant_id","in":"path","required":true,"schema":{"type":"string","title":"Grant Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretCreateRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/shared/vaults/{grant_id}/secrets/{key}":{"put":{"tags":["Shared Vaults"],"summary":"Update A Secret In A Shared Vault","description":"Sets the value of an existing key in the shared vault, with the same scope rules and the same version history as the owner's own `/v1/vault/secrets/{key}` route.","operationId":"shared_vault_update_v1_shared_vaults__grant_id__secrets__key__put","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"grant_id","in":"path","required":true,"schema":{"type":"string","title":"Grant Id"}},{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":128,"title":"Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Shared Vaults"],"summary":"Delete A Secret From A Shared Vault","description":"Permanently deletes a key from the shared vault. A `full` grant may delete anything the owner has; a `prefix:<p>/` grant only inside its prefix; read-only grants are refused.","operationId":"shared_vault_delete_v1_shared_vaults__grant_id__secrets__key__delete","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"grant_id","in":"path","required":true,"schema":{"type":"string","title":"Grant Id"}},{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":128,"title":"Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretDeleteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/vault/secrets":{"post":{"tags":["Vault"],"summary":"Store or Update a Secret","description":"Encrypts and stores a new secret or updates an existing key. Supports text, JSON, TTL, environment, webhook, and burn-after-reading.","operationId":"create_or_update_secret_v1_vault_secrets_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretCreateRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]}},"/v1/vault/import":{"post":{"tags":["Vault"],"summary":"Bulk Import Secrets","description":"Stores a list of secrets in one request. Every entry is re-validated with the same bounds as a single store, and the request body must stay under 5 MB. The browser parses the source file (format and its own 5 MB check) before posting this list.","operationId":"import_secrets_v1_vault_import_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretImportRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]}},"/v1/vault/export":{"get":{"tags":["Vault"],"summary":"Bulk Export Secrets","description":"Exports active secrets as JSON or shell 'export KEY=VAL' lines. Filterable by environment.","operationId":"export_secrets_v1_vault_export_get","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"format","in":"query","required":false,"schema":{"type":"string","description":"'shell' (export KEY=VAL) or 'json'","default":"shell","title":"Format"},"description":"'shell' (export KEY=VAL) or 'json'"},{"name":"environment","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by environment (e.g. 'production', 'staging', 'dev')","title":"Environment"},"description":"Filter by environment (e.g. 'production', 'staging', 'dev')"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/vault/keys":{"get":{"tags":["Vault"],"summary":"List Secret Keys & Metadata","description":"Returns active secret keys and metadata (expiration, burn status, environment) without decrypting values. Respects token prefix restrictions.","operationId":"list_keys_v1_vault_keys_get","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"environment","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional deprecated environment filter","title":"Environment"},"description":"Optional deprecated environment filter"},{"name":"tag","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional tag filter","title":"Tag"},"description":"Optional tag filter"},{"name":"expiring_within","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Filter keys expiring within N seconds","title":"Expiring Within"},"description":"Filter keys expiring within N seconds"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SecretMetaResponse"},"title":"Response List Keys V1 Vault Keys Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/vault/tags":{"get":{"tags":["Vault"],"summary":"List Account Tags","description":"Returns the account's distinct tags and how many secrets carry each.","operationId":"list_tags_v1_vault_tags_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]}},"/v1/vault/tags/{tag}":{"delete":{"tags":["Vault"],"summary":"Remove a Tag Everywhere","description":"Removes one tag from every secret that carries it.","operationId":"delete_tag_v1_vault_tags__tag__delete","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"tag","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":20,"title":"Tag"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/vault/secrets/{key}/raw":{"put":{"tags":["Vault"],"summary":"Set Secret from Raw Body (cURL-friendly)","description":"Convenience endpoint to store raw text passed in the request body (e.g. cat secret.txt | curl -X PUT ...).","operationId":"put_secret_raw_v1_vault_secrets__key__raw_put","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":128,"title":"Key"}},{"name":"ttl_seconds","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Optional TTL in seconds","title":"Ttl Seconds"},"description":"Optional TTL in seconds"},{"name":"burn_after_read","in":"query","required":false,"schema":{"type":"boolean","description":"Burn after first read","default":false,"title":"Burn After Read"},"description":"Burn after first read"},{"name":"environment","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional environment tag: 'production', 'staging', 'dev'","title":"Environment"},"description":"Optional environment tag: 'production', 'staging', 'dev'"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Vault"],"summary":"Retrieve Raw Secret Value","description":"Returns the raw, decrypted secret value as text/plain. Perfect for shell variable capture: export KEY=$(curl ...)","operationId":"get_secret_raw_v1_vault_secrets__key__raw_get","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":128,"title":"Key"}}],"responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/vault/secrets/{key}/rollback":{"post":{"tags":["Vault"],"summary":"Roll Back Secret to Previous Version","description":"Reverts secret content to its previous version snapshot.","operationId":"rollback_secret_v1_vault_secrets__key__rollback_post","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":128,"title":"Key"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/SecretRollbackRequest"},{"type":"null"}],"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretRollbackResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/vault/secrets/{key}":{"put":{"tags":["Vault"],"summary":"Set Secret by Key","description":"Idempotently sets a secret for the specified key identifier.","operationId":"put_secret_v1_vault_secrets__key__put","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":128,"title":"Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Vault"],"summary":"Retrieve Secret","description":"Retrieves and decrypts the secret. If burn_after_read was set, it is deleted immediately. If Accept: text/plain is passed, returns raw string.","operationId":"get_secret_v1_vault_secrets__key__get","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":128,"title":"Key"}},{"name":"accept","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Vault"],"summary":"Delete a Secret","description":"Permanently removes a secret from the vault.","operationId":"delete_secret_v1_vault_secrets__key__delete","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":128,"title":"Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretDeleteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/vault/secret-versions/{key}":{"get":{"tags":["Vault"],"summary":"List Secret Version History","description":"Lists the archived snapshots kept for a secret (newest first) with their timestamps. The vault keeps the three most recent snapshots per key; restore one with POST /v1/vault/secrets/{key}/rollback. Values are never returned here.","operationId":"list_secret_versions_v1_vault_secret_versions__key__get","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":128,"title":"Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/vault/secrets/bulk-delete":{"post":{"tags":["Vault"],"summary":"Delete Several Secrets in One Request","description":"Deletes up to 200 keys of the caller's own vault in one call. Keys that do not exist — or belong to another account — are listed in `not_found` instead of failing the request. Exists so a dashboard select-all delete costs one rate-limit slot rather than one per key. A read-only token is refused, and a prefix-scoped token may only delete inside its prefix.","operationId":"bulk_delete_secrets_v1_vault_secrets_bulk_delete_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretBulkDeleteRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretBulkDeleteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]}},"/v1/agent/context":{"get":{"tags":["Agent Ergonomics"],"summary":"Agent Session Context & Dashboard","description":"One-call session startup inspection returning identity, token scope, quota, expiring keys, recent keys, and prioritized next actions. Every key-derived field (`recent_keys`, `expiring_soon`, `vault.secrets_count`, `vault.quota_remaining`, `vault.storage`) is confined to the calling token's `prefix:` scope, exactly like `GET /v1/vault/keys` and the MCP `get_agent_context` tool, so a scoped token never learns about keys it may not read. `vault.storage` reports measured bytes: the ciphertext holding every secret value, the plaintext lookup columns (key names and tags), and the stored plaintext secret values.","operationId":"get_agent_context_v1_agent_context_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Get Agent Context V1 Agent Context Get"}}}}},"security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}]}},"/v1/info":{"get":{"tags":["Agent Ergonomics"],"summary":"Public Service Capabilities & Manifest Discovery","description":"Unauthenticated endpoint providing service version, capabilities, operational limits, and specification links.","operationId":"get_service_info_v1_info_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Get Service Info V1 Info Get"}}}}}}},"/llms.txt":{"get":{"tags":["AI Ergonomics & Ecosystem"],"summary":"LLM Documentation File","description":"Compact plain-text context for language models: what this service is, how to register, how to store and read secrets, and where the MCP endpoints live. Served as text/markdown.","operationId":"get_llms_txt_llms_txt_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/llms-full.txt":{"get":{"tags":["AI Ergonomics & Ecosystem"],"summary":"Full LLM Documentation File","description":"The extended version of /llms.txt: complete request and response examples for every agent-facing workflow, scope rules, error semantics and MCP tool inventory.","operationId":"get_llms_full_txt_llms_full_txt_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/skill.md":{"get":{"tags":["AI Ergonomics & Ecosystem"],"summary":"Agent Skill Specification (SKILL.md)","description":"The document an autonomous agent is expected to read first: registration, credential persistence, MCP connection, scope handling and the exact rules for storing secrets. Plain markdown, no authentication required.","operationId":"get_skill_md_skill_md_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/skill.json":{"get":{"tags":["AI Ergonomics & Ecosystem"],"summary":"Machine-Readable Agent Skill Manifest","description":"The machine-readable companion to skill.md: service metadata, authentication options, transports, the full MCP tool list with input schemas, limits and the pricing block.","operationId":"get_skill_json_skill_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/rules.md":{"get":{"tags":["AI Ergonomics & Ecosystem"],"summary":"Agent Operational & Security Rules","description":"The operational contract for agents using this vault: what may be stored, how scoped tokens must be used, how to handle TTL and burn-after-read secrets, and what an agent must never do with a retrieved value.","operationId":"get_rules_md_rules_md_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/heartbeat.md":{"get":{"tags":["AI Ergonomics & Ecosystem"],"summary":"Agent Liveness & Heartbeat Protocol","description":"How an agent signals that it is still alive, and how a supervisor detects a dead worker: heartbeat keys with TTL, the interval to refresh them, and how to interpret a missing key.","operationId":"get_heartbeat_md_heartbeat_md_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/.well-known/ai-plugin.json":{"get":{"tags":["AI Ergonomics & Ecosystem"],"summary":"OpenAI AI Plugin Manifest","description":"Manifest in the OpenAI plugin format describing the service for model-facing tooling, including the instructions a model should follow when it needs a credential.","operationId":"get_ai_plugin_json__well_known_ai_plugin_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/ecosystem":{"get":{"tags":["AI Ergonomics & Ecosystem"],"summary":"Agent Ecosystem Specification Index","description":"Machine-readable index of every file and endpoint this service publishes for agents: specification documents, discovery manifests, MCP artefacts and API entry points, each with a stable id, URL and short description. Built for automatic discovery rather than for humans.","operationId":"get_ecosystem_index_v1_ecosystem_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/oauth-protected-resource":{"get":{"tags":["OAuth Discovery"],"summary":"OAuth 2.0 Protected Resource Metadata (RFC 9728)","description":"Advertises AgentSecrets as the authorization server for the MCP endpoint, so MCP clients and directories can complete discovery without an interactive flow.","operationId":"oauth_protected_resource__well_known_oauth_protected_resource_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/oauth-authorization-server":{"get":{"tags":["OAuth Discovery"],"summary":"OAuth 2.0 Authorization Server Metadata (RFC 8414)","description":"Describes how an agent obtains a bearer token: one unauthenticated POST.","operationId":"oauth_authorization_server__well_known_oauth_authorization_server_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/mcp/sse":{"get":{"tags":["Model Context Protocol (Remote SSE)"],"summary":"Establish MCP SSE Connection","description":"Establishes a persistent Server-Sent Events (SSE) connection for Model Context Protocol.\n\n**Authentication is OPTIONAL on this endpoint.**\n- With `Authorization: Bearer <token>` or `X-API-Key: <token>`: connects to that vault.\n- Without any credentials: provisions a NEW, isolated autonomous vault for this session and\n  returns its token through the `get_my_credentials` tool. No existing vault is ever exposed\n  by an anonymous connection.\n\nAnonymous provisioning is rate limited per client IP (`mcp_autonomous_limit_per_hour_per_ip`\nin `GET /v1/info`) and responses carry `X-AgentSecrets-Mode: autonomous-provisioned` so callers\nand auditors can tell an intentional zero-config session from an unauthenticated one.\n\n**Asynchronous Semantics:**\n- Upon connection, the server immediately emits an `endpoint` event containing the POST URI: `event: endpoint\\ndata: /mcp/messages?sessionId=<uuid>\\n\\n`.\n- **The session lives exactly as long as this stream.** Keep the SSE response open for the\n  whole conversation; reading the `endpoint` event and then closing the stream (a short-lived\n  probe, a dropped response object) destroys the session and the advertised POST URL starts\n  answering 404.\n- Messages posted to `/mcp/messages?sessionId=<uuid>` return `{\"status\": \"accepted\"}` immediately.\n- The actual JSON-RPC response is delivered asynchronously over this SSE stream (`event: message\\ndata: {...}\\n\\n`).\n- Keepalive comments (`: ping\\n\\n`) are sent every 20 seconds to prevent reverse-proxy timeouts.\n\n**Origin Validation:** Origin header is validated against DNS rebinding per the MCP specification.","operationId":"mcp_sse_connect_mcp_sse_get","responses":{"200":{"description":"SSE stream established. Delivers JSON-RPC events and keepalive pings. Anonymous sessions carry `X-AgentSecrets-Mode: autonomous-provisioned`.","headers":{"X-AgentSecrets-Mode":{"description":"Present with the value `autonomous-provisioned` when the session was created without credentials, i.e. a new isolated vault was provisioned rather than an existing one being accessed.","schema":{"type":"string","example":"autonomous-provisioned"}}},"content":{"text/event-stream":{"schema":{"type":"string","example":"event: endpoint\ndata: /mcp/messages?sessionId=...\n\n"}}}},"401":{"description":"Only returned when credentials are supplied but invalid."},"403":{"description":"Forbidden (untrusted Origin)"},"429":{"description":"Too many autonomous agent vaults created from this IP"}},"security":[]},"post":{"tags":["Model Context Protocol (Remote SSE)"],"summary":"Direct MCP JSON-RPC over HTTP (Streamable HTTP)","description":"Processes direct MCP JSON-RPC POST requests per Streamable HTTP specification.","operationId":"mcp_direct_jsonrpc_mcp_sse_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/mcp":{"get":{"tags":["Model Context Protocol (Remote SSE)"],"summary":"MCP SSE Stream (Streamable HTTP entry point)","description":"The MCP endpoint itself, speaking Server-Sent Events. Identical wire format to `GET /mcp/sse` (`event: endpoint` then JSON-RPC replies as `event: message`), so a client that probes the canonical `/mcp` URL finds the transport instead of a 405.\n\n**No vault is created here.** Unlike `/mcp/sse`, an anonymous connection to this endpoint only opens a stream. A vault is provisioned lazily, at the moment a message actually needs one, so health checks and directory scanners do not consume the per-IP autonomous quota (`mcp_autonomous_limit_per_hour_ip` in `GET /v1/info`).\n\nCredentials are optional and, when supplied, must be valid.","operationId":"mcp_stream_endpoint_mcp_get","responses":{"200":{"description":"SSE stream established.","headers":{"X-AgentSecrets-Mode":{"description":"`authenticated` when credentials were supplied, `autonomous-on-demand` when the session starts without a vault and provisions one only if a message requires it.","schema":{"type":"string","example":"autonomous-on-demand"}}},"content":{"text/event-stream":{"schema":{"type":"string","example":"event: endpoint\ndata: /mcp/messages?sessionId=...\n\n"}}}},"401":{"description":"Credentials were supplied but are invalid."},"403":{"description":"Forbidden (untrusted Origin)"},"429":{"description":"Too many autonomous agent vaults created from this IP"}},"security":[]},"post":{"tags":["Model Context Protocol (Remote SSE)"],"summary":"Direct MCP JSON-RPC over HTTP (Streamable HTTP)","description":"Processes direct MCP JSON-RPC POST requests per Streamable HTTP specification.\n\n**Authentication is OPTIONAL.** `initialize`, `ping`, `tools/list`, `prompts/list`, `prompts/get`, `resources/list` and `resources/templates/list` are answered without credentials — they describe the server and expose no vault data, so they never provision anything.\n\n**Without any credentials, a vault method auto-provisions a new isolated vault** — exactly like `GET /mcp/sse`. `tools/call` and `resources/read` from an anonymous caller create a brand-new agent account, execute against it, and the response carries `X-AgentSecrets-Mode: autonomous-provisioned`. Because this transport keeps no session between requests, that same response also hands back the freshly minted token (a text line plus `agent_token` / `vault_provisioned` / `vault_note` in `structuredContent`, or in `error.data` for a JSON-RPC error): send it as `Authorization: Bearer <token>` on every later call, otherwise the next credential-less call reaches a DIFFERENT, empty vault. No existing vault is ever reachable anonymously. Provisioning is rate limited per client IP (`mcp_autonomous_limit_per_hour_per_ip` in `GET /v1/info`), the same quota the SSE transport consumes.\n\n**Invalid credentials are always an error.** If a token is supplied it must be valid; a bad token returns 401 rather than silently degrading to an anonymous call or provisioning a vault.","operationId":"mcp_direct_jsonrpc_mcp_post","responses":{"200":{"description":"JSON-RPC reply. Responses carry `X-AgentSecrets-Mode`: `autonomous-provisioned` when the call just created a vault, `authenticated` when a token was used, and `autonomous-on-demand` for a credential-less public method that created nothing.","headers":{"X-AgentSecrets-Mode":{"description":"How the caller was identified for this request: `autonomous-provisioned`, `authenticated` or `autonomous-on-demand`.","schema":{"type":"string","example":"autonomous-provisioned"}}},"content":{"application/json":{"schema":{}}}},"401":{"description":"A token was supplied but is invalid or revoked"},"403":{"description":"Forbidden (untrusted Origin)"},"429":{"description":"Too many autonomous agent vaults created from this IP"}},"security":[]}},"/mcp/messages":{"post":{"tags":["Model Context Protocol (Remote SSE)"],"summary":"Post MCP JSON-RPC Message","description":"Submits a JSON-RPC message (initialize, tools/list, tools/call) for an active MCP session.\n\n**Asynchronous Semantics:**\n- This endpoint accepts the message and returns `{\"status\": \"accepted\"}` immediately.\n- The actual JSON-RPC result or error is sent asynchronously over the active SSE stream established via `GET /mcp/sse`.\n\n**Scope Enforcement:** Scoped delegation tokens (`read_only`, `prefix:...`) are strictly enforced for all tool calls.","operationId":"mcp_post_message_mcp_messages_post","security":[{"HTTPBearer":[]},{"APIKeyHeader":[]}],"parameters":[{"name":"sessionId","in":"query","required":true,"schema":{"type":"string","title":"Sessionid"}}],"responses":{"200":{"description":"Message accepted. Response is delivered asynchronously over SSE stream.","content":{"application/json":{"schema":{},"example":{"status":"accepted"}}}},"400":{"description":"Invalid JSON or missing fields"},"401":{"description":"Missing or invalid Bearer token / X-API-Key"},"403":{"description":"Forbidden (untrusted Origin or insufficient scope)"},"404":{"description":"Session not found or expired: the SSE stream that created the session is closed, the server restarted, or the POST reached a different worker process than the one holding the stream"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AccountDeleteRequest":{"properties":{"mode":{"type":"string","title":"Mode","description":"'account_vault' or 'account_vault_shares'","default":"account_vault"}},"type":"object","title":"AccountDeleteRequest"},"AuthResponse":{"properties":{"status":{"type":"string","title":"Status","description":"Status code string","default":"success"},"user_id":{"type":"string","title":"User Id","description":"Unique user GUID"},"username":{"type":"string","title":"Username","description":"Registered username"},"api_token":{"type":"string","title":"Api Token","description":"Persistent Bearer token for autonomous agents"},"recovery_phrase":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recovery Phrase","description":"12-word mnemonic recovery phrase. Store offline."},"recovery_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recovery Token","description":"Direct recovery token string"},"created_at":{"type":"string","title":"Created At","description":"Account creation timestamp"}},"type":"object","required":["user_id","username","api_token","created_at"],"title":"AuthResponse"},"ChangePasswordRequest":{"properties":{"current_password":{"type":"string","maxLength":128,"minLength":1,"title":"Current Password","description":"The account's current password"},"new_password":{"type":"string","maxLength":128,"minLength":4,"title":"New Password","description":"The replacement password"}},"type":"object","required":["current_password","new_password"],"title":"ChangePasswordRequest"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HandoffAcceptRequest":{"properties":{"code":{"type":"string","maxLength":128,"minLength":1,"title":"Code","description":"The handoff code from POST /v1/handoff, e.g. 'hs_...'. Valid for ten minutes."}},"type":"object","required":["code"],"title":"HandoffAcceptRequest","description":"Body of `POST /v1/handoff/accept`: redeem a single-use `hs_...` code."},"HandoffAcceptResponse":{"properties":{"status":{"type":"string","title":"Status","default":"accepted"},"vault":{"$ref":"#/components/schemas/HandoffVaultSummary"},"token":{"$ref":"#/components/schemas/HandoffMintedToken"},"grant_id":{"type":"string","title":"Grant Id","description":"The grant this acceptance created. Either side ends it with `DELETE /v1/handoff/{grant_id}`, which also revokes the token above."}},"type":"object","required":["vault","token","grant_id"],"title":"HandoffAcceptResponse","description":"Response of `POST /v1/handoff/accept`."},"HandoffAcceptedBy":{"properties":{"user_id":{"type":"string","title":"User Id"},"username":{"type":"string","title":"Username"}},"type":"object","required":["user_id","username"],"title":"HandoffAcceptedBy","description":"The account that redeemed an outgoing grant's code."},"HandoffCreateRequest":{"properties":{"scope":{"type":"string","maxLength":64,"title":"Scope","description":"Scope of the token the acceptor receives: 'full', 'read_only', 'prefix:<str>' or 'prefix:ro:<str>'. Defaults to 'read_only' (least privilege).","default":"read_only"},"ttl_seconds":{"type":"integer","minimum":1.0,"title":"Ttl Seconds","description":"Lifetime of the token minted at acceptance, in seconds. Defaults to 86400 (24 hours). Values below 60 are raised to 60 and values above 2592000 (30 days) are lowered to 2592000.","default":86400},"code_ttl_seconds":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Code Ttl Seconds","description":"How long the code itself stays redeemable, in seconds. Defaults to 600 (ten minutes). Clamped to 60..2592000 like the token lifetime. A long window means a leaked code keeps working for that long, so raise it only when the code has to travel through something slow, such as e-mail."},"name":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Name","description":"Optional label for this handoff, reused as the minted token's name."}},"type":"object","title":"HandoffCreateRequest","description":"Body of `POST /v1/handoff`: mint a single-use code another entity can redeem.\n\n`scope` and `ttl_seconds` describe the credential the *acceptor* will receive.\n`code_ttl_seconds` is the code's own life — the window in which it can still be\nredeemed — and defaults to ten minutes. It exists because a code sent by e-mail is\nroutinely read long after ten minutes, and a deadline the sender cannot move makes the\ne-mail hand-off unusable; the cost of a longer window is that a leaked code stays\nliveable longer, so the default stays short and extending it is a deliberate act."},"HandoffCreateResponse":{"properties":{"code":{"type":"string","title":"Code","description":"Raw handoff code. Returned exactly once: only its SHA-256 hash is stored, so it can never be read back. Give it to the person who should receive access."},"grant_id":{"type":"string","title":"Grant Id","description":"Stable id of the grant, usable with DELETE /v1/handoff/{grant_id}"},"code_expires_at":{"type":"string","title":"Code Expires At","description":"Moment the code stops being redeemable (UTC)"},"scope":{"type":"string","title":"Scope","description":"Scope of the token that will be minted at acceptance"},"token_ttl_seconds":{"type":"integer","title":"Token Ttl Seconds","description":"Lifetime of the token minted at acceptance, in seconds"}},"type":"object","required":["code","grant_id","code_expires_at","scope","token_ttl_seconds"],"title":"HandoffCreateResponse","description":"Response of `POST /v1/handoff`: the code, shown exactly once."},"HandoffIncomingItem":{"properties":{"grant_id":{"type":"string","title":"Grant Id"},"scope":{"type":"string","title":"Scope"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"accepted_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accepted At"},"vault":{"$ref":"#/components/schemas/HandoffIncomingVault"},"token":{"anyOf":[{"$ref":"#/components/schemas/HandoffIncomingToken"},{"type":"null"}]}},"type":"object","required":["grant_id","scope","vault"],"title":"HandoffIncomingItem","description":"A live relationship the caller accepted: a vault they may operate on."},"HandoffIncomingToken":{"properties":{"token_id":{"type":"string","title":"Token Id"},"token_prefix":{"type":"string","title":"Token Prefix"},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At"},"is_active":{"type":"boolean","title":"Is Active","default":true}},"type":"object","required":["token_id","token_prefix"],"title":"HandoffIncomingToken","description":"The delegated token this relationship runs on."},"HandoffIncomingVault":{"properties":{"user_id":{"type":"string","title":"User Id"},"username":{"type":"string","title":"Username"}},"type":"object","required":["user_id","username"],"title":"HandoffIncomingVault","description":"The vault an incoming relationship reaches."},"HandoffListResponse":{"properties":{"outgoing":{"items":{"$ref":"#/components/schemas/HandoffOutgoingItem"},"type":"array","title":"Outgoing"},"incoming":{"items":{"$ref":"#/components/schemas/HandoffIncomingItem"},"type":"array","title":"Incoming"}},"type":"object","title":"HandoffListResponse","description":"Response of `GET /v1/handoff`: the caller's relationships, both directions."},"HandoffMintedToken":{"properties":{"api_token":{"type":"string","title":"Api Token","description":"Raw Bearer token, returned exactly once. It operates on the grantor's vault."},"token_prefix":{"type":"string","title":"Token Prefix"},"token_id":{"type":"string","title":"Token Id"},"scope":{"type":"string","title":"Scope"},"expires_at":{"type":"string","title":"Expires At"}},"type":"object","required":["api_token","token_prefix","token_id","scope","expires_at"],"title":"HandoffMintedToken","description":"The delegated token minted by an acceptance. It belongs to the grantor's account."},"HandoffOutgoingItem":{"properties":{"grant_id":{"type":"string","title":"Grant Id"},"scope":{"type":"string","title":"Scope"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"created_at":{"type":"string","title":"Created At"},"code_expires_at":{"type":"string","title":"Code Expires At"},"accepted_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accepted At"},"accepted_by":{"anyOf":[{"$ref":"#/components/schemas/HandoffAcceptedBy"},{"type":"null"}]},"token_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Token Id"},"status":{"type":"string","title":"Status","description":"'pending' (not redeemed yet, code still valid), 'expired' (code lapsed), 'accepted' (redeemed and live) or 'revoked' (ended by either side)."}},"type":"object","required":["grant_id","scope","created_at","code_expires_at","status"],"title":"HandoffOutgoingItem","description":"One grant the caller issued, in any state."},"HandoffRecordDeletedResponse":{"properties":{"status":{"type":"string","title":"Status","default":"deleted"},"grant_id":{"type":"string","title":"Grant Id"},"deleted_at":{"type":"string","title":"Deleted At","description":"When the grant's record was removed"}},"type":"object","required":["grant_id","deleted_at"],"title":"HandoffRecordDeletedResponse","description":"Response of `DELETE /v1/handoff/{grant_id}/record`."},"HandoffRevokeResponse":{"properties":{"status":{"type":"string","title":"Status","default":"revoked"},"grant_id":{"type":"string","title":"Grant Id"},"token_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Token Id","description":"The token this grant minted, when it was accepted"},"token_revoked":{"type":"boolean","title":"Token Revoked","description":"True when the grant's token exists and is inactive after this call","default":false},"revoked_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revoked At","description":"When the relationship was ended; unchanged on a repeat call"}},"type":"object","required":["grant_id"],"title":"HandoffRevokeResponse","description":"Response of `DELETE /v1/handoff/{grant_id}`."},"HandoffVaultSummary":{"properties":{"user_id":{"type":"string","title":"User Id"},"username":{"type":"string","title":"Username"},"secrets_count":{"type":"integer","title":"Secrets Count","description":"Active (unexpired) secrets in that vault","default":0}},"type":"object","required":["user_id","username"],"title":"HandoffVaultSummary","description":"The vault a handoff grants access to."},"SecretBulkDeleteRequest":{"properties":{"keys":{"items":{"type":"string"},"type":"array","maxItems":200,"minItems":1,"title":"Keys","description":"Key names to delete, at most 200 per request"}},"type":"object","required":["keys"],"title":"SecretBulkDeleteRequest","description":"Deletes several of the caller's own keys in one request.\n\nThe dashboard used to delete a selection one key at a time, which spends a\nrate-limit slot per key: selecting everything in a full vault (100 keys) walked\ninto the 60 requests/minute limit and was answered with 429s — a legitimate\ncleanup that looked exactly like a burst attack. One request per selection keeps\nthe limiter's view of a normal user honest."},"SecretBulkDeleteResponse":{"properties":{"status":{"type":"string","title":"Status","default":"deleted"},"deleted":{"items":{"type":"string"},"type":"array","title":"Deleted","description":"Keys that were removed"},"not_found":{"items":{"type":"string"},"type":"array","title":"Not Found","description":"Keys that were not in the caller's vault (unknown, expired, or owned by somebody else)"},"message":{"type":"string","title":"Message","default":"Bulk delete completed"}},"type":"object","title":"SecretBulkDeleteResponse"},"SecretCreateRequest":{"properties":{"key":{"type":"string","maxLength":128,"minLength":1,"title":"Key","description":"Secret key identifier (e.g. stripe_key, prod/db_pass)"},"value":{"anyOf":[{"type":"string"},{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"},{"type":"integer"},{"type":"number"},{"type":"boolean"}],"title":"Value","description":"Secret value: plain string, token, password, or JSON object"},"environment":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Environment","description":"Deprecated environment label; prefer `tags`"},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tags","description":"Up to three tags, each at most 20 characters"},"webhook_url":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Webhook Url","description":"Optional HTTP webhook URL to notify when secret is burned or expires"},"ttl_seconds":{"anyOf":[{"type":"integer","maximum":315360000.0,"minimum":1.0},{"type":"null"}],"title":"Ttl Seconds","description":"Optional Time-To-Live in seconds before automatic deletion"},"burn_after_read":{"type":"boolean","title":"Burn After Read","description":"If True, the secret is permanently deleted immediately after first read","default":false}},"type":"object","required":["key","value"],"title":"SecretCreateRequest"},"SecretDeleteResponse":{"properties":{"status":{"type":"string","title":"Status","default":"deleted"},"key":{"type":"string","title":"Key"},"message":{"type":"string","title":"Message","default":"Secret deleted successfully"}},"type":"object","required":["key"],"title":"SecretDeleteResponse"},"SecretImportRequest":{"properties":{"secrets":{"items":{"$ref":"#/components/schemas/SecretCreateRequest"},"type":"array","maxItems":2000,"minItems":1,"title":"Secrets","description":"Secrets to store, each validated by SecretCreateRequest"}},"type":"object","required":["secrets"],"title":"SecretImportRequest","description":"Bulk import payload. The browser parses the source file client-side (format and a\n5 MB size limit) and posts this list so the server can re-validate and store every\nkey with the same bounds as a single `POST /v1/vault/secrets`."},"SecretMetaResponse":{"properties":{"key":{"type":"string","title":"Key","description":"Secret key name"},"content_type":{"type":"string","title":"Content Type","description":"'text' or 'json'"},"environment":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Environment","description":"Deprecated environment label"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","description":"Up to three tags, each at most 20 characters"},"burn_after_read":{"type":"boolean","title":"Burn After Read","description":"Whether secret is burned after first read"},"read_count":{"type":"integer","title":"Read Count","description":"Access count"},"version":{"type":"integer","title":"Version","description":"Secret version number","default":1},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At","description":"Expiration timestamp"},"created_at":{"type":"string","title":"Created At","description":"Creation timestamp"},"updated_at":{"type":"string","title":"Updated At","description":"Last update timestamp"}},"type":"object","required":["key","content_type","burn_after_read","read_count","created_at","updated_at"],"title":"SecretMetaResponse"},"SecretResponse":{"properties":{"key":{"type":"string","title":"Key","description":"Secret key name"},"value":{"title":"Value","description":"Decrypted secret value (string or parsed JSON)"},"content_type":{"type":"string","title":"Content Type","description":"'text' or 'json'"},"environment":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Environment","description":"Deprecated environment label"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","description":"Up to three tags, each at most 20 characters"},"burn_after_read":{"type":"boolean","title":"Burn After Read","description":"Whether secret was marked to burn after read"},"read_count":{"type":"integer","title":"Read Count","description":"Number of times this secret has been retrieved"},"version":{"type":"integer","title":"Version","description":"Secret version number","default":1},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At","description":"Expiration timestamp if TTL set"},"created_at":{"type":"string","title":"Created At","description":"Creation timestamp"},"updated_at":{"type":"string","title":"Updated At","description":"Last update timestamp"}},"type":"object","required":["key","value","content_type","burn_after_read","read_count","created_at","updated_at"],"title":"SecretResponse"},"SecretRollbackRequest":{"properties":{"version_number":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version Number","description":"Optional specific version number to revert to. Defaults to previous version."}},"type":"object","title":"SecretRollbackRequest"},"SecretRollbackResponse":{"properties":{"status":{"type":"string","title":"Status","default":"restored"},"key":{"type":"string","title":"Key"},"restored_version":{"type":"integer","title":"Restored Version"},"message":{"type":"string","title":"Message","default":"Secret successfully rolled back"}},"type":"object","required":["key","restored_version"],"title":"SecretRollbackResponse"},"SecretUpdateRequest":{"properties":{"value":{"anyOf":[{"type":"string"},{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"},{"type":"integer"},{"type":"number"},{"type":"boolean"},{"type":"null"}],"title":"Value","description":"Secret value: plain string, token, password, or JSON object. If omitted, retains current value and updates metadata/TTL."},"key":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Key","description":"Optional key matching or redundant with the path parameter"},"environment":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Environment","description":"Deprecated environment label; prefer `tags`"},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tags","description":"Up to three tags, each at most 20 characters"},"webhook_url":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Webhook Url","description":"Optional HTTP webhook URL to notify when secret is burned or expires"},"ttl_seconds":{"anyOf":[{"type":"integer","maximum":315360000.0,"minimum":1.0},{"type":"null"}],"title":"Ttl Seconds","description":"Optional Time-To-Live in seconds before automatic deletion"},"burn_after_read":{"type":"boolean","title":"Burn After Read","description":"If True, the secret is permanently deleted immediately after first read","default":false}},"type":"object","title":"SecretUpdateRequest"},"SessionPolicyRequest":{"properties":{"policy":{"type":"string","title":"Policy","description":"'persistent', 'browser_close' or 'idle_5m'"}},"type":"object","required":["policy"],"title":"SessionPolicyRequest"},"SharedVaultResponse":{"properties":{"grant_id":{"type":"string","title":"Grant Id","description":"The accepted grant; also used to read that vault"},"username":{"type":"string","title":"Username","description":"Account that owns the shared vault"},"scope":{"type":"string","title":"Scope","description":"Scope the code carried, enforced on every read"},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At","description":"When the shared credential stops working (never for a principal token)"},"secrets_count":{"type":"integer","title":"Secrets Count","description":"Active secrets in that vault","default":0}},"type":"object","required":["grant_id","username","scope"],"title":"SharedVaultResponse","description":"One vault a hand-off shared with the calling account, as `GET /v1/shared/vaults` lists it.\n\nThis is the durable view of an acceptance: the raw credential was shown once, but the\ngrant stays readable for as long as its token is active and unexpired."},"TokenCreateRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Name","description":"Optional label for the delegated token. Defaults to a description built from the scope."},"scope":{"type":"string","maxLength":64,"title":"Scope","description":"Permission scope: 'full', 'read_only', 'prefix:<str>' or 'prefix:ro:<str>'. Defaults to 'read_only' (least privilege).","default":"read_only"},"ttl_seconds":{"type":"integer","minimum":1.0,"title":"Ttl Seconds","description":"Required time-to-live in seconds. Values below 60 are raised to 60 and values above 2592000 (30 days) are lowered to 2592000."}},"type":"object","required":["ttl_seconds"],"title":"TokenCreateRequest","description":"Body of the single delegation primitive, `POST /v1/auth/tokens`.\n\nA delegated token always carries a deadline: the issuer is present when it is\nhanded out and can renew it, which is why a TTL is required here and why the\nprincipal token issued at registration never expires."},"TokenMintResponse":{"properties":{"api_token":{"type":"string","title":"Api Token","description":"Raw Bearer token. Returned exactly once: only its SHA-256 hash is stored, so it can never be read back."},"token_prefix":{"type":"string","title":"Token Prefix","description":"Public token preview prefix"},"token_id":{"type":"string","title":"Token Id","description":"Stable id of the token row, usable with DELETE /v1/auth/tokens/{id}"},"scope":{"type":"string","title":"Scope","description":"Enforced permission scope of the delegated token"},"expires_at":{"type":"string","title":"Expires At","description":"Moment the delegated token stops working (UTC)"},"name":{"type":"string","title":"Name","description":"Label of the delegated token"}},"type":"object","required":["api_token","token_prefix","token_id","scope","expires_at","name"],"title":"TokenMintResponse","description":"Response of `POST /v1/auth/tokens`: the delegated token, shown exactly once."},"TokenResponse":{"properties":{"id":{"type":"string","title":"Id"},"token_id":{"type":"string","title":"Token Id","description":"Alias of `id`; stable identifier of this token row"},"name":{"type":"string","title":"Name"},"token_prefix":{"type":"string","title":"Token Prefix"},"scope":{"type":"string","title":"Scope"},"api_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Token"},"created_at":{"type":"string","title":"Created At"},"last_used_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Used At","description":"When this token was last used; null means it has never been used."},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At","description":"When this token stops working; null means it never expires."},"parent_token_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent Token Id","description":"Id of the token that issued this one; null for a principal token."}},"type":"object","required":["id","token_id","name","token_prefix","scope","created_at"],"title":"TokenResponse"},"TokenRotateResponse":{"properties":{"status":{"type":"string","title":"Status","default":"success"},"message":{"type":"string","title":"Message","default":"API token rotated successfully"},"api_token":{"type":"string","title":"Api Token","description":"New persistent Bearer API token"},"token_prefix":{"type":"string","title":"Token Prefix","description":"Public token preview prefix"}},"type":"object","required":["api_token","token_prefix"],"title":"TokenRotateResponse"},"UserLoginRequest":{"properties":{"username":{"type":"string","title":"Username","description":"Registered username or bot ID"},"password":{"type":"string","title":"Password","description":"Account password"}},"type":"object","required":["username","password"],"title":"UserLoginRequest"},"UserMeResponse":{"properties":{"user_id":{"type":"string","title":"User Id"},"username":{"type":"string","title":"Username"},"token_prefix":{"type":"string","title":"Token Prefix"},"secrets_count":{"type":"integer","title":"Secrets Count"},"created_at":{"type":"string","title":"Created At"},"is_admin":{"type":"boolean","title":"Is Admin","description":"True when this account carries the operator flag that unlocks the monitoring endpoints `GET /v1/system/metrics` and `GET /metrics`. It is granted out of band with `python -m agentsecrets.admin_cli grant <username>`; no username grants access and no request field can set this value.","default":false},"is_claimed":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Claimed","default":false},"claimed_by_user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Claimed By User Id"},"registration_method":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Registration Method","description":"Code path that created this account: 'rest_register', 'agent_self_register' or 'mcp_zero_config'. Null for accounts created before this field existed."},"registration_origin":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Registration Origin","description":"Origin request header sent at registration, when the caller sent one."},"registration_client":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Registration Client","description":"Coarse client class derived from the User-Agent at registration: curl, python, node, browser, mcp-client or unknown."},"session_policy":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Session Policy","description":"Browser session auto-expiry choice: 'persistent', 'browser_close' or 'idle_5m'. Changeable only through PUT /v1/account/session-policy.","default":"persistent"}},"type":"object","required":["user_id","username","token_prefix","secrets_count","created_at"],"title":"UserMeResponse"},"UserNotesResponse":{"properties":{"username":{"type":"string","title":"Username"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Decrypted personal notes"},"useful_links":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Useful Links","description":"Decrypted useful reference links"},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["username"],"title":"UserNotesResponse"},"UserNotesUpdateRequest":{"properties":{"notes":{"anyOf":[{"type":"string","maxLength":65536},{"type":"null"}],"title":"Notes","description":"Personal notes, agent instructions, or scratchpad (up to 64 KB, AES-256-GCM encrypted)","default":""},"useful_links":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Useful Links","description":"List of useful reference URLs"}},"type":"object","title":"UserNotesUpdateRequest"},"UserRecoverRequest":{"properties":{"username":{"type":"string","title":"Username","description":"Registered username or bot ID"},"recovery_phrase":{"type":"string","title":"Recovery Phrase","description":"12-word mnemonic phrase or recovery token provided at registration"},"new_password":{"type":"string","maxLength":128,"minLength":4,"title":"New Password","description":"New account password"}},"type":"object","required":["username","recovery_phrase","new_password"],"title":"UserRecoverRequest"},"UserRegisterRequest":{"properties":{"username":{"type":"string","maxLength":64,"minLength":3,"title":"Username","description":"Unique identifier: 3 to 64 characters (letters, numbers, hyphens, dots, underscores)"},"password":{"type":"string","maxLength":128,"minLength":4,"title":"Password","description":"Password for human/agent account login"}},"type":"object","required":["username","password"],"title":"UserRegisterRequest"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"HTTPBearer":{"type":"http","scheme":"bearer"},"APIKeyHeader":{"type":"apiKey","in":"header","name":"X-API-Key"}}},"tags":[{"name":"Authentication","description":"Register, log in, recover an account, and read your own profile. Registration is a single unauthenticated request — no email, captcha, or human verification."},{"name":"Token Management","description":"Issue and revoke API tokens. Scoped tokens (`read_only`, `prefix:<str>`, `prefix:ro:<str>`) let an agent hold only the access it needs. Creating, rotating and revoking tokens requires a token whose scope is exactly `full`."},{"name":"Handoff","description":"The agent-to-human (and human-to-agent) half of delegation: mint a single-use code, hand it to a person, and let them redeem it for a time-bounded token on the grantor's vault. Only the code's hash is stored, the code expires in ten minutes, and either side can end the relationship at any time."},{"name":"Vault","description":"Store, read, list, roll back and delete secrets. Values are sealed with AES-256-GCM before they reach disk. Supports TTL expiry, burn-after-read, environment tags, version snapshots, and bulk shell/JSON export."},{"name":"Model Context Protocol (Remote SSE)","description":"The remote MCP surface: SSE and Streamable HTTP transports plus the JSON-RPC message channel. Discovery methods (`initialize`, `tools/list`, `prompts/list`, `resources/list`) are answered without credentials; anything touching vault data requires a token."},{"name":"Agent Ergonomics","description":"One-call helpers for agent runtimes: session context with quota and next actions, plus the public capability manifest. Handing a vault to a human operator or a sub-agent is done with a time-bounded delegated token (`POST /v1/auth/tokens`), never by transferring the agent's own identity."},{"name":"AI Ergonomics & Ecosystem","description":"Machine-readable specifications served as plain text or JSON: skill.md, skill.json, RULES.md, HEARTBEAT.md, llms.txt and the OpenAI plugin manifest. These are what an agent reads before it stores anything."},{"name":"Discovery","description":"Unauthenticated service metadata: capabilities, limits and the pricing model."},{"name":"Ecosystem","description":"Index of every machine-readable file and endpoint this service publishes."},{"name":"Monitoring","description":"Liveness, public aggregate server statistics (no client data), and admin-restricted Prometheus metrics and system load. Access is the per-account `is_admin` flag, granted out of band with `python -m agentsecrets.admin_cli grant <username>`; the two restricted routes answer 404 rather than 403 to every account that does not carry it."},{"name":"Health","description":"Service health check used by the container orchestrator."},{"name":"OAuth Discovery","description":"RFC 9728 / RFC 8414 metadata so MCP clients can discover how to authenticate, including the RFC 9207 `iss` parameter."},{"name":"User Profile","description":"Encrypted profile notes and scratchpad stored alongside the vault."}]}