{"openapi":"3.1.0","info":{"title":"ActionLake","description":"One surface for every action.","version":"2.0.0"},"paths":{"/v1/account/tenant.create":{"post":{"summary":"Tenant Create Route","description":"`tenant_create`, through the front door: refused from another site's page first.","operationId":"tenant_create_route_v1_account_tenant_create_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Tenant Create Route V1 Account Tenant Create Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/tenant.update":{"post":{"summary":"Tenant Update Route","description":"`tenant.update`, through the front door: the same standing check the op makes.","operationId":"tenant_update_route_v1_account_tenant_update_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Tenant Update Route V1 Account Tenant Update Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/status":{"get":{"summary":"Account Status","description":"What this key is and what it may do — the answer to \"what am I connected to?\".\n\n**Scope-free on purpose** (SURF-02). It describes the credential presenting it — its own\ngrants, cap and notes, and its tenant's name — which a token needs to know whatever it was\nconsented for, and `account {op: 'status'}` is the one op any door may ask for the same reason.\nIt returns no other key, no run and no spend.\n\n`dedicated_ip` is the tenant's Dedicated IP in two fields — its state and its address — and\nnothing more. Whatever a key was consented for, its calls leave from that address, so \"which\naddress will the vendor see?\" is a question about the credential's own situation; the full\nrow (health, last error, the price) is `egress.status`, under `account`.","operationId":"account_status_v1_account_status_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Account Status V1 Account Status Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/keys":{"get":{"summary":"Keys List","description":"The tenant's live keys a page at a time; `include_revoked` adds the revoked ones, and\n`next_cursor` is the `cursor` for the next page (review 2026-10-11 ADMIN-14).","operationId":"keys_list_v1_account_keys_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":1000,"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","default":"","title":"Cursor"}},{"name":"include_revoked","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Revoked"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Keys List V1 Account Keys Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/keys.create":{"post":{"summary":"Keys Create","description":"Mint a key under this one. Attenuation only, never escalation.","operationId":"keys_create_v1_account_keys_create_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Keys Create V1 Account Keys Create Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/keys.update":{"post":{"summary":"Keys Update","description":"Edit a live key in place — name, grants, cap, policy. The secret is untouched, so nothing\nholding the key has to be handed a new one. Held to the same attenuation as a mint.","operationId":"keys_update_v1_account_keys_update_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Keys Update V1 Account Keys Update Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/keys.recovery_email":{"post":{"summary":"Keys Recovery Email","description":"Attach, replace or remove a person key's recovery email (`admin/recovery.py`).\n\nThe address is mailed a verification link and recovers nothing until it is opened; the old\naddress, when there was one, is told. `email` null or empty removes it. The standing is the\ntenant's root key — over any key, its own included — or the key that minted it.","operationId":"keys_recovery_email_v1_account_keys_recovery_email_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Keys Recovery Email V1 Account Keys Recovery Email Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/keys.recover":{"post":{"summary":"Keys Recover","description":"\"Forgot your key?\" — one fixed answer, now; the lookup and the mail in the background.\n\n**Enumeration-safe by construction**: the body, the status and the time to answer do not\ndepend on whether the address is on any key. `tenant_id` narrows which tenant's keys are\nmeant when one address recovers keys in several.","operationId":"keys_recover_v1_account_keys_recover_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Keys Recover V1 Account Keys Recover Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/keys.recover.peek":{"post":{"summary":"Keys Recover Peek","description":"What a reset link is for — key, tenant, until when — before the person confirms. Reading\nit changes nothing, so a mail scanner that opens the link resets nothing.","operationId":"keys_recover_peek_v1_account_keys_recover_peek_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Keys Recover Peek V1 Account Keys Recover Peek Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/keys.recover.confirm":{"post":{"summary":"Keys Recover Confirm","description":"The button on the recovery page: rotate the key, spend the link, tell the address. The\nnew secret is shown once, like a mint.","operationId":"keys_recover_confirm_v1_account_keys_recover_confirm_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Keys Recover Confirm V1 Account Keys Recover Confirm Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/keys.recovery_email.verify":{"post":{"summary":"Keys Recovery Email Verify","description":"The verification link was opened: from now on the address can recover the key.","operationId":"keys_recovery_email_verify_v1_account_keys_recovery_email_verify_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Keys Recovery Email Verify V1 Account Keys Recovery Email Verify Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/keys.rotate":{"post":{"summary":"Keys Rotate","description":"A new secret for a key that keeps everything else — its id, grants, cap, pins and children.\n\nThe answer to \"this key leaked\" and to \"I want a fresh secret\" that does not end with a tenant\nrevoking its last root key and losing the ability to raise a cap.","operationId":"keys_rotate_v1_account_keys_rotate_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Keys Rotate V1 Account Keys Rotate Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/keys.revoke":{"post":{"summary":"Keys Revoke","operationId":"keys_revoke_v1_account_keys_revoke_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Keys Revoke V1 Account Keys Revoke Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cost":{"get":{"summary":"Cost","description":"Spend so far, forecast, cap headroom, the price book. Free, always.\n\nOne line: this and the MCP `cost` tool are the same function. This route had drifted — it\nreturned headroom alone while the tool also returned the period's spend and hit rate, so the\nconsole showed blanks for numbers the agent could see.\n\n**`billing` on this route** (SURF-02), as on `account {op: 'usage'}` which answers the same\nfunction: the tenant's spend is what the `billing` consent names. The MCP `cost` tool stays\nreachable with `actions` alone — an agent must see its own headroom before it spends, and that\ntool is one of the eight every agent is told to call before a `do`.","operationId":"cost_v1_cost_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Cost V1 Cost Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/egress/echo":{"get":{"summary":"Egress Echo","description":"The caller's own address, as our ingress saw it. **Unauthenticated on purpose.**\n\nIt is what the Dedicated IP health check rests on: the check asks this route *through* the\ntenant's hop and the address must come back as the reserved one, which proves the whole path —\ndroplet up, secret accepted, packets leaving from the right address — rather than a port being\nopen. It also lets a customer see, from their own network, what address they present.\n\nThe address is the inbound limiter's (`core.ratelimit.client_ip`): DigitalOcean's\n`do-connecting-ip`, then `CF-Connecting-IP` only when the peer is a Cloudflare edge. Never\n`X-Forwarded-For` — the caller writes that header, and a health check that believes it can be\ntold any address it wants to hear.\n\nThe answer differs per caller, so it keeps the `no-store` every `/v1` answer gets: this path\nmust never join `_PUBLIC_PATHS` in `main.py`, where a shared cache would hand one caller\nanother's address.","operationId":"egress_echo_v1_egress_echo_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Egress Echo V1 Egress Echo Get"}}}}}}},"/v1/actions":{"get":{"summary":"Actions List","description":"`find_actions`. One line per result — id, title, cost, effect — never full schemas.\n\n**One line, on purpose.** This and the MCP `find_actions` tool are the same function. There\nwere briefly two, and the route had already drifted: it did not accept `scope` at all, so a\nsearch could not be widened to the store or narrowed to saved plans.\n\n`vocabulary=1` on a no-query search adds every verb with the services that answer it — the\nconsole's catalogue browses on it; an agent's cold start never pays for it.\n\n`verb=` is the exact question `q=` cannot answer. `q` ranks on text and admits a result that\nmatches two terms in three, so `q=service.ticket.get` returns every action with \"ticket\" in\nits id — deletes included — because `get` never had to match at all. That is right for a\nperson typing \"create a ticket\" and wrong for anyone asking which actions *carry* a verb.\nNow that every action has one, that question deserves a filter rather than a ranking.","operationId":"actions_list_v1_actions_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","default":"","title":"Q"}},{"name":"scope","in":"query","required":false,"schema":{"type":"string","default":"connected","title":"Scope"}},{"name":"entity","in":"query","required":false,"schema":{"type":"string","default":"","title":"Entity"}},{"name":"effect","in":"query","required":false,"schema":{"type":"string","default":"","title":"Effect"}},{"name":"service","in":"query","required":false,"schema":{"type":"string","default":"","title":"Service"}},{"name":"verb","in":"query","required":false,"schema":{"type":"string","default":"","title":"Verb"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":10,"title":"Limit"}},{"name":"vocabulary","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Vocabulary"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Actions List V1 Actions Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/actions/{action_id}":{"get":{"summary":"Action Get","description":"`get_action`. The full input schema, output shape, cost and a worked example.\n\nOne line: the same function the MCP tool calls. This route had reimplemented it and was\nmissing the worked example — §5.9 says every action carries one, and an agent that cannot copy\nan example has to guess.","operationId":"action_get_v1_actions__action_id__get","parameters":[{"name":"action_id","in":"path","required":true,"schema":{"type":"string","title":"Action Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Action Get V1 Actions  Action Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/do":{"post":{"summary":"Do","description":"Perform one action, or several in order.\n\n**One line, on purpose.** This endpoint and the MCP `do` tool are the same function, so they\ncannot drift — which is what the design means by \"MCP is a thin translation on top of REST,\nnot a second implementation\". There were briefly two implementations here and the REST one had\nalready fallen behind: it did not know about `steps`.","operationId":"do_v1_do_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Do V1 Do Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/check":{"post":{"summary":"Check","description":"Dry-run a `do` or `ask` payload. Free, and nothing is sent.","operationId":"check_v1_check_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Check V1 Check Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/connections":{"get":{"summary":"Connections List","operationId":"connections_list_v1_connections_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Connections List V1 Connections Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/connections.create":{"post":{"summary":"Connections Create","description":"The agent connects a service it holds the credential for — no human.","operationId":"connections_create_v1_account_connections_create_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Connections Create V1 Account Connections Create Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/oauth_clients.create":{"post":{"summary":"Oauth Clients Create","description":"A static OAuth client for an admin form that asks for a client id and secret — Copilot\nStudio's manual OAuth, Gemini Enterprise, Agentforce, Azure AI Foundry. Credential management,\nso held as `connections.create` is (`account:*`) and refused to a token as `keys.create` is.","operationId":"oauth_clients_create_v1_account_oauth_clients_create_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Oauth Clients Create V1 Account Oauth Clients Create Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/oauth_clients":{"get":{"summary":"Oauth Clients List","operationId":"oauth_clients_list_v1_account_oauth_clients_get","parameters":[{"name":"include_revoked","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Revoked"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Oauth Clients List V1 Account Oauth Clients Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/oauth_clients.revoke":{"post":{"summary":"Oauth Clients Revoke","operationId":"oauth_clients_revoke_v1_account_oauth_clients_revoke_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Oauth Clients Revoke V1 Account Oauth Clients Revoke Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/connections.delete":{"post":{"summary":"Connections Delete","description":"**Revocation is deletion**: the row goes, and its ciphertext with it.\n\nAddressable by `connection_id`, or by `service` and `name` — because the id is shown once at\ncreation and an agent that wants to replace a connection it made an hour ago has the service\nname and not the id. Without this there was no way to remove a connection at all: a wrong\ncredential, or one that discovered the wrong host, was permanent for the life of the tenant.","operationId":"connections_delete_v1_account_connections_delete_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Connections Delete V1 Account Connections Delete Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/connections.update":{"post":{"summary":"Connections Update","description":"Correct a connection in place: new secrets, a corrected zone, or a new name.\n\nUntil this existed, a wrong credential or a discovered host that turned out wrong meant\ndelete-and-recreate, and a misconfigured endpoint meant republishing the whole service file.\nAddressable like `connections.delete`: by `connection_id`, or by `service` and `name`.\n\n**A new host is a new trust decision** (review 2026-10-10 SURFACE-01, CRED-01): a change to\nany field the service reads its server, native host or token endpoint from must come with\nthe credential re-supplied, unless the caller is the tenant's root key — and is re-tested\nagainst the new host either way (`connections_admin.update_connection`).","operationId":"connections_update_v1_account_connections_update_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Connections Update V1 Account Connections Update Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/price-book":{"get":{"summary":"Price Book","description":"Free, no auth: an agent can read the price before it spends anything.","operationId":"price_book_v1_price_book_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Price Book V1 Price Book Get"}}}}}}},"/v1/runs/summary":{"get":{"summary":"Runs Summary","description":"The figures and the chart behind the runs screen, over the whole window — never over the\npage the table has loaded.\n\nThe screen used to add up the hundred rows it had fetched and call the sum \"requests, 24h\";\nthe overview, reading `/v1/usage`, said four times as many. Every tile here is one aggregate\nover every row the filters match, through the same predicate `GET /v1/runs` pages with, and\n`/v1/usage` is this call for `window=24h` with no filter — so the two screens agree by\nconstruction.\n\n`window` is `1h`, `24h`, `7d` or `all`; `kind`, `action`, `status`, `cache` (`hit`/`miss`)\nand `key` are the list's filters. `calls` is the vendor calls — every one, the calls grouped\nruns made included, unless `kind` names a shape — and `groups` the grouped runs. `buckets` is\nthe chart: `bucket_s` seconds a column, `t` the column's start in epoch seconds, over the\nwindow (`all`: the last ninety days). Each figure is over the newest `_RUNS_SUMMARY_CAP` rows\nat most, and says `capped` when it stopped there.","operationId":"runs_summary_v1_runs_summary_get","parameters":[{"name":"window","in":"query","required":false,"schema":{"type":"string","default":"24h","title":"Window"}},{"name":"action","in":"query","required":false,"schema":{"type":"string","default":"","title":"Action"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","default":"","title":"Status"}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","default":"","title":"Kind"}},{"name":"cache","in":"query","required":false,"schema":{"type":"string","default":"","title":"Cache"}},{"name":"key","in":"query","required":false,"schema":{"type":"string","default":"","title":"Key"}},{"name":"platform","in":"query","required":false,"schema":{"type":"string","default":"","title":"Platform"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Runs Summary V1 Runs Summary Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/runs":{"get":{"summary":"Runs List","description":"Every call: who, what, when, cost, cache, timing — filterable.\n\n`kind` narrows the list: `action` (calls made outside any group), `plan` / `ask` / `verb` /\n`steps` (grouped runs of that shape, one row each), `group` (any grouped run), `step` (the\ncalls groups made), `platform` (calls to ActionLake itself), `all` (every vendor call, groups\nexcluded), or the default — actions and groups together, newest first. `plan_run_id` lists\none group's calls. `platform=1` keeps the calls to ActionLake itself in any view; they are\nhidden otherwise. `cache` (`hit` / `miss`) keeps one verdict — calls only, since a group has\nnone; `key` one key's rows; `window` (`1h`, `24h`, `7d`, the default `all`) the rows since\nthen, the same window `/v1/runs/summary` adds up. `before_at` (ISO) pages the merged list;\n`before` (a run id) still pages the calls alone. `total` is the count on the server that\nmatches the filters, so a page of 100 never reads as \"100 requests\" — counted up to 10,000\nper table, with `total_capped` true past that.","operationId":"runs_list_v1_runs_get","parameters":[{"name":"action","in":"query","required":false,"schema":{"type":"string","default":"","title":"Action"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","default":"","title":"Status"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"before","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Before"}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","default":"","title":"Kind"}},{"name":"plan_run_id","in":"query","required":false,"schema":{"type":"string","default":"","title":"Plan Run Id"}},{"name":"before_at","in":"query","required":false,"schema":{"type":"string","default":"","title":"Before At"}},{"name":"platform","in":"query","required":false,"schema":{"type":"string","default":"","title":"Platform"}},{"name":"cache","in":"query","required":false,"schema":{"type":"string","default":"","title":"Cache"}},{"name":"key","in":"query","required":false,"schema":{"type":"string","default":"","title":"Key"}},{"name":"window","in":"query","required":false,"schema":{"type":"string","default":"all","title":"Window"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Runs List V1 Runs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/runs/{run_id}":{"get":{"summary":"Run Get","description":"One run, in full — **with secrets redacted**.\n\nThe payload hashes are always here; the payloads themselves are in the bucket for 90 days and\nare gone after that, by design. A run can still be proven by hash once the\npersonal data has expired.","operationId":"run_get_v1_runs__run_id__get","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"integer","title":"Run Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Run Get V1 Runs  Run Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/runs/{run_id}/trace":{"get":{"summary":"Run Trace","description":"What a run sent and what came back, for as long as the plan keeps it.\n\n**A key reads its own runs; the tenant's root key and a key granted `traces:*` read every\nkey's.** The record is sealed under the tenant's data key and opened here, for this request,\nand nothing else — the list of runs never carries a body.","operationId":"run_trace_v1_runs__run_id__trace_get","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"integer","title":"Run Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Run Trace V1 Runs  Run Id  Trace Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/usage":{"get":{"summary":"Usage","description":"The overview numbers, and the two the design says to publish from day one: the cache hit\nrate (§5.3 — the whole margin story rests on it) and the error rate.\n\n`today` is `/v1/runs/summary?window=24h` with no filter — the same predicate and the same\naggregate, so the overview and the runs screen say the same day.","operationId":"usage_v1_usage_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Usage V1 Usage Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/plans":{"get":{"summary":"Plans List","description":"The REST twin of `plans.list` — the envelope, not the bare steps.\n\nReads through the plan store, so the console sees what an agent sees: a title, the current\nversion, `use_when`, the effect and how the plan has been running. It used to read `plans`\ndirectly and return a name and a step list, which is exactly the \"a name plus a step count\nsays almost nothing\" problem the envelope exists to fix.","operationId":"plans_list_v1_plans_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Plans List V1 Plans Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/usage/{period}":{"get":{"summary":"Usage Period","description":"A month's usage, from the ledger. `SUM(billed_calls)` is the bill.","operationId":"usage_period_v1_usage__period__get","parameters":[{"name":"period","in":"path","required":true,"schema":{"type":"string","title":"Period"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Usage Period V1 Usage  Period  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/invoices":{"get":{"summary":"Invoices List","operationId":"invoices_list_v1_invoices_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Invoices List V1 Invoices Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/invoices/roll-up":{"post":{"summary":"Invoices Roll Up","description":"Close a period into an invoice. The cron does this at the turn of the month; this is the\nsame call, for a period that needs re-stating after a correction.","operationId":"invoices_roll_up_v1_invoices_roll_up_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Invoices Roll Up V1 Invoices Roll Up Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/store":{"get":{"summary":"Store Search","operationId":"store_search_v1_store_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","default":"","title":"Q"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Store Search V1 Store Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/store/plans":{"get":{"summary":"Store Plans","description":"The plan store, browsable without a key like the service store (PLAN-STORE.md).","operationId":"store_plans_v1_store_plans_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","default":"","title":"Q"}},{"name":"service","in":"query","required":false,"schema":{"type":"string","default":"","title":"Service"}},{"name":"effect","in":"query","required":false,"schema":{"type":"string","default":"","title":"Effect"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":24,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Store Plans V1 Store Plans Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/store/plans/{slug}":{"get":{"summary":"Store Plan","operationId":"store_plan_v1_store_plans__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"version","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Store Plan V1 Store Plans  Slug  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/store/{slug}":{"get":{"summary":"Store Listing","operationId":"store_listing_v1_store__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Store Listing V1 Store  Slug  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/publisher/earnings":{"get":{"summary":"Publisher Earnings","description":"A publisher's own view: installs, calls, error rate, earnings (§7.3).\n\nScoped to the caller's tenant as its own publisher id, which is what `publish` records.","operationId":"publisher_earnings_v1_publisher_earnings_get","parameters":[{"name":"period","in":"query","required":false,"schema":{"type":"string","default":"","title":"Period"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Publisher Earnings V1 Publisher Earnings Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/{op}":{"post":{"summary":"Account Operation","description":"`POST /v1/account/{op}` — the REST twin of the `account` tool.\n\nOne route for every op, dispatching to the same function the MCP tool calls. The named routes\nabove (`keys.create`, `connections.create`, …) predate this and stay because they are what\n§5's REST table lists; this catches the rest, so the console never needs an endpoint an agent\ndoes not have.","operationId":"account_operation_v1_account__op__post","parameters":[{"name":"op","in":"path","required":true,"schema":{"type":"string","title":"Op"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Account Operation V1 Account  Op  Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/.well-known/actionlake-price-book.json":{"get":{"summary":"Price Book Well Known","description":"The same price book, at the address a machine looks for it.\n\n**Served by the API, not only by the site.** `web/nginx.conf` proxies this path to `/v1/\nprice-book`, which is correct in the single-origin local arrangement and silently wrong\ndeployed: the site and the API are two apps there, so the site's SPA fallback answered this\nwith `index.html` and a 200. A price book that resolves to a web page is worse than one that\n404s, because a client parses the 404.","operationId":"price_book_well_known__well_known_actionlake_price_book_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Price Book Well Known  Well Known Actionlake Price Book Json Get"}}}}}}},"/mcp":{"post":{"summary":"Mcp","description":"The MCP endpoint, for both eras of the protocol (2026-07-28 basic/versioning: \"A dual-era\nserver selects its behavior from how the client opens\").\n\n* **Legacy** (2025-03-26, 2025-06-18, 2025-11-25): `initialize` and the requests after it, as\n  before. This server never held a session, so each request already stood alone.\n* **Modern** (2026-07-28): a request whose `MCP-Protocol-Version` header (or `_meta` version)\n  names it. No handshake; headers checked against the body; `resultType`, `_meta.serverInfo`\n  and caching hints on every result.","operationId":"mcp_mcp_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"MCP-Protocol-Version","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mcp-Protocol-Version"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/.well-known/oauth-authorization-server":{"get":{"summary":"Metadata","operationId":"metadata__well_known_oauth_authorization_server_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Metadata  Well Known Oauth Authorization Server Get"}}}}}}},"/.well-known/oauth-protected-resource/mcp":{"get":{"summary":"Protected Resource","description":"RFC 9728: the resource tells a client where its authorization server is.\n\n**The `resource` is the host that was called**, when it is one of `CONFIG.mcp_origins`: a\nclient that connected to `connect.` and read back `api.` must refuse the document (§3.3).\nServed at the root path and at the path-inserted form for `/mcp` (§3.1), because clients try\neither first.","operationId":"protected_resource__well_known_oauth_protected_resource_mcp_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Protected Resource  Well Known Oauth Protected Resource Mcp Get"}}}}}}},"/.well-known/oauth-protected-resource":{"get":{"summary":"Protected Resource","description":"RFC 9728: the resource tells a client where its authorization server is.\n\n**The `resource` is the host that was called**, when it is one of `CONFIG.mcp_origins`: a\nclient that connected to `connect.` and read back `api.` must refuse the document (§3.3).\nServed at the root path and at the path-inserted form for `/mcp` (§3.1), because clients try\neither first.","operationId":"protected_resource__well_known_oauth_protected_resource_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Protected Resource  Well Known Oauth Protected Resource Get"}}}}}}},"/.well-known/jwks.json":{"get":{"summary":"Jwks","operationId":"jwks__well_known_jwks_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Jwks  Well Known Jwks Json Get"}}}}}}},"/oauth/register":{"post":{"summary":"Register","description":"RFC 7591. A client registers itself; nobody approves it — approval is what the consent\nscreen is for, per grant, by a human who can see the client's name.","operationId":"register_oauth_register_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/oauth/authorize":{"get":{"summary":"Authorize","description":"The first half of the dance: check everything, then show a consent screen that names the\nclient and the scopes. Nothing is granted until a human says so.","operationId":"authorize_oauth_authorize_get","parameters":[{"name":"client_id","in":"query","required":true,"schema":{"type":"string","title":"Client Id"}},{"name":"redirect_uri","in":"query","required":true,"schema":{"type":"string","title":"Redirect Uri"}},{"name":"response_type","in":"query","required":false,"schema":{"type":"string","default":"code","title":"Response Type"}},{"name":"code_challenge","in":"query","required":false,"schema":{"type":"string","default":"","title":"Code Challenge"}},{"name":"code_challenge_method","in":"query","required":false,"schema":{"type":"string","default":"S256","title":"Code Challenge Method"}},{"name":"scope","in":"query","required":false,"schema":{"type":"string","default":"","title":"Scope"}},{"name":"state","in":"query","required":false,"schema":{"type":"string","default":"","title":"State"}},{"name":"resource","in":"query","required":false,"schema":{"type":"string","default":"","title":"Resource"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Authorize Oauth Authorize Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/oauth/consent":{"post":{"summary":"Consent","description":"The human approves — on behalf of an API key, which is the principal the token will carry.","operationId":"consent_oauth_consent_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_consent_oauth_consent_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Consent Oauth Consent Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/oauth/token":{"post":{"summary":"Token","operationId":"token_oauth_token_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/oauth/revoke":{"post":{"summary":"Revoke","description":"RFC 7009. Always 200 — a revocation endpoint that reveals whether a token existed is an\noracle.\n\nEither kind of token may be presented, and either one kills the whole grant: the refresh\nchain, and the access token through the dead marker. Revoking only the chain, as this used\nto, left the access token valid for its full lifetime, which is the wrong answer to \"I think\nmy Claude connection is compromised\".","operationId":"revoke_oauth_revoke_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"summary":"Health","description":"Liveness, and it actually checks the two things whose absence would make every request\nfail. A health check that only proves the process is running is how a green probe sits in\nfront of a broken deployment.\n\n**What an anonymous probe sees** (INFRA-09): `ok`, `checks`, `services` (loaded), `available`\n(on disk) and `seed` — the operator confirms a deploy by the service count, and a partial load\nor a failed seed is visible as numbers without being a reason to roll back. `version` and\n`resident` only for a caller presenting `AL-Probe` equal to `AL_PROBE_TOKEN`; with no token\nconfigured, never.\n\n**The status code is the verdict** (review 2026-10-11 CORE-01 / INFRA-02): `200` when every\ncheck passed, `503` otherwise. App Platform's HTTP health check reads only the status, so a\nbody that said `\"ok\": false` under a `200` kept a deploy with no database, no Redis or an empty\ncatalogue green — promoted, and never restarted. `seed` and `traces` stay informational.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"Body_consent_oauth_consent_post":{"properties":{"pending":{"type":"string","title":"Pending"},"api_key":{"type":"string","title":"Api Key","default":""},"deny":{"type":"string","title":"Deny","default":""}},"type":"object","required":["pending"],"title":"Body_consent_oauth_consent_post"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"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"}}}}