Skip to main content
Three routes let a client learn what it is talking to and who it is. GET /v1/capabilities and GET /config.json take no credential; GET /v1/whoami reflects whichever credential the Vexlo server accepted. The UI’s boot sequence and the MCP server’s startup checks both begin here. The bodies on this page were captured from three servers: one under bearer authentication on 127.0.0.1:18200, seeded with the spec’s conformance trace on team fixture and holding the tokens named below; one started with -no-auth on 127.0.0.1:18201; and one started with -header-trust -header-trust-secret proxy-shared-secret-7f3a on 127.0.0.1:18202. Every token was minted on a throwaway server storage directory. Minting is covered on authentication and tokens.

GET /v1/whoami

Takes no parameters and returns the caller’s own validated credential. Either role is accepted: an ingest token confirming its pins is as legitimate a caller as the UI learning its team-set. A read token spanning two teams:
An ingest token for team fixture pinned to environment prod:
An unpinned ingest token for team demo:
Under no-auth mode no tokens exist. Every call answers with role read and the single team the server was started with (-team, default default):
An Authorization header sent to that server changes nothing; an unknown token gets the same body:
Under header-trust mode a reverse proxy in front of the server injects X-Vexlo-Team and X-Vexlo-Trust-Secret; the server consults them only when Authorization is absent, and the principal it builds is a read principal for that one team:
Both headers are required, and the secret must match:

GET /v1/capabilities

Unauthenticated, never rate limited, and free of team or environment data: the route a client calls before it holds a credential, to learn which authentication mode to use and which bounds the server enforces. The MCP server reads its own limits from limits. The bearer server:
record_format_versions sits in an unauthenticated response because it answers one operational question, whether this server accepts what an SDK is about to stamp, and the rollout it belongs to puts the server before the SDKs. Nothing in the emit path reads it: an emitter stamps the version it implements, and nothing between the process and the server rewrites that field. The no-auth server reports "auth_mode": "none". Its limits are the same numbers, although no rate limit is applied in that mode (conventions):
The header-trust server reports "auth_mode": "header_trust":

GET /config.json

The bootstrap document the UI reads first. It sits outside /v1, takes no credential, is never rate limited, and carries one field:
api_base_url is always the empty string: the UI and the /v1 API are served from one process on one port, so the API is same-origin. No flag changes it.