{"openapi":"3.1.0","info":{"title":"Hanzo Cloud API","description":"The Hanzo Cloud API as a customer calls it: every operation under /v1/ except the operator's admin product, relay routes, legacy spellings and capabilities still reached by flag. Tagged by product: the first path segment after /v1/.","version":"v1"},"servers":[{"url":"https://api.hanzo.ai"}],"security":[{"bearer":[]}],"tags":[{"name":"account","description":"Package account is your own account: API keys you mint and revoke, and org onboarding."},{"name":"ad","description":"Package ads is your paid ad campaigns, launched and paused from one place."},{"name":"affiliate","description":"Package affiliates is a partner program that pays commission on what your referrals spend."},{"name":"agent","description":"Package agents is autonomous agents for your org: define them, run them, keep every run."},{"name":"ai","description":"Package ai is Hanzo AI — the model API on /v1 (/v1/chat/completions, /v1/messages, /v1/models and the rest of hanzoai/ai's surface) — mounted into a cloud binary with the money, ingest and telemetry callbacks cloud BUILDS but cannot INSTALL."},{"name":"allowance","description":"Package allowance is how much a plan lets you do without paying, and how much of it you have left today."},{"name":"ask","description":"Package ask is a plain-language question about your business, answered with real numbers."},{"name":"audit","description":"Package auditlog is your org's tamper-evident audit trail: every security-relevant event, hash-chained and readable."},{"name":"author","description":"Package authors is a royalty for open-source work: your repo runs, you get paid."},{"name":"authz","description":"Package serve is the access decision behind an org-scoped call: who may do what, where, answered allow or deny."},{"name":"auto","description":"Package auto is workflows that run themselves, on a schedule or a webhook."},{"name":"base","description":"Package base is managed Hanzo Base: a hosted backend for your app — collections, records, access rules and sign-in."},{"name":"benchmark","description":"Package benchmark is one honest score for any model, on the tests everyone quotes."},{"name":"billing","description":"Package billing is your org's balance, what it has spent, and the cards it pays with."},{"name":"blueprint","description":"Package blueprint is what a template costs to run, worked out before you deploy."},{"name":"books","description":"Package books is double-entry accounting: chart of accounts, ledger, bank reconciliation, and the reports that prove the books balance."},{"name":"bot","description":"Package bot is a bot doing your work on a real desktop, live, while you watch."},{"name":"campaign","description":"Package campaign is one go-to-market push across paid, organic and email at once."},{"name":"captable","description":"Package captable is your cap table: stakeholders, share classes, grants, SAFEs, rounds, and who owns what."},{"name":"catalog","description":"Package catalog is one place to browse every project, app and site built here."},{"name":"channel","description":"Package channels is one inbox for the chat apps you connect — Discord, Slack, Teams, Telegram."},{"name":"ci","description":"Package ci mounts the CI fleet dashboard as a capability of this binary."},{"name":"cloudflare","description":"Package cloudflare is your Cloudflare account, managed from Hanzo: zones, Pages, Workers, Workers AI, R2, KV and D1."},{"name":"code","description":"Package code is search and symbols across your repos, for you and your agents."},{"name":"commerce","description":"Package commerce is selling: checkout, subscriptions, invoices, spend alerts, payment webhooks and the storefront catalog."},{"name":"company","description":"Package company is incorporation end to end: pick a structure, add founders, pay, file, and e-sign."},{"name":"compliance","description":"Package compliance is your KYC/KYB onboarding, accreditation records, and the evidence trail behind them."},{"name":"compute","description":"Package compute is the compute you rent from Hanzo: machines, GPUs and clusters — launch one, resize it, tear it down."},{"name":"content","description":"Package content is marketing content from draft to published, on every channel."},{"name":"crawl","description":"Package crawl is any web page turned into clean markdown a model can read."},{"name":"dataroom","description":"Package dataroom is a secure document room you share by link and watch page by page."},{"name":"dataset","description":"Package dataset is the per-org dataset plane of /v1/risk: a dataset is a VERSIONED, IMMUTABLE snapshot of one tenant's own event surface, and this is where it is declared, materialised, described, exported and disposed of."},{"name":"deploy","description":"Package deploy is Hanzo CD: see what each app is running, sync it, and roll back a bad release."},{"name":"destination","description":"Package destinations is your events forwarded to the ad and analytics tools you use."},{"name":"dns","description":"Package dns is your DNS records: the zones and records behind every name you point at Hanzo."},{"name":"domain","description":"Package domain is Hanzo Domains: search a name, see the price, buy it from your prepaid wallet."},{"name":"email"},{"name":"engine","description":"Package engine is Hanzo Engine: which models the serving runtime has loaded, and the GPUs under it."},{"name":"entitlement","description":"Package entitlements is what your org may run: what the plan grants, and which of those products are switched on."},{"name":"environment","description":"Package environment is what a codebase is before its agent starts: the commands that install it, the command that starts it, and the secrets it reads."},{"name":"esign","description":"Package esign is a document out for signature, signed and filed with an audit trail."},{"name":"eval","description":"Package eval is scoring a model on your own data, with a judge you choose."},{"name":"event","description":"Package analytics is product analytics: send an event, read back who did what."},{"name":"exec","description":"Package exec is the code interpreter: run a snippet in a sandbox, and move files in and out of the session that sandbox IS."},{"name":"experiment","description":"Package experiments is A/B testing anything: a flag, an ad, a subject line, a model."},{"name":"explorer","description":"Package explorer is chain data: your block indexers and how far each has caught up, plus the on-chain price feeds."},{"name":"flag","description":"Package flags is feature flags: ship it dark, then turn it on for who you pick."},{"name":"flow","description":"Package flow is Hanzo Flow: build an agent workflow on a visual canvas, run it, and read every run."},{"name":"framework","description":"Package framework is document types you define: describe a record once, then create, list, submit and cancel documents against it."},{"name":"function","description":"Package functions is your serverless code: publish it, call it over HTTP, watch every run and what it cost."},{"name":"gateway","description":"Package gateway is live control of the policy your API applies to every incoming request: CORS, rate limits, cache TTL and allowed methods, changed without a redeploy."},{"name":"git","description":"Package git is Git hosting for your org: create repos, clone, push, and see what they cost."},{"name":"graph","description":"Package graph is one organization's entities and the relations between them, held as assertions: somebody, at some moment, from some evidence, asserted that this thing stands in that relation to that other thing."},{"name":"guide","description":"Package guide is the AI that builds an agentic company with you, one measured step at a time."},{"name":"help","description":"Package help is a support desk: customers file tickets, your team answers them."},{"name":"iam","description":"Package iam is Hanzo's identity provider: users, organizations, applications, and the OIDC/OAuth2 endpoints every Hanzo service authenticates against."},{"name":"index","description":"Package index is fast full-text search over your own data, typos forgiven."},{"name":"ingress","description":"Package ingress is your edge: automatic TLS certificates and hostname routing to any backend, changed live."},{"name":"kms","description":"Package kms is secret custody: your org's secrets sealed at rest, plus threshold signing."},{"name":"knowledge","description":"Package knowledge is your team's wiki and your agents' memory, searchable by meaning."},{"name":"kv","description":"Package kv is your key-value store: buckets of versioned values your apps read and write by key."},{"name":"label","description":"Package label is the ground-truth plane: what actually turned out to be fraud, who said so, and when they could first have said it."},{"name":"leaderboard","description":"Package leaderboard is the ranking of who uses AI most, in your org and globally."},{"name":"legal","description":"Package legal is the paperwork your company needs, drafted, signed and filed."},{"name":"library","description":"Package library is the Library: everything a person made, in one place."},{"name":"licensing","description":"Package licensing is what an org has bought and may run: signed licenses to issue, verify and revoke, and the releases they unlock."},{"name":"link","description":"Package link is the unified AI login manager's registry: the org+user-scoped record of WHICH provider accounts (Claude Max, ChatGPT Plus, a Hanzo API key, a raw provider key) a developer has signed into, ON WHICH MACHINES, with each account's latest usage snapshot."},{"name":"lsp","description":"Package lsp is live semantic code intelligence — definitions, references, types, hover, outline and diagnostics — over a repository AND its resolved dependencies, with no toolchain on the caller's machine."},{"name":"market","description":"Package market is what trades on each chain, and how far the read of it got."},{"name":"marketing","description":"Package marketing is lifecycle email: drip sequences that reach the right people."},{"name":"marketplace","description":"Package marketplace is the one market between orgs: agents and personas to hire, apps, skills, MCP servers and tools to buy, each sold by the org that owns it, and the two-sided work one org buys from another."},{"name":"meet","description":"Package meet is the virtual office: it decides who may join a room and mints the short-lived token that lets them in."},{"name":"metrics"},{"name":"ml","description":"Package ml is model serving: deploy a model behind an endpoint and call it."},{"name":"mq","description":"Package mq is queue and stream admin for your org: create them, watch them drain, ack what you pulled."},{"name":"network","description":"Package network mounts the Hanzo Cloud NETWORKING surface: the tenant's Hanzo Zero Trust footprint — the overlay network, its routers and its services — served as clean, org-scoped REST off the unified cloud binary and fronting the Hanzo Zero Trust controller (hanzoai/zt, an ZT-based fabric)."},{"name":"node","description":"Package nodes is your machines: the ones you own, connected and ready to take a command."},{"name":"notify","description":"Package notify is transactional email and SMS, sent through your org's own provider credential."},{"name":"o11y","description":"Package o11y is your logs, metrics and traces: ship them in, query them, chart them."},{"name":"openapi","description":"The served contract: the OpenAPI document every client, tool list and command group is generated from, its command projection, the agent endpoint that offers the same operations over MCP, and the index a client follows from the API root to reach any of it."},{"name":"patent","description":"Package patent is the record of who thought of what, and when the machine was asked to write it."},{"name":"patrol","description":"Package patrol stands watch over an estate: sites, units, tours, keys, cameras, and the incidents that interrupt them."},{"name":"plan","description":"Package plan is the plan catalog: every tier you can buy, what it costs, and what it grants."},{"name":"platform","description":"Package platform is Hanzo PaaS: deploy containers to your own tenant namespace — builds, releases, environments, logs, custom domains."},{"name":"pref","description":"Package prefs is your own settings — theme, density, pinned nav — following you across every Hanzo app."},{"name":"pricing","description":"Package pricing is the price list: what every model, provider, GPU tier, tool and hosting plan costs."},{"name":"principal","description":"Package principals serves an org as an economic principal: who it is, what it may pay, and which agents answer to it."},{"name":"project","description":"Package projects is where your sites live: create one, deploy a build, roll back to any release."},{"name":"prompt","description":"Package prompts is your prompt library, versioned, so nothing changes silently."},{"name":"provider","description":"Package integrations is how your org connects third-party accounts like Slack, and revokes them."},{"name":"provisioning","description":"Package provisioning is one-click data add-ons: a SQL, key-value, document, vector, search or object store, wired straight into your app."},{"name":"pubsub","description":"Package pubsub is your message bus: publish, subscribe, and durable streams your apps read at their own pace."},{"name":"reference","description":"Package reference is the lookup data a risk decision needs but cannot derive: which email domains hand out throwaway inboxes, which addresses belong to a datacentre or a Tor exit, which card scheme an issuer prefix belongs to, which browsers the fleet sees everywhere, and how current the designation lists the screening engine holds actually are."},{"name":"referral","description":"Package referrals is referral ATTRIBUTION: who referred whom, and whether that referee ever became a real customer."},{"name":"registry","description":"Package registry is your container and package registry: push images, pull them back, see what you store."},{"name":"risk","description":"Package risk is HANZO RISK's model plane: the per-organisation feature surface and the per-organisation models trained on it."},{"name":"s3","description":"Package s3 is object storage: your buckets and the files in them, with signed URLs for upload and download."},{"name":"sandbox","description":"Package sandbox is the ONE compute primitive: a sandbox is a gVisor pod that runs somebody else's code, and every lifetime is the same object."},{"name":"sbom","description":"Package sbom is what is inside a container image: every component, resolvable by digest or image ref."},{"name":"search","description":"Package search is one ranked result set over everything your org has stored."},{"name":"security","description":"Package security is secret scanning for your code: submit sources, get findings, masked never raw."},{"name":"seo","description":"Package seo is search visibility as data: what a phrase is worth, what a site already places for, who places beside it, who links to it, and what one page gets wrong."},{"name":"settings","description":"Package settings is how an org configures each product it uses, secret fields included."},{"name":"share","description":"Package share is a public URL for a service on your own machine, and a list of what you have open."},{"name":"social","description":"Package social is posting to every social account you own, now or on a schedule."},{"name":"space","description":"Package space is where work lives: drives, folders and the files in them."},{"name":"standing","description":"Package standing prices and tracks what it costs to KEEP a company, as distinct from what it cost to form one."},{"name":"studio","description":"Package studio is Hanzo Studio's workflow backend: every creation — an image, a poster, a document, a deck, a type system, a 3D model, an ad, a film, a voice, a song — is a run of a graph of steps that the person who started it owns."},{"name":"sync","description":"Package sync is data sync: link two endpoints and keep them in step, on a webhook, on a schedule, or on demand."},{"name":"task","description":"Package task is Hanzo Task: boards, the work items on them, and the filters that make a board."},{"name":"tax","description":"Package tax is how companies formed on Hanzo exchange W-9s, W-8s and 1099s with each other, from the payments that moved between them on Hanzo's rails."},{"name":"taxonomy","description":"Package taxonomy is the product catalogue's shape: which categories exist, what each product is called, which category it sits in, what it is tagged with, and the order the two are shown in."},{"name":"team","description":"Package team is your org's shared space: documents edited together, files, seats, and agents as teammates."},{"name":"tel","description":"Package tel is the telecommunications surface: phone numbers, calls and messages, on whatever carrier the deployment is configured for."},{"name":"template","description":"Package templates is a gallery of starter kits you can deploy as they come."},{"name":"tool","description":"Package tools is everything your org can call, in one list: connector actions, functions, agents, skills and your own MCP servers."},{"name":"train","description":"Package train is the cloud's one training endpoint, /v1/train (HIP-1333): clients the caller drives on the engine, and jobs the org's linked machines or Hanzo's executor run, whose adaptation, protection, objective and output are fields and whose artifacts, bases and evaluations are what they produce."},{"name":"translate","description":"Package translate is text in, the same text out in the language you asked for."},{"name":"treasury","description":"Package treasury is the reserve fund behind every payout: real capital, held and accounted for."},{"name":"trust","description":"Package trust is your trust centre: the controls you publish, the coverage they compute to, the documents a reviewer asks for, and who you send data to."},{"name":"usage","description":"Package usage is what your org ran and what it cost, broken down per account."},{"name":"validator","description":"Package validators is one-click validator onboarding: prove your Genesis NFT, get a node provisioned, queue its registration."},{"name":"wallet","description":"Package wallets is blockchain key custody: create wallets, rotate their keys, and sign with them."},{"name":"web3","description":"Package web3 is the chain-access surface: which chains this deployment can reach, a JSON-RPC endpoint onto each, and the two token reads every wallet UI needs."},{"name":"webhook","description":"Package webhooks is how your app hears about events: register an endpoint, pick the events, get each one delivered and signed."},{"name":"websearch","description":"Package websearch is a web search and a page fetch your agents can call."},{"name":"workflow","description":"Package workflow is Hanzo Workflow: durable workflows that survive a crash, with every run visible and replayable."},{"name":"world","description":"Package world is a live news feed filtered to what your project cares about."},{"name":"x402","description":"Package x402 is pay-per-request over HTTP 402: quote a price, take the payment, serve the resource."}],"paths":{"/v1":{"get":{"operationId":"get_capabilities","summary":"Every capability this deployment answers, and where to follow each one","description":"The API root. One row per capability — its name, the address it answers under, whether it is generally available, and the sentence it says about itself — plus the links to the document at /v1/openapi.json and the agent MCP server.\n\nIt is a projection of that same document and carries the same surface a customer calls: the operator's admin product, the relays, the legacy spellings and any capability that is not yet generally available are in neither.\n\nUnauthenticated by design, exactly as the document it derives from: a client has to be able to read the contract before it holds a credential, and a list of capability names grants nothing.","tags":["openapi"],"responses":{"2XX":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Root"}}}}},"security":[],"x-app":"openapi","x-public":true}},"/v1/account/appearance":{"get":{"operationId":"get_account_appearance","summary":"Returns the signed-in caller's own appearance preference — text size, density and accent — read from their IAM account so it is the same on every device and every Hanzo surface.","description":"Returns the signed-in caller's own appearance preference — text\nsize, density and accent — read from their IAM account so it is the same on\nevery device and every Hanzo surface. An unset preference is an empty object.\n\nA transient IAM read failure reports the empty preference rather than a 5xx, so\na surface applies its published default and never error-toasts on load — the\nsame fail-soft the key read uses.","tags":["account"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/account.appearance"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"account","x-public":true,"x-tool":true},"post":{"operationId":"post_account_appearance","summary":"Stores the caller's appearance preference on their IAM account, preserving every other field of the row.","description":"Stores the caller's appearance preference on their IAM account,\npreserving every other field of the row. The accent is validated as a real\ncolour token before it is stored; an unset or invalid axis is dropped rather\nthan stored.","tags":["account"],"requestBody":{"content":{"application/json":{"example":{"accent":"#8b5cf6","density":"compact","type":1.15},"schema":{"$ref":"#/components/schemas/account.appearance"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/account.appearance"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"account","x-public":true,"x-tool":true}},"/v1/account/avatar":{"post":{"operationId":"post_account_avatar","summary":"Set your profile photo","description":"Stores one image as the signed-in user's profile photo and answers the URL it is served from, which is also written to the user's IAM record — so every surface that already renders `avatar` picks it up with no further call.\n\nThe body is a multipart form with a `file` part. The format is decided by the BYTES, never the filename or the part's Content-Type: png, jpeg, gif and webp are accepted and everything else is refused with 415, so an SVG cannot be stored as a picture and later served as a program. Over 8 MiB is 413; empty is 400.\n\nThe photo is addressed by the sha256 of its bytes, so setting a new one yields a new URL rather than a stale cache of the old face. The caller is taken from the validated identity ONLY — there is no way to name a different subject — so this always sets your own photo, and a caller with no organization yet is refused.","tags":["account"],"x-app":"account","x-public":true}},"/v1/account/avatar/{org}/{user}/{digest}":{"get":{"operationId":"get_account_avatar_by_org_by_user_by_digest","summary":"Fetch a profile photo","description":"Streams a profile photo's raw BYTES. This is the address stored on the user's IAM record and rendered directly by an `\u003cimg\u003e`, so it takes no credentials — the 64-hex content digest in the path is the capability, and it can only be produced by someone who already has the image.\n\nThe Content-Type is derived from the stored bytes and the response carries nosniff, so only a real raster image is ever served and only under its true type. Anything else — a miss, a malformed path, an object that is not an image — is one 404, and a hit caches for a year because the address is the content.","tags":["account"],"parameters":[{"name":"org","in":"path","required":true,"schema":{"type":"string"}},{"name":"user","in":"path","required":true,"schema":{"type":"string"}},{"name":"digest","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"account","x-public":true}},"/v1/account/csrf":{"get":{"operationId":"get_account_csrf","summary":"Mints the anti-forgery token a browser echoes as X-CSRF-Token on every change it asks for.","description":"Mints the anti-forgery token a browser echoes as X-CSRF-Token on\nevery change it asks for. The token is bound to the caller's validated identity\nand expires, so one minted for one identity cannot authorize a change as another.\n\nIt is answered no-store, so it is never cached by a shared proxy. This is the\nsame-origin endpoint the embedded console reads — the Same-Origin Policy is what\nstops a cross-site page from reading the response and forging a change.","tags":["account"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/account.csrfResp"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"account","x-public":true,"x-tool":true}},"/v1/account/embed":{"get":{"operationId":"get_account_embed","summary":"Reports whether one of this brand's shared embedded apps (cms, erp, help) may be framed by the caller and is actually running, so a console module can choose between the embed and the provision panel.","description":"Reports whether one of this brand's shared embedded apps (cms, erp,\nhelp) may be framed by the caller and is actually running, so a console module\ncan choose between the embed and the provision panel.\n\nIt answers two questions the browser cannot answer for itself. ENTITLEMENT is\nserver-authoritative: each app is a single shared per-BRAND instance, so only a\nmember of the owning brand org — or a SuperAdmin — is given the embed URL; every\nother caller gets phase \"not-entitled\" and no URL. REACHABILITY is a probe of\nthat origin, which a cross-origin page cannot read for itself.\n\nThe probed host is always \u003capp\u003e.\u003cthis deployment's own brand domain\u003e: no part of\nit comes from the request, so this can never be steered into probing an\narbitrary origin.","tags":["account"],"parameters":[{"name":"app","in":"query","required":false,"description":"App is the embedded app to report on: cms (Content Studio), erp or help.","schema":{"type":"string"},"example":"cms"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/account.embedStatusResp"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"account","x-public":true,"x-tool":true}},"/v1/account/keys":{"get":{"operationId":"get_account_keys","summary":"Returns the API keys the caller may see, newest first: their own, or every key the org holds when the caller administers it.","description":"Returns the API keys the caller may see, newest first: their own, or\nevery key the org holds when the caller administers it. Each is its own\ncredential with its own name, prefix, status, expiry and limit. Revoked keys\nstay listed. No secret material comes back; a publishable key, which is public\nby construction, carries its full value.","tags":["account"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/account.apiKeyList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"account","x-public":true,"x-tool":true},"post":{"operationId":"post_account_keys","summary":"Creates a NEW API key and returns its secret ONCE.","description":"Creates a NEW API key and returns its secret ONCE. It never revokes\nor changes any other key: every key the caller already holds keeps working.\nThe key is filed in the org the caller acts in and names them as its creator.\n\nAn org holds at most 1,000 live keys; past that the create is refused until one\nis revoked.","tags":["account"],"requestBody":{"content":{"application/json":{"example":{"budget":{"month":5000,"total":0},"name":"production","rate":600,"type":"secret"},"schema":{"$ref":"#/components/schemas/account.keyIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/account.apiKey"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"account","x-public":true,"x-tool":true}},"/v1/account/keys/{id}":{"delete":{"operationId":"delete_account_keys_by_id","summary":"Revokes exactly one API key, by id.","description":"Revokes exactly one API key, by id. Every other key keeps working.\nThe key stays listed as revoked, with who revoked it and when, and can never be\nused again. IAM refuses it at once; cloud caches a resolved key for up to 60\nseconds, so a request inside that window may still be served.\n\nA member revokes their own keys; an org admin revokes any of the org's, and\nrevoking someone else's is recorded on the audit trail.","tags":["account"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the key to act on, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/account.apiKey"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"account","x-public":true,"x-tool":true},"patch":{"operationId":"patch_account_keys_by_id","summary":"Changes one key's name, permissions, budget, rate or expiry.","description":"Changes one key's name, permissions, budget, rate or expiry. The secret\nis not reissued: the key in your deployment keeps working, under its new\npolicy. Only the person the key belongs to may edit it, and a revoked key\ncannot be edited.","tags":["account"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the key to edit, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"budget":{"month":5000,"total":0},"limit":["read:*"],"name":"staging","rate":60},"schema":{"$ref":"#/components/schemas/account.keyEdit"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/account.apiKey"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"account","x-public":true,"x-tool":true}},"/v1/account/orgs":{"post":{"operationId":"post_account_orgs","summary":"Creates an organization and makes the caller its owner.","description":"Creates an organization and makes the caller its owner.\n\nThe caller's own account is not touched: who they are, the org their account\nlives in and how they sign in are the same before and after. The new org is a\nseparate organization they belong to by membership, carried in the signed\n`orgs` claim of their next token, and reached by selecting it (X-Org-Id, the\norg switcher). Teammates join it the same way. The org starts at a zero\nbalance, and its default API key is minted for the creator and returned once.\n\nMoving the creator into the org instead re-keyed their identity to\n\"\u003corg\u003e/\u003cname\u003e\", and sign-in, which resolves an address in the signup org,\nthen found nobody: the person was offered a second account for their own\naddress.","tags":["account"],"requestBody":{"content":{"application/json":{"example":{"name":"Acme"},"schema":{"$ref":"#/components/schemas/account.onboardReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/account.onboardResp"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"account","x-public":true,"x-tool":true}},"/v1/ad/campaigns":{"get":{"operationId":"get_ad_campaigns","summary":"Returns the caller org's ad campaigns, most recently updated first, optionally narrowed to one lifecycle status.","description":"Returns the caller org's ad campaigns, most recently updated\nfirst, optionally narrowed to one lifecycle status. The listing is bounded by\nthe org: another tenant's campaigns are not reachable from here at all.","tags":["ad"],"parameters":[{"name":"status","in":"query","required":false,"description":"Status filters to one lifecycle state (draft, active, paused, completed).\nEmpty returns every campaign the org has.","schema":{"type":"string"},"example":"active"},{"name":"limit","in":"query","required":false,"description":"Limit caps how many campaigns come back: default 200, maximum 1000. A\nvalue that is not a positive integer reads as the default.","schema":{"format":"int64","type":"integer"},"example":50}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ad.campaignList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ad","x-public":true,"x-tool":true},"post":{"operationId":"post_ad_campaigns","summary":"Registers a new ad campaign for the caller's org and answers 201 with the stored row.","description":"Registers a new ad campaign for the caller's org and answers\n201 with the stored row. It only records the campaign — nothing is sent to the\nad network until POST /v1/ad/campaigns/{id}/launch runs it. The org is\nstamped by the server from the validated principal, so a body can never place\na campaign in another tenant.","tags":["ad"],"requestBody":{"content":{"application/json":{"example":{"budget":50000,"name":"Spring Launch","objective":"conversions","platform":"meta"},"schema":{"$ref":"#/components/schemas/ad.campaignInput"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ad.AdCampaign"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ad","x-public":true,"x-tool":true}},"/v1/ad/campaigns/{id}":{"delete":{"operationId":"delete_ad_campaigns_by_id","summary":"Removes one of the caller org's campaigns and answers 204 with no body.","description":"Removes one of the caller org's campaigns and answers 204 with\nno body. It deletes the stored record only: a campaign already launched keeps\nrunning on the ad network, which must be stopped there. An id another org owns\nreads as not found.","tags":["ad"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"camp_2f9c1d"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ad","x-public":true,"x-tool":true},"get":{"operationId":"get_ad_campaigns_by_id","summary":"Returns one of the caller org's campaigns.","description":"Returns one of the caller org's campaigns. An id another org owns\nreads as not found, so the response cannot confirm that it exists.","tags":["ad"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"camp_2f9c1d"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ad.AdCampaign"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ad","x-public":true,"x-tool":true},"put":{"operationId":"put_ad_campaigns_by_id","summary":"Replaces the user-owned fields of one of the caller org's campaigns and answers the stored row.","description":"Replaces the user-owned fields of one of the caller org's\ncampaigns and answers the stored row. It is a full replace, not a patch: every\nfield is written from the request, so an omitted one is cleared. externalId is\nlaunch-owned and is never touched here, so editing a campaign cannot break its\nlink to a live provider execution.","tags":["ad"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"camp_2f9c1d"}],"requestBody":{"content":{"application/json":{"example":{"budget":75000,"id":"camp_2f9c1d","name":"Spring Launch","platform":"meta","status":"paused"},"schema":{"$ref":"#/components/schemas/ad.updateCampaignIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ad.AdCampaign"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ad","x-public":true,"x-tool":true}},"/v1/ad/campaigns/{id}/launch":{"post":{"operationId":"post_ad_campaigns_by_id_launch","summary":"Run one of your stored campaigns on its ad network","description":"Creates the campaign on its platform under the CALLER ORG'S own connected ad account, records the provider campaign id, flips the stored campaign to active and answers the updated record. No ad-network token is held here: it is resolved from KMS through the org's connector at launch time, BEFORE any provider call, so an org that has not connected that platform gets 424 and no spend can ever start on a connection the org did not make. Meta is executed for real; a campaign on a platform whose provider is not wired yet answers 501 even when the connector is connected, and an edge failure at the platform is 502. The optional {account} body overrides the target ad account for this launch and is TOLERANT — a malformed or non-JSON body is ignored and the campaign launches on its stored account rather than being refused. A campaign id another org owns reads as not found.","tags":["ad"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"ad","x-public":true}},"/v1/ad/summary":{"get":{"operationId":"get_ad_summary","summary":"Rolls the caller org's ad campaigns up into four numbers: how many campaigns exist, how many are active, and the summed budget and spend across all of them.","description":"Rolls the caller org's ad campaigns up into four numbers: how many\ncampaigns exist, how many are active, and the summed budget and spend across\nall of them. Budget and spend are MINOR units (cents), the same units the\ncampaign rows carry. It counts only this org's campaigns.","tags":["ad"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ad.adSummary"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ad","x-public":true,"x-tool":true}},"/v1/affiliate":{"get":{"operationId":"get_affiliate","summary":"Answers the caller org's OWN affiliate standing: status, referral code and share link, commission rate, how many orgs it has referred, and its lifetime accrued, still-pending and already-paid commission in integer cents, with its payout history.","description":"Answers the caller org's OWN affiliate standing: status, referral\ncode and share link, commission rate, how many orgs it has referred, and its\nlifetime accrued, still-pending and already-paid commission in integer cents,\nwith its payout history.\n\nAn org that never applied gets an honest `isAffiliate:false` and the default\nrate rather than a 404 — the console renders the apply form off that answer.\n\nThe affiliate is resolved from the VALIDATED org, never from a field, so this\ncan only ever read the caller's own row; without a principal it is refused. It\nis a PURE READ: nothing accrues until the sweep runs. Commission is earned on\nHanzo's MARGIN, never on the referred customer's bill, so nothing here changes\nwhat that customer pays.","tags":["affiliate"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/affiliate.affiliateStanding"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"affiliate","x-public":true,"x-tool":true}},"/v1/affiliate/apply":{"post":{"operationId":"post_affiliate_apply","summary":"Enrolls the caller's OWN org as an affiliate at status `applied`, optionally requesting a vanity code, and answers the record — 201 on the first apply, 200 with `created:false` afterwards.","description":"Enrolls the caller's OWN org as an affiliate at status `applied`,\noptionally requesting a vanity code, and answers the record — 201 on the first\napply, 200 with `created:false` afterwards.\n\nIDEMPOTENT, first apply wins: one affiliate per org, so re-applying never\ncreates a second row and never resets an existing approval. Applying is not\njoining — no code is minted and nothing accrues until staff approve, which is\nwhere both the code and the commission rate come from.\n\nThe org is the validated caller's, never a field. A malformed vanity code is\nrefused up front; the code is only REQUESTED here, and approval may mint a\ndifferent one if the requested code is taken.","tags":["affiliate"],"requestBody":{"content":{"application/json":{"example":{"requestedCode":"acme"},"schema":{"$ref":"#/components/schemas/affiliate.applyRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/affiliate.application"}}},"description":"ok"},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/affiliate.application"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"affiliate","x-public":true,"x-tool":true}},"/v1/affiliate/attribute":{"post":{"operationId":"post_affiliate_attribute","summary":"Records the first-touch edge every later commission is computed from: the caller's org was referred by the affiliate that owns this code.","description":"Records the first-touch edge every later commission is computed\nfrom: the caller's org was referred by the affiliate that owns this code.\n\nThe REFERRED org is the validated caller, never a field. A caller that could\nname the referred org could attach itself to somebody else's revenue. The\naffiliate is resolved from the code, and only an APPROVED affiliate's code\nresolves.\n\nFIRST TOUCH WINS, set once: one affiliate per referred org, so a re-post\nanswers the existing edge with `created:false` rather than moving the\nattribution. Self-attribution is refused, and so is a code that would make a\ncycle in the upline chain. An unknown code is a 404, deliberately: an\naffiliate code IS a public shareable link, so whether one is real is public by\ndesign, and the caller legitimately needs to know its link resolved.\n\nA user-level mirror of the edge is written best-effort; a conflict there never\nfails the org attribution, which is the money-bearing one.","tags":["affiliate"],"requestBody":{"content":{"application/json":{"example":{"code":"acme"},"schema":{"$ref":"#/components/schemas/affiliate.attributeRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/affiliate.attribution"}}},"description":"ok"},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/affiliate.attribution"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"affiliate","x-public":true,"x-tool":true}},"/v1/affiliate/click":{"post":{"operationId":"post_affiliate_click","summary":"Counts a click on a share link.","description":"Counts a click on a share link. PUBLIC — it takes no principal, because\na visitor clicking a shareable link has no session yet.\n\nThe ping folds into an in-memory buffer and NEVER writes the money database\nsynchronously, so a click flood cannot contend with the accrual and payout\nwrite path; tallies are flushed in one batch on the next authenticated links\nread and at shutdown. Clicks are a vanity metric: no accrual and no payout\never reads them — those key on real metered spend — so click inflation cannot\nmove money.\n\nAny well-formed code is accepted WITHOUT checking that it exists,\ndeliberately: this is not a code-existence oracle. `counted` reports that the\nbuffer took the ping, not that the code is real; an unknown code simply no-ops\nat flush time.","tags":["affiliate"],"requestBody":{"content":{"application/json":{"example":{"code":"acme"},"schema":{"$ref":"#/components/schemas/affiliate.clickRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/affiliate.clickCount"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"affiliate","x-public":true,"x-tool":true}},"/v1/affiliate/leaderboard":{"get":{"operationId":"get_affiliate_leaderboard","summary":"Answers the top affiliates by lifetime accrued commission, shown by OPT-IN HANDLE with aggregate figures only, plus the caller's own exact rank.","description":"Answers the top affiliates by lifetime accrued commission, shown by\nOPT-IN HANDLE with aggregate figures only, plus the caller's own exact rank.\n\nIt never discloses an org identity and never a referred org's usage. An\naffiliate that has set no handle still OCCUPIES its rank but is not listed —\nso opting out hides the name, not the position, and the visible board must not\nbe read as a complete roster.\n\nThe caller's own row carries its exact GLOBAL rank, computed over the whole\napproved set rather than over the page, so it is right well outside the top of\nthe board. Only an approved affiliate has a rank. Requires a validated\nprincipal; a signed-in non-affiliate may read the board but gets no personal\nrow.","tags":["affiliate"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/affiliate.affiliateBoard"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"affiliate","x-public":true,"x-tool":true}},"/v1/affiliate/me":{"get":{"operationId":"get_affiliate_me","summary":"Answers the richer self-view: the same lifetime accrued, pending and paid commission and payout history, plus the caller's downline broken out by upline LEVEL — direct, second, third — each with the rate paid at that level and how many orgs sit there.","description":"Answers the richer self-view: the same lifetime accrued, pending and paid\ncommission and payout history, plus the caller's downline broken out by upline\nLEVEL — direct, second, third — each with the rate paid at that level and how\nmany orgs sit there.\n\nCommission is MULTI-LEVEL: a referred org's spend pays up its referral chain,\nthree levels deep and no further. The direct level is the affiliate's own\nnegotiated rate; the second and third are platform-wide switches, read live,\nso the schedule shown is the one actually in force rather than one compiled\nin. A caller that has not applied still gets that schedule alongside\n`isAffiliate:false`, so the console can show what it would earn.\n\nScoped to the validated org and nothing else, and refused without a\nprincipal. A PURE READ — it reports the downline but accrues nothing.","tags":["affiliate"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/affiliate.affiliateSelf"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"affiliate","x-public":true,"x-tool":true}},"/v1/affiliate/me/earnings":{"get":{"operationId":"get_affiliate_me_earnings","summary":"Answers the caller's own commission ledger: per period, the margin it earned against and the commission taken from that margin; and per referred org, that referral's aggregate contribution.","description":"Answers the caller's own commission ledger: per period, the margin it\nearned against and the commission taken from that margin; and per referred\norg, that referral's aggregate contribution. Integer cents throughout.\n\nThe per-org view deliberately carries the affiliate's OWN earned share and NOT\nthe referred org's spend or margin. An affiliate is entitled to what it\nearned, not to a restatement of its customer's usage — the period view is\nwhere the margin base appears, aggregated across every referral.\n\nScoped server-side to the validated caller's affiliate; a caller that is not\none gets `isAffiliate:false`.","tags":["affiliate"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/affiliate.affiliateEarnings"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"affiliate","x-public":true,"x-tool":true}},"/v1/affiliate/me/handle":{"post":{"operationId":"post_affiliate_me_handle","summary":"Sets the caller's public leaderboard display name, or clears it.","description":"Sets the caller's public leaderboard display name, or clears it.\n\nThe handle IS the opt-in. An empty handle opts out: the affiliate keeps its\nrank and can still see its own row, it simply stops being listed to anyone\nelse. That is the whole privacy control — there is no separate visibility\nflag, and no way to be listed without choosing a name.\n\nRequires a validated principal and an existing affiliate record; apply first.\nThe handle is bounded and restricted to letters, digits, space, hyphen,\nunderscore and dot.","tags":["affiliate"],"requestBody":{"content":{"application/json":{"example":{"handle":"acme partners"},"schema":{"$ref":"#/components/schemas/affiliate.handleRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/affiliate.handleSet"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"affiliate","x-public":true,"x-tool":true}},"/v1/affiliate/me/links":{"get":{"operationId":"get_affiliate_me_links","summary":"Answers the caller's share links, each with its URL and its funnel: clicks tracked, signups — orgs attributed with that code — and conversions, meaning how many of those signups have actually produced commission.","description":"Answers the caller's share links, each with its URL and its funnel:\nclicks tracked, signups — orgs attributed with that code — and conversions,\nmeaning how many of those signups have actually produced commission.\n\nSignups and conversions are DERIVED from the commission ledger and never\nstored, so they cannot drift from the money. Clicks are the one stored counter\nand the one that is pure vanity.\n\nAny pending public click pings are folded into the store before the read, in\none batch — which is how the counters stay current without a database write\nper click. Scoped to the validated caller's own affiliate; a non-affiliate\ngets `isAffiliate:false` and the link cap.","tags":["affiliate"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/affiliate.affiliateLinks"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"affiliate","x-public":true,"x-tool":true},"post":{"operationId":"post_affiliate_me_links","summary":"Mints a new share link for the caller's own affiliate and answers it with its full URL, 201.","description":"Mints a new share link for the caller's own affiliate and answers it\nwith its full URL, 201.\n\nAPPROVAL IS REQUIRED: an org that has applied but is not approved is refused,\nbecause a link that cannot accrue is a link that quietly loses the referral. A\nrequested vanity code must be valid and free across the WHOLE directory —\ncodes are one global namespace, so a taken code is a 409 rather than a silent\nalias. Omit the code and a random one is minted.\n\nBounded per affiliate. The label is cosmetic: it is trimmed, stripped of\ncontrol characters and capped, and it is never part of a code.","tags":["affiliate"],"requestBody":{"content":{"application/json":{"example":{"label":"twitter"},"schema":{"$ref":"#/components/schemas/affiliate.createLinkRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/affiliate.linkMint"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"affiliate","x-public":true,"x-tool":true}},"/v1/agent":{"get":{"operationId":"get_agent","summary":"Returns every agent defined in the caller's org, each with the number of runs recorded against it.","description":"Returns every agent defined in the caller's org, each with the\nnumber of runs recorded against it.","tags":["agent"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.agentList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true},"post":{"operationId":"post_agent","summary":"Defines an agent in the caller's org: a model, a system prompt (instructions) and a set of tool names.","description":"Defines an agent in the caller's org: a model, a system prompt\n(instructions) and a set of tool names. The name must be unique in the org and\nmatch ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$. An omitted model takes the\ndeployment's configured default; a named one is checked against the gateway's\nserved catalog, so a model this deployment never serves is refused here rather\nthan failing at run time. A long-running agent must carry a 5-field cron\nschedule (the scheduler would otherwise never fire it) and counts against a\nper-org cap on scheduled agents. An agent spawned by another names it as its\nparent; the parent must be an agent of the caller's org, and the new agent\ncarries its whole lineage.","tags":["agent"],"requestBody":{"content":{"application/json":{"example":{"instructions":"be terse","model":"enso-flash","name":"helper"},"schema":{"$ref":"#/components/schemas/agent.createAgentIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.agentView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/activity":{"get":{"operationId":"get_agent_activity","summary":"Serves the recent-activity feed.","description":"Serves the recent-activity feed. Events are REAL: each of the\ncaller's own recorded runs is an invoked (ok) or failed (error) event; each of\nthe org's agents' create/update timestamps are created/updated events. Merged, newest first,\ncapped. Nothing is invented — an org with no agents and no runs gets [].","tags":["agent"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.activityFeed"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/ask":{"post":{"operationId":"post_agent_ask","summary":"The MCP server a coding run's harness asks its person through.","description":"Speaks MCP over streamable HTTP and serves one tool, ask_user: a question and 2 to 8 options, shown as buttons in the run's thread, answered by the person the run is for. The call waits for the answer, up to 30 minutes, streaming as text/event-stream with a comment every 15 seconds, and returns it as the tool's result, or says none came.\n\nThe caller is a coding run, not a tenant: the request carries the run's ticket in X-Hanzo-Run and no bearer. The ticket is minted for one run, opens this server and nothing else, names the run the question belongs to, and ends with the run. A request without a live ticket is 401, and any tool but ask_user is refused.","tags":["agent"],"x-app":"agent","x-public":true}},"/v1/agent/builds":{"get":{"operationId":"get_agent_builds","summary":"Returns the public index of every published build, most recently updated first, so a gallery can link straight to the story behind each product.","description":"Returns the public index of every published build, most recently\nupdated first, so a gallery can link straight to the story behind each product.\nPUBLIC, no tenancy: publishing is the author's act, and only published root\nsessions appear here.","tags":["agent"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit caps the page. Absent, zero or over 500 reads as 100.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.buildList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/builds/{org}/{project}":{"get":{"operationId":"get_agent_builds_by_org_by_project","summary":"Returns the readable build of one product: the agent session that produced it, turn by turn — the prompts, the reasoning, the commits each turn produced — plus the exact `git log` that re-derives every commit binding from git itself, so nothing here has to be taken on trust.","description":"Returns the readable build of one product: the agent session that\nproduced it, turn by turn — the prompts, the reasoning, the commits each turn\nproduced — plus the exact `git log` that re-derives every commit binding from\ngit itself, so nothing here has to be taken on trust.\n\nPUBLIC, no tenancy: it answers only for a session its author explicitly\npublished, which is what makes it safe to be anonymous. An unpublished session\nis invisible here no matter who asks; its owner reads it through the org-scoped\n/v1/agent/sessions routes, which need a validated principal.","tags":["agent"],"parameters":[{"name":"org","in":"path","required":true,"description":"Org is the org that published the build, from the path.","schema":{"type":"string"},"example":"hanzo"},{"name":"project","in":"path","required":true,"description":"Project is the product's slug, from the path.","schema":{"type":"string"},"example":"landing"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.buildView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/chat":{"post":{"operationId":"post_agent_chat","summary":"Run one tool-calling round against your org's own tools","description":"Answers one turn of a conversation with four things: the model's `reply`, the `actions` the server executed on the caller's behalf, the `ops` the client must apply itself, and the `conversationId` the turn was recorded under.\n\nThe split between actions and ops is the rule most easily got wrong. A tool call is executed HERE only when the chosen preset is server-executing AND the tool resolves in the caller's own scope; every other call is handed back as an op for the client to apply to its own graph or UI. A tool that fails still comes back as an action, carrying its error rather than failing the round.\n\n`preset` selects the system prompt and the tool set (`capability` is a legacy alias for it); an unknown one is refused. `conversationId` continues an existing thread, and its absence starts one. A validated principal with a non-empty org is required — the org is the sole authority for both persistence and tool scope, and is NEVER read from the body.\n\nA completion refused for the caller's own reason — 402 insufficient balance, 429, 403 — is relayed with its own status and body verbatim, so the real billing message reaches the client instead of an opaque gateway error. Only a genuine upstream fault becomes a 502.","tags":["agent"],"x-app":"agent","x-public":true}},"/v1/agent/chat/conversations":{"get":{"operationId":"get_agent_chat_conversations","summary":"List your own conversations","description":"Returns a summary of each conversation the caller opened — id, title, when it was last appended to, and whether it is pinned or archived — for populating a thread list: pinned first, then most recent. Archived conversations are left out; `?archived=true` lists them alone.\n\nA conversation is the person's who opened it, not the org's: another member of the same org lists none of it. Each org's conversations live in a store of its own, and inside it only the caller's are listed. One recorded before members were kept names nobody and is nobody's: `?memberless=true` lists those instead, for a SuperAdmin alone (403 for anyone else), and each such list is audited. A validated principal naming an org and a user the identity boundary attests no two people share is required: 401 without a principal, 403 without an org or such a user.","tags":["agent"],"x-app":"agent","x-public":true},"post":{"operationId":"post_agent_chat_conversations","summary":"Record turns in a conversation","description":"Writes turns to the caller's thread store without running a completion, and answers the `conversationId` they were written under. An absent `conversationId` opens a new thread; supplying one appends to it.\n\nThis is for a client that streams its own turn through /v1/chat/completions and still wants the conversation in its history — the round records what IT answers, and is otherwise the only writer. It takes the same store, the same per-org isolation and the same notion of a thread: what is recorded here reads back through the two GETs beside it and the round can continue it by id. A validated principal with a non-empty org is required: 401 without a principal, 403 without an org.","tags":["agent"],"x-app":"agent","x-public":true}},"/v1/agent/chat/conversations/{id}":{"delete":{"operationId":"delete_agent_chat_conversations_by_id","summary":"Delete one of your conversations","description":"Removes the conversation for good: every turn of it, and every link it was shared by, which stops opening and leaves the lists of the people it was open to. Only the member who opened it may delete it; anyone else is answered 404, as for one that is not there. Every delete is written to the audit trail.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"agent","x-public":true},"get":{"operationId":"get_agent_chat_conversations_by_id","summary":"Read one agent thread in full","description":"Returns every message of one of the caller's conversations in order — role, content, the assistant's tool calls where it made any, and each message's creation time — which is the transcript a client replays to resume a thread.\n\nAnother member's conversation, another org's, and one recorded with no member are answered 404, exactly as an id that never existed, so an id says nothing about whose it is (a SuperAdmin alone reads one with no member, and each read is audited). A turn sent under such an id opens a fresh conversation of the caller's. A validated principal naming an org and a user is required: 401 without a principal, 403 without an org or a user.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"agent","x-public":true},"patch":{"operationId":"patch_agent_chat_conversations_by_id","summary":"Rename, pin or archive one of your conversations","description":"Takes `{title?, pinned?, archived?}` and changes what it names, leaving the rest; a body naming none is refused 400, and so is an empty title. A title is cut to one line of at most 80 characters. Answers the conversation as the list does — id, title, updatedAt, pinned, archived — and the change does not move `updatedAt`, which stays when it was last spoken in.\n\nThe list puts pinned conversations first and leaves archived ones out; `?archived=true` lists those alone. Only the member who opened the conversation may change it; another member's, another org's, and one recorded with no member answer 404. Every change is written to the audit trail.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"agent","x-public":true}},"/v1/agent/chat/conversations/{id}/shares":{"get":{"operationId":"get_agent_chat_conversations_by_id_shares","summary":"List the live links to one of your conversations","description":"Returns each unrevoked share of a conversation the caller owns: its id, its access (`read`), when it was made, and its `viewers` — each signed-in person who opened it, with the name they signed in with and when. Tokens are not in the list; they are returned only when a share is made.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"agent","x-public":true},"post":{"operationId":"post_agent_chat_conversations_by_id_shares","summary":"Share one of your conversations by link","description":"Makes a read-only link to a conversation the caller owns and answers the share and its `token`. The token is 256 random bits and is returned ONCE: the store keeps only its SHA-256, so a lost token is replaced by making another share, never read back. The token names the chat and authenticates nobody.\n\nA share is a snapshot of the user and assistant turns up to the moment it was made. System turns, tool calls and tool results are never part of it, and turns added later need a new share. Only the member who opened the conversation may share it; anyone else — and anyone at all for a conversation recorded with no member — is answered 404. Every share made is written to the audit trail.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"agent","x-public":true}},"/v1/agent/chat/conversations/{id}/shares/{share}":{"delete":{"operationId":"delete_agent_chat_conversations_by_id_shares_by_share","summary":"Revoke a link to one of your conversations","description":"Ends one share of a conversation the caller owns, for every viewer: it leaves their lists, and its token opens nothing and reads exactly like a token that never existed. Every revoke is written to the audit trail.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"share","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"agent","x-public":true}},"/v1/agent/chat/conversations/{id}/shares/{share}/viewers/{viewer}":{"delete":{"operationId":"delete_agent_chat_conversations_by_id_shares_by_share_viewers_by_viewer","summary":"Remove one viewer from a link","description":"Closes one share of a conversation the caller owns to one viewer: it leaves their list, and the token no longer opens it for them. Everyone else the share is open to keeps it. Every removal is written to the audit trail.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"share","in":"path","required":true,"schema":{"type":"string"}},{"name":"viewer","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"agent","x-public":true}},"/v1/agent/chat/presets":{"get":{"operationId":"get_agent_chat_presets","summary":"List the agent presets available to a caller","description":"Returns the preset catalog: each entry's id, its description and whether it is server-executing — the flag that decides if a preset's tool calls run here or come back for the client to apply. The ids are what the round accepts in `preset`.\n\nThe catalog is compiled into the build, identical for every caller, and this is the one read in the group that needs no principal.","tags":["agent"],"x-app":"agent","x-public":true}},"/v1/agent/chat/shared":{"get":{"operationId":"get_agent_chat_shared","summary":"List the chats shared with you","description":"Returns each live share the caller opened signed in: its id, the conversation's title and when the caller first opened it, most recent first. A revoked share, or one its owner closed to the caller, is not in it. A signed-in person is required.","tags":["agent"],"x-app":"agent","x-public":true}},"/v1/agent/chat/shared/{share}":{"get":{"operationId":"get_agent_chat_shared_by_share","summary":"Read a chat shared with you","description":"Returns the snapshot of a share the caller is a viewer of, without its token, in the shape POST /shares/read answers a signed-in person. Anyone who is not one of its viewers is answered 404.","tags":["agent"],"parameters":[{"name":"share","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"agent","x-public":true}},"/v1/agent/chat/shares":{"get":{"operationId":"get_agent_chat_shares","summary":"List every live link in your organization","description":"For an admin of the caller's organization: every unrevoked share made in it, with the conversation's id and title, the member who made it, when, and how many people it is open to. `?user=` narrows it to one member's. Anyone else is answered 403, and so is an admin of a held org such as hanzo, whose members are customers who are strangers to each other.","tags":["agent"],"x-app":"agent","x-public":true}},"/v1/agent/chat/shares/read":{"post":{"operationId":"post_agent_chat_shares_read","summary":"Open a conversation shared by link","description":"Takes `{token}` in the body, so the token never sits in a URL a log keeps. A caller who is not a signed-in person gets the title and `full: false`, and no turn of the transcript — which is what a sign-in prompt shows. A signed-in person, of any org, is recorded as a viewer the owner can see, and reads the whole snapshot with the share's id; the reader's own org is neither read nor changed. An assistant turn carries `model` only when this server stored it from that model's completion. A token that does not open — malformed, unknown, revoked, or closed to this viewer — is answered 404 with one sentence for all.","tags":["agent"],"x-app":"agent","x-public":true}},"/v1/agent/chat/shares/{share}":{"delete":{"operationId":"delete_agent_chat_shares_by_share","summary":"Revoke any link in your organization","description":"For an admin of the caller's organization: ends one share made in it, for every viewer, exactly as its owner's revoke does. Anyone else is answered 403 (an admin of a held org included), and a share of another organization 404. Every revoke is written to the audit trail.","tags":["agent"],"parameters":[{"name":"share","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"agent","x-public":true}},"/v1/agent/coding":{"post":{"operationId":"post_agent_coding","summary":"Start one autonomous coding run against a repo in the caller's org","description":"Runs a coding task on a repository: clones it into a sandbox, lets a model read\nand edit the code, run the tests, and push the work to a branch. Say the thing\nyou want done — \"fix the failing auth test in hanzoai/cloud\" — and the run\ninfers the repo, the branch and the plan. No prefix, no ceremony.\n\nName no repo and the run works in an empty workspace of its own: nothing is\ncloned and nothing is pushed, and what it makes is kept in its sandbox and as\nits artifacts. Name a repository the caller can read and not push to — a public\none — and it is cloned read-only, the same way.\n\nIt answers 202 with the run's handle the moment the run is ADMITTED — not when\nit finishes. A coding run takes minutes; holding a request open for one would\ntie a connection to a model loop and give the caller nothing it cannot get\nbetter from the session stream.\n\nThe handle is a session id, and that is deliberate: the session is already the\nrun's durable record and its live stream (/v1/agent/sessions/stream?root=\u003cid\u003e), so\nthis op does not grow a progress endpoint, a status endpoint or a cancel\nendpoint of its own. One way to watch a run, whoever started it.\n\nIt is also how work CONTINUES. Pass an earlier run's session as `after` and\nthis one starts from where that one stopped, so \"now add tests for it\" builds\non the branch already pushed instead of a fresh clone. The follow-up still gets\nits own branch and its own session — one run, one branch, always reviewable on\nits own.","tags":["agent"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.CodingStartIn"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.CodingStarted"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/coding/{session}/artifacts":{"get":{"operationId":"get_agent_coding_by_session_artifacts","summary":"Lists what a coding run left, kept after its sandbox is gone: every file it added or changed and its whole change as `changes.patch`, stored beside the run; the ports it served, each a preview while its sandbox is kept; its pull request and where its work was published.","description":"Lists what a coding run left, kept after its sandbox is gone: every file it\nadded or changed and its whole change as `changes.patch`, stored beside the run;\nthe ports it served, each a preview while its sandbox is kept; its pull request\nand where its work was published. A run that is still working, or saved\nnothing, answers an empty list.","tags":["agent"],"parameters":[{"name":"session","in":"path","required":true,"description":"Session is the run's handle — the sessionId POST /v1/agent/coding answered\nwith — from the path.","schema":{"type":"string"},"example":"sess_0123456789abcdef0123456789abcdef"}],"responses":{"200":{"content":{"application/json":{"example":{"artifacts":[{"kind":"patch","name":"changes.patch","sha256":"…","size":812},{"kind":"file","name":"src/app.ts","sha256":"…","size":1042},{"kind":"preview","name":"port 5173","port":5173,"sandbox":"m_0123456789abcdef01234567","url":"https://sandbox-…-preview-5173.hanzo.app/"}],"saved":"2026-09-29T18:00:00Z","session":"sess_0123456789abcdef0123456789abcdef"},"schema":{"$ref":"#/components/schemas/agent.CodingArtifacts"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/coding/{session}/blob":{"get":{"operationId":"get_agent_coding_by_session_blob","summary":"Returns one file of a coding run's repository, read where the tree is read, in the shape GET /v1/git/repos/{name}/blob answers: text verbatim, anything else base64, and a file past the 1 MiB view cap marked truncated with no content.","description":"Returns one file of a coding run's repository, read where the tree is read,\nin the shape GET /v1/git/repos/{name}/blob answers: text verbatim, anything\nelse base64, and a file past the 1 MiB view cap marked truncated with no\ncontent.","tags":["agent"],"parameters":[{"name":"session","in":"path","required":true,"description":"Session is the run's handle, from the path.","schema":{"type":"string"},"example":"sess_0123456789abcdef0123456789abcdef"},{"name":"path","in":"query","required":false,"description":"Path is repo-relative, from the query. Empty is the repository's root.","schema":{"type":"string"},"example":"api/server.go"}],"responses":{"200":{"content":{"application/json":{"example":{"binary":false,"content":"package api\n\nvar port = 8080\n","encoding":"utf8","path":"api/server.go","size":29,"truncated":false},"schema":{"$ref":"#/components/schemas/agent.CodingBlob"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/coding/{session}/changes":{"get":{"operationId":"get_agent_coding_by_session_changes","summary":"Returns what a coding run changed, read from the forge it pushed its branch to: the commits on its branch that the base does not have, newest first; the net change of the branch against its base, one entry per file with that file's patch; and its pull request with the reviews it has had, or null while it has none.","description":"Returns what a coding run changed, read from the forge it pushed its branch\nto: the commits on its branch that the base does not have, newest first; the\nnet change of the branch against its base, one entry per file with that file's\npatch; and its pull request with the reviews it has had, or null while it has\nnone.\n\nA run whose branch is not on the forge yet — still working, or finished with\nnothing to change — answers with no commits, no files and no pull request.\nEvery read is made as the caller, so a repository they cannot open on the\nforge is not found here either, whoever can see the run.\n\nOne answer is bounded, and says where it was cut rather than failing: the\nnewest 250 commits (`moreCommits` when there are more), the change up to 8 MiB\nof diff or 3000 files (`moreFiles`, the last file marked truncated), and the\nfirst 50 reviews (`moreReviews`), each body up to 16 KiB and 256 KiB across\nthem (`truncated` on a cut one). A caller has at most two of these reads in\nflight and is answered 429 past that; two asking for the same change at once\nshare one read.","tags":["agent"],"parameters":[{"name":"session","in":"path","required":true,"description":"Session is the run's handle — the sessionId POST /v1/agent/coding answered\nwith — from the path.","schema":{"type":"string"},"example":"sess_0123456789abcdef0123456789abcdef"}],"responses":{"200":{"content":{"application/json":{"example":{"base":"main","commits":[{"author":"hanzo-agent","date":"2026-09-27T08:00:00Z","message":"Fix the port","sha":"2f1c9e0a7b3d4c5e6f708192a3b4c5d6e7f80912"}],"files":[{"additions":1,"deletions":1,"patch":"@@ -1 +1 @@\n-var port = 80\n+var port = 8080\n","path":"api/server.go","status":"modified"}],"head":"agent/456789abcdef","pull":null,"repo":"hanzoai/cloud"},"schema":{"$ref":"#/components/schemas/agent.CodingChanges"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/coding/{session}/merge":{"post":{"operationId":"post_agent_coding_by_session_merge","summary":"Merges a coding run's pull request into the branch it proposes into, on the forge the run pushed to, and answers the pull request after.","description":"Merges a coding run's pull request into the branch it proposes into, on the\nforge the run pushed to, and answers the pull request after.\n\nThe caller must be able to read the run: its person, or an admin of its org.\nWhat lands is the run's branch at the commit the forge holds when this asks —\na push after that is refused, not merged unseen — and nothing is forced: a\npull request that conflicts, was closed, or that a rule on its base keeps\nfrom merging is 409 with the forge's reason. One already merged answers as\nit is.","tags":["agent"],"parameters":[{"name":"session","in":"path","required":true,"description":"Session is the run's handle — the sessionId POST /v1/agent/coding answered\nwith — from the path.","schema":{"type":"string"},"example":"sess_0123456789abcdef0123456789abcdef"}],"responses":{"200":{"content":{"application/json":{"example":{"base":"main","number":7,"state":"merged","url":"https://git.hanzo.ai/acme/site/pulls/7"},"schema":{"$ref":"#/components/schemas/agent.CodingMerged"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/coding/{session}/steer":{"post":{"operationId":"post_agent_coding_by_session_steer","summary":"Redirect your running or paused coding session.","description":"Redirect your running or paused coding session. The current run keeps its\nwork before starting a follow-up; its status events report the next session.\nOwnership comes from the authenticated credential, never the request body.","tags":["agent"],"parameters":[{"name":"session","in":"path","required":true,"description":"Session identifies the running or paused coding session from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.codingInstruction"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.CodingAck"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/coding/{session}/tree":{"get":{"operationId":"get_agent_coding_by_session_tree","summary":"Lists one directory of a coding run's repository, one level down with directories first: at the run's own branch once the forge holds it, and at the branch it started from until then — `ref` says which.","description":"Lists one directory of a coding run's repository, one level down with\ndirectories first: at the run's own branch once the forge holds it, and at the\nbranch it started from until then — `ref` says which. Walk down a level at a\ntime; an empty path is the root.","tags":["agent"],"parameters":[{"name":"session","in":"path","required":true,"description":"Session is the run's handle, from the path.","schema":{"type":"string"},"example":"sess_0123456789abcdef0123456789abcdef"},{"name":"path","in":"query","required":false,"description":"Path is repo-relative, from the query. Empty is the repository's root.","schema":{"type":"string"},"example":"api"}],"responses":{"200":{"content":{"application/json":{"example":{"entries":[{"name":"server.go","path":"api/server.go","size":1042,"type":"blob"}],"ref":"agent/456789abcdef"},"schema":{"$ref":"#/components/schemas/agent.CodingTree"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/mcp/{server}":{"post":{"operationId":"post_agent_mcp_by_server","summary":"The MCP address a coding run's harness reaches one of its org's MCP servers through.","description":"Speaks MCP over streamable HTTP for one of the org's MCP servers, named by its id: tools/list answers the tools of it an admin of the org activated, and tools/call calls one. The server's address and credential never reach the run: the tool plane adds the credential and dials the server.\n\nThe caller is a coding run, not a tenant: the request carries the run's ticket in X-Hanzo-Run and no bearer. A request without a live ticket is 401, and a server the run's kit did not carry when it started is 403. A run has at most four requests in flight here and twenty in a burst, then one a second; a request past that is 429 with Retry-After.","tags":["agent"],"parameters":[{"name":"server","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"agent","x-public":true}},"/v1/agent/metrics":{"get":{"operationId":"get_agent_metrics","summary":"Serves the invocations-over-time histogram for the Agents dashboard, over the caller's own runs.","description":"Serves the invocations-over-time histogram for the Agents\ndashboard, over the caller's own runs. Every point is a REAL count of recorded\nruns in that time bucket —\none series line per agent that ran in the window. The Resource Usage rollup is\nall-null because this store meters no CPU/memory/storage/cost; the console\nrenders those as \"—\" rather than a fabricated figure. No runs =\u003e empty series\n(an honest \"not connected / no activity yet\"), never a synthesized trend.","tags":["agent"],"parameters":[{"name":"range","in":"query","required":false,"description":"Range is the window to bucket: 24H, 7D or 30D. Anything else reads as 30D.","schema":{"type":"string"},"example":"7D"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.metricsView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/runs":{"get":{"operationId":"get_agent_runs","summary":"Returns the caller's own agent runs across EVERY agent of the org, newest first — what ran, on which model, how long it took, and why it failed.","description":"Returns the caller's own agent runs across EVERY agent of the org,\nnewest first — what ran, on which model, how long it took, and why it failed.\nA run is the person's who asked for it: another member's never appears, and a\nrun no person asked for (a schedule) appears to a SuperAdmin alone.\n\nIt is the feed the per-agent history could not be: an operator asking \"what is\nthis tenant's agent plane doing\" does not start out knowing an agent ref, and\nanswering by listing the agents and then paging each one's history is N+1 round\ntrips to reconstruct one ordering the database already has (RunsSince, ordered\nby created_at over the org index).\n\nThe org is the CALLER's, resolved from identity by tenantStore — never a\nparameter. There is deliberately no org field on orgRunsQuery to forge: run\nhistory is the tenant's own record, and the only tenant this can answer for is\nthe one asking.","tags":["agent"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit caps how many runs come back, newest first. Absent, zero or out of\nrange (1..200) reads as 50.","schema":{"format":"int64","type":"integer"},"example":20},{"name":"status","in":"query","required":false,"description":"Status keeps only runs with this outcome (\"ok\" or \"error\"). Empty keeps\nboth. It is the filter an operator reaches for first — \"show me what broke\"\n— and answering it here rather than by paging the whole history client-side\nis the difference between a usable feed and a download.","schema":{"type":"string"},"example":"error"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.runList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/sessions":{"get":{"operationId":"get_agent_sessions","summary":"Returns the caller org's live sessions, newest first — each with its event count, its direct-child count and a one-line preview of its latest event.","description":"Returns the caller org's live sessions, newest first — each with\nits event count, its direct-child count and a one-line preview of its latest\nevent. With no filter it returns ROOT sessions only, so a dashboard shows one\nrow per flow rather than one per subagent; ?root= or ?parent= descends.","tags":["agent"],"parameters":[{"name":"root","in":"query","required":false,"description":"Root scopes the page to one subagent tree (its root session id).","schema":{"type":"string"}},{"name":"parent","in":"query","required":false,"description":"Parent scopes the page to the direct children of one session. Ignored when\nroot is set; with neither, only ROOT sessions come back.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Status filters to running, paused, done or error.","schema":{"type":"string"},"example":"running"},{"name":"project","in":"query","required":false,"description":"Project filters to the sessions tagged with one product slug.","schema":{"type":"string"}},{"name":"room","in":"query","required":false,"description":"Room filters to the sessions started in one collaborative room — the query a\nspace view runs to show what has been run in it.","schema":{"type":"string"}},{"name":"kind","in":"query","required":false,"description":"Kind filters to the sessions of one kind of run: \"coding\" lists coding runs,\neach carrying its repo, base, branch, environment and pull request.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps the page. Absent, zero or over 500 reads as 100.","schema":{"format":"int64","type":"integer"},"example":20},{"name":"after","in":"query","required":false,"description":"After is the `next` of the previous page. Absent starts at the newest.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.sessionList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true},"post":{"operationId":"post_agent_sessions","summary":"Opens a live agent session in the caller's org — the row every surface (the CLI's outer agent, hanzo.bot, the console, chat) hangs its activity off.","description":"Opens a live agent session in the caller's org — the row every\nsurface (the CLI's outer agent, hanzo.bot, the console, chat) hangs its\nactivity off. A session with a parentSessionId becomes a subagent of that\nsession and inherits its root, so one flow is one tree; without one it is\nitself a root. Registering with a terminal status records a session that has\nalready finished.","tags":["agent"],"requestBody":{"content":{"application/json":{"example":{"agent":"hanzo-dev","host":"gpu-01","title":"ship the landing page"},"schema":{"$ref":"#/components/schemas/agent.registerReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.sessionView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/sessions/stream":{"get":{"operationId":"get_agent_sessions_stream","summary":"Live session and event updates for the caller's org, as Server-Sent Events.","description":"Holds the connection open as text/event-stream and pushes a frame each time the org's registry moves: an `event: session` frame carrying the same session shape the list and detail reads answer with (a registration, an update, or a login-manager revoke tearing a session down), and an `event: event` frame carrying one appended turn. Optional ?root=\u003csession id\u003e narrows the feed to a single subagent tree.\n\nRequires a validated principal carrying an org: 401 without a principal, 403 without an org. Org-scoped fail-closed: the bus filters on tenant before it fans out, so a subscriber only ever receives its own org's updates, and ?root= narrows that further but can never widen it. Within the org a subscriber receives what GET /v1/agent/sessions/{id} would show them: a member the frames of the sessions they opened, an org admin or a SuperAdmin the org's.\n\nDelivery is best-effort and the GET reads remain the source of truth. A subscriber that falls more than 256 frames behind is DROPPED — its channel is closed and the stream ends — so one stuck dashboard can never back-pressure a session write; the client reconnects and re-reads the session endpoints to resynchronise. A `: ping` comment every 25 seconds holds the connection open through proxies and is how a departed client is noticed.","tags":["agent"],"x-app":"agent","x-public":true}},"/v1/agent/sessions/{id}":{"get":{"operationId":"get_agent_sessions_by_id","summary":"Returns one session with its direct child sessions and its 50 most recent events, oldest of those first.","description":"Returns one session with its direct child sessions and its 50 most\nrecent events, oldest of those first. The children are those the caller may\nsee, by the rule the session itself is read by: a member's own, and every one\nfor an admin of the org. In a held org, where self-serve signups land beside\nthe platform's staff, a session is its person's alone.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the session to act on, from the path.","schema":{"type":"string"},"example":"sess_1"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.sessionDetail"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true},"patch":{"operationId":"patch_agent_sessions_by_id","summary":"Updates a session's surface-owned truth: its status, its title, the run-target it is dispatched to, and the product it built plus whether that build's story is public.","description":"Updates a session's surface-owned truth: its status, its title,\nthe run-target it is dispatched to, and the product it built plus whether that\nbuild's story is public. A FINISHED session stays finished — reopening a\ndone/error run would fabricate liveness — and publishing is refused unless the\nsession names the project it built, because the public build route is keyed on\n(org, project).","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the session to update, from the path.","schema":{"type":"string"},"example":"sess_1"}],"requestBody":{"content":{"application/json":{"example":{"id":"sess_1","status":"done"},"schema":{"$ref":"#/components/schemas/agent.patchSessionIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.sessionView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/sessions/{id}/budget":{"post":{"operationId":"post_agent_sessions_by_id_budget","summary":"Sets, raises, or removes a session's cap.","description":"Sets, raises, or removes a session's cap.\n\n  - a replacement must be strictly greater than what the session has consumed\n  - removal is one-way: a session whose cap was removed cannot take one again,\n    and a session created without one cannot be given one\n  - raising or removing the cap resumes work that paused at it","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the session, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.sessionBudgetIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.sessionBudgetView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/sessions/{id}/control":{"get":{"operationId":"get_agent_sessions_by_id_control","summary":"Returns the steering commands (pause/resume/stop/message) recorded against the caller's own session that are newer than the cursor, oldest first, with the cursor to poll from next.","description":"Returns the steering commands (pause/resume/stop/message)\nrecorded against the caller's own session that are newer than the cursor,\noldest first, with the cursor to poll from next. It is how a locally started\n`hanzo code` session — which is not task-backed, so nothing forwards its\ncommands to an execution engine — consumes what the dashboard posted. Read-only\nand bounded at 200 per poll, so a steady poll is cheap and an applied command is\nnever redelivered.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the session whose commands are being drained, from the path.","schema":{"type":"string"},"example":"sess_1"},{"name":"after","in":"query","required":false,"description":"After is the last seq this poller applied; only commands newer than it come\nback. Absent or negative reads as 0, which drains from the beginning.","schema":{"format":"int64","type":"integer"},"example":12}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.controlDrain"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/sessions/{id}/events":{"post":{"operationId":"post_agent_sessions_by_id_events","summary":"Records one turn of a session's transcript and answers 201 with it.","description":"Records one turn of a session's transcript and answers 201 with it.\n\nA `progress` turn additionally MOVES THE SESSION'S PROGRESS, marked as the run's\nown word rather than an estimate, and pushes the updated session onto the live\nstream — so a board's bar follows the run without polling and without a second\nwrite path. See progress.go.\n\nTHE TURN IS SCANNED BEFORE IT IS STORED. The same engine the code-security\nsurface runs reads the payload at this boundary, and a credential in it refuses\nthe append with 422 rather than redacting it — a redacted transcript is one\nthat still had the secret in it once, and this way the author learns which\nvalue to rotate. The refusal carries every finding: the rule, the severity, the\nline, a MASKED preview and the fingerprint. The secret is never in the answer.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the session to append to, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.eventIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.eventView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/sessions/{id}/message":{"post":{"operationId":"post_agent_sessions_by_id_message","summary":"Sends a steering message to a running session — the endpoint a human or another agent interrupts through.","description":"Sends a steering message to a running session — the endpoint a\nhuman or another agent interrupts through. It requires a `message` or a\n`payload`; the other three commands do not.\n\nA chat turn's run READS it: the message is handed to the model as the person's\nnext words at its next step, and a message that arrives while the model is\nwriting its answer gets a step of its own before the answer stands. A turn that\nhas already answered takes no more and answers 409 — what is said after an\nanswer is a new turn.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the session to steer, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.controlIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.controlResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/sessions/{id}/pause":{"post":{"operationId":"post_agent_sessions_by_id_pause","summary":"Asks a running session to pause.","description":"Asks a running session to pause. Recorded durably, and forwarded\nto the durable-execution engine when the session is task-backed.\n\nA chat turn's run is paused where it runs: it stops, the session stays live as\n`paused`, and its sandbox is PARKED — the pod stops and every file stays, with\nnothing billed for compute — until a resume picks it up.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the session to steer, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.controlIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.controlResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/sessions/{id}/progress":{"get":{"operationId":"get_agent_sessions_by_id_progress","summary":"Returns how far along one run is: the share of its goal that is done, whether it is running, blocked or finished, and a line saying what it is doing right now.","description":"Returns how far along one run is: the share of its goal that\nis done, whether it is running, blocked or finished, and a line saying what it\nis doing right now.\n\nIt is a MODEL ESTIMATE read off the run's own transcript, not a measurement —\n`estimated` says so on every answer, and a run whose progress cannot be told\nreports phase \"unknown\" with no percentage rather than a zero it does not\nmean. A session that has already finished answers from its own status instead,\nand is marked not estimated.\n\nThe list and detail reads carry the same value; this address is the one that\nWAITS. Where the stored estimate has gone stale it is remade before answering,\nso a human deciding whether to step into a run gets a current reading rather\nthan the last poll's — which costs one small completion, charged to the same\nwallet the session already names, at most once every thirty seconds per run.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the session to act on, from the path.","schema":{"type":"string"},"example":"sess_1"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.sessionProgress"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/sessions/{id}/resume":{"post":{"operationId":"post_agent_sessions_by_id_resume","summary":"Asks a paused session to continue, on the same terms as a pause.","description":"Asks a paused session to continue, on the same terms as a pause.\n\nA chat turn that was paused or STOPPED runs again: the same session, in the same\nsandbox with every file it had written, told `message` next (\"Continue where you\nleft off.\" when there is none). Only the person whose turn it was may resume\nit, since the agent runs as them.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the session to steer, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.controlIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.controlResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/sessions/{id}/stop":{"post":{"operationId":"post_agent_sessions_by_id_stop","summary":"Ends a running session.","description":"Ends a running session. `message` is recorded as the cancellation\nreason, which is what a later reader of the transcript sees.\n\nSTOPPING IS NOT DELETING: the session, its transcript and anything it produced\nstay readable. A session that has already finished is 409 rather than a second\nstop.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the session to steer, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.controlIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.controlResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/sessions/{id}/tree":{"get":{"operationId":"get_agent_sessions_by_id_tree","summary":"Returns the subagent-flow graph rooted at this session: the session, its children, their children, each node carrying its own event count.","description":"Returns the subagent-flow graph rooted at this session: the session,\nits children, their children, each node carrying its own event count. One\nindexed read pulls the whole flow (every node of a flow shares a root id), so\nthe shape is assembled in memory rather than by walking the store per node. It\nholds the sessions the caller may see — a member's own, every one for an admin\nof the org — and a session they may not see is absent with all beneath it.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the session to act on, from the path.","schema":{"type":"string"},"example":"sess_1"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.treeNode"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/targets":{"get":{"operationId":"get_agent_targets","summary":"Returns every machine registered to the caller's org, newest first, each with its live session load.","description":"Returns every machine registered to the caller's org, newest\nfirst, each with its live session load. In a held org, where self-serve\nsignups land beside the platform's staff, it is only the caller's own.","tags":["agent"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.targetList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true},"post":{"operationId":"post_agent_targets","summary":"Registers a machine as an agent target, or re-links one that is already registered.","description":"Registers a machine as an agent target, or re-links one that is\nalready registered. Re-linking is idempotent and keyed on org+host+owner, so a\nmachine that reconnects refreshes its own row rather than piling up duplicates;\nit answers 200, while a first registration answers 201.","tags":["agent"],"requestBody":{"content":{"application/json":{"example":{"host":"gpu-01","kind":"gpu","label":"workshop"},"schema":{"$ref":"#/components/schemas/agent.targetReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.targetView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/targets/{id}":{"delete":{"operationId":"delete_agent_targets_by_id","summary":"Deregisters one machine.","description":"Deregisters one machine. Only its owner, or an org admin, may\nremove it; an unknown id, a cross-org id and a machine owned by someone else\nall answer the same not-found, so a probe learns nothing about what exists.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the target to act on, from the path.","schema":{"type":"string"},"example":"tgt_1"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.targetDeleted"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true},"get":{"operationId":"get_agent_targets_by_id","summary":"Returns one registered machine, with its live session load.","description":"Returns one registered machine, with its live session load.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the target to act on, from the path.","schema":{"type":"string"},"example":"tgt_1"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.targetView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true},"patch":{"operationId":"patch_agent_targets_by_id","summary":"Updates one machine in place.","description":"Updates one machine in place. Every field is optional; a field the\nrequest omits is left alone. A metrics patch IS a heartbeat — the server stamps\nits own clock, so a client can neither forge nor backdate staleness.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the target to update, from the path.","schema":{"type":"string"},"example":"tgt_1"}],"requestBody":{"content":{"application/json":{"example":{"id":"tgt_1","status":"draining"},"schema":{"$ref":"#/components/schemas/agent.patchTargetIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.targetView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/targets/{id}/claim":{"post":{"operationId":"post_agent_targets_by_id_claim","summary":"ClaimRoutedRun is the machine's long poll for work: it authenticates the daemon, stamps the liveness the dispatch gate reads (the poll IS the proof a runner is listening), and waits up to 25 seconds for the next run addressed to THIS machine.","description":"ClaimRoutedRun is the machine's long poll for work: it authenticates the\ndaemon, stamps the liveness the dispatch gate reads (the poll IS the proof a\nrunner is listening), and waits up to 25 seconds for the next run addressed to\nTHIS machine. It answers the run when one arrives and 204 with no body when the\nwindow elapses, on which the daemon re-polls immediately.\n\nTWO independent proofs are required and both fail closed to the same 403: the\ncaller must own this machine (or be an org admin) AND present its claim key in\nX-Target-Key. A run offered to one machine is unreachable from another's claim.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the target to act on, from the path.","schema":{"type":"string"},"example":"tgt_1"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.routedRunOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/targets/{id}/key":{"post":{"operationId":"post_agent_targets_by_id_key","summary":"Mints (or rotates) the claim key a `hanzo code --serve` daemon presents to claim work for this machine, and returns it ONCE: only its SHA-256 hash is stored.","description":"Mints (or rotates) the claim key a `hanzo code --serve`\ndaemon presents to claim work for this machine, and returns it ONCE: only its\nSHA-256 hash is stored. Rotating supersedes any prior daemon, so only the\nmachine's owner — or an org admin — may call it; every other caller gets the\nsame not-found an unknown id gets, and learns nothing about what exists.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the target to act on, from the path.","schema":{"type":"string"},"example":"tgt_1"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.claimKeyOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/targets/{id}/runs/{runId}/report":{"post":{"operationId":"post_agent_targets_by_id_runs_by_runid_report","summary":"Completes a claimed run: it delivers the terminal result to the run's durable owner, which is what lets that workflow finish.","description":"Completes a claimed run: it delivers the terminal result to the\nrun's durable owner, which is what lets that workflow finish. Scoped to (org,\ntarget, run) and claim-key authenticated, so a machine can only ever report a\nrun it legitimately holds. Idempotent — a report for an unknown or\nalready-finished run answers delivered:false rather than failing, because the\nsession's terminal state was already set by the machine's own stream.","tags":["agent"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the machine reporting, from the path.","schema":{"type":"string"},"example":"tgt_1"},{"name":"runId","in":"path","required":true,"description":"RunID is the routed run being completed, from the path.","schema":{"type":"string"},"example":"run_1"}],"requestBody":{"content":{"application/json":{"example":{"branch":"hanzo/fix","changed":true,"id":"tgt_1","ok":true,"runId":"run_1"},"schema":{"$ref":"#/components/schemas/agent.reportRunIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.reportOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/{ref}":{"delete":{"operationId":"delete_agent_by_ref","summary":"Removes an agent and every run recorded against it.","description":"Removes an agent and every run recorded against it. Answers 204.","tags":["agent"],"parameters":[{"name":"ref","in":"path","required":true,"description":"Ref is the agent's public id (the agent_… handle create and list return) or\nits org-unique name, from the path. Either resolves the same agent.","schema":{"type":"string"},"example":"helper"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true},"get":{"operationId":"get_agent_by_ref","summary":"Returns one agent with its system prompt and the caller's own 20 most recent runs of it: a run's input and output are its person's.","description":"Returns one agent with its system prompt and the caller's own 20 most\nrecent runs of it: a run's input and output are its person's.\nThe ref is the agent's public id or its org-unique name — a created agent is\nimmediately gettable by whatever create handed back.","tags":["agent"],"parameters":[{"name":"ref","in":"path","required":true,"description":"Ref is the agent's public id (the agent_… handle create and list return) or\nits org-unique name, from the path. Either resolves the same agent.","schema":{"type":"string"},"example":"helper"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.agentDetail"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true},"patch":{"operationId":"patch_agent_by_ref","summary":"Changes an agent in place.","description":"Changes an agent in place. Every field is optional; a field the\nrequest omits keeps its stored value. The resulting mode+schedule are\nre-validated together, so a partial update can never leave a long-running\nagent without the cron the scheduler needs to fire it, and a transition INTO\nlong-running counts against the per-org cap on scheduled agents.","tags":["agent"],"parameters":[{"name":"ref","in":"path","required":true,"description":"Ref is the agent to update — its public id or org-unique name, from the path.","schema":{"type":"string"},"example":"helper"}],"requestBody":{"content":{"application/json":{"example":{"instructions":"be terse and cite sources","ref":"helper"},"schema":{"$ref":"#/components/schemas/agent.updateAgentIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.agentView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/{ref}/run":{"post":{"operationId":"post_agent_by_ref_run","summary":"Run one of your org's agents and get the recorded run back.","description":"Composes the agent's stored instructions with the caller's `input`, executes one real chat completion through the same in-process AI client the rest of the console uses, and answers with the run that was recorded: its id, status, model, output, duration and error. Every run this returns reflects an execution that actually happened — a model failure is recorded and reported, never hidden and never fabricated. A transient upstream failure (429, 5xx, empty choices) is retried up to three times with jittered backoff, and a configured failover model is tried before the run is called an error.\n\n`ref` is the agent's public `agent_…` id or its org-unique name; either resolves the same agent, and it must belong to the caller's org, so an agent in another tenant is a 404 exactly like one that does not exist. A validated principal is required and the check is made twice on purpose: this route MOVES MONEY, so the debit's principal requirement is asserted where the money moves rather than inherited from the tenant lookup.\n\nThe org's balance is authorized BEFORE any inference, so an unfunded tenant gets 402 and no free compute, and a billing plane that cannot answer gets 503 rather than a free run. The flat per-run fee is an operator knob; setting it to zero makes runs free and removes the balance gate with them. Only a SUCCESSFUL run is billed, attributed to the model actually used — a failover run bills the model it fell over to, not the one it started on. A deployment with no inference wired answers 503 before any of this.\n\nTHE RULE A READER GETS WRONG: a failed run is a 502 whose body is the RUN, not an error envelope. The execution happened, the run was persisted to this agent's history, and its `error` field is the product — so a client that treats every non-2xx as an opaque failure throws away the only account of what went wrong. Each run also opens a root session in the live session registry, best-effort: a bookkeeping failure there never fails the run, because the run and its billing already happened.","tags":["agent"],"parameters":[{"name":"ref","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"agent","x-public":true}},"/v1/agent/{ref}/runs":{"get":{"operationId":"get_agent_by_ref_runs","summary":"Returns the caller's own runs of one agent, newest first — each run's input, its output or its error, and how long it took.","description":"Returns the caller's own runs of one agent, newest first — each\nrun's input, its output or its error, and how long it took. A run is the\nperson's who asked for it, so another member's runs are not listed, nor an\norg admin's view of them; a run no person asked for (a schedule) is listed to a\nSuperAdmin alone. Every row is a run that actually happened.","tags":["agent"],"parameters":[{"name":"ref","in":"path","required":true,"description":"Ref is the agent's public id or its org-unique name, from the path.","schema":{"type":"string"},"example":"helper"},{"name":"limit","in":"query","required":false,"description":"Limit caps how many runs come back, newest first. Absent, zero or out of\nrange (1..200) reads as 50.","schema":{"format":"int64","type":"integer"},"example":20}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.runList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/agent/{ref}/spend":{"get":{"operationId":"get_agent_by_ref_spend","summary":"Answers what one of your org's agents has spent, in integer micro-USD.","description":"Answers what one of your org's agents has spent, in integer micro-USD.\n\nIt answers the agent's budget — `cap_micro_usd` per `period`,\n`max_task_micro_usd` per run — with what the current period has consumed,\nwhat remains, and `by_component`: the spend attributed to `model` (every\ncompletion the agent bought), `computer` (the runtime it was resident for)\nand `tool`. A component with no spend is absent, not zero. Every amount is an\ninteger number of micro-USD (1,000,000 = $1); 11902000 is $11.902. Pass\n`by=component` to ask for the breakdown by name — it is the one grouping, and\nthe default.","tags":["agent"],"parameters":[{"name":"ref","in":"path","required":true,"description":"Ref is the agent's public id or its org-unique name.","schema":{"type":"string"}},{"name":"by","in":"query","required":false,"description":"By groups the answer: \"component\" is the only grouping today.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/agent.spendView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"agent","x-public":true,"x-tool":true}},"/v1/ai/account":{"get":{"operationId":"get_ai_account","summary":"Account","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/activities":{"get":{"operationId":"get_ai_activities","summary":"List activities","description":"List the caller's activities.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Activity"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/answer":{"get":{"operationId":"get_ai_answer","summary":"Answer","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/articles":{"get":{"operationId":"get_ai_articles","summary":"List articles","description":"List the caller's articles.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Article"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_articles","summary":"Create a article","description":"Create one article.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Article"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/articles/global":{"get":{"operationId":"get_ai_articles_global","summary":"List articles across tenants","description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Article"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/articles/{owner}/{name}":{"delete":{"operationId":"delete_ai_articles_by_owner_by_name","summary":"Delete a article","description":"Delete one article.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Article"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_articles_by_owner_by_name","summary":"Retrieve a article","description":"Read one article by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Article"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_articles_by_owner_by_name","summary":"Update a article","description":"Update one article. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Article"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_articles_by_owner_by_name","summary":"Replace a article","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Article"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/assets":{"get":{"operationId":"get_ai_assets","summary":"List assets","description":"List the caller's assets.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Asset"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_assets","summary":"Create a asset","description":"Create one asset.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Asset"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/assets/scan":{"post":{"operationId":"post_ai_assets_scan","summary":"Scan (asset)","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/assets/{owner}/{name}":{"delete":{"operationId":"delete_ai_assets_by_owner_by_name","summary":"Delete a asset","description":"Delete one asset.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Asset"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_assets_by_owner_by_name","summary":"Retrieve a asset","description":"Read one asset by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Asset"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_assets_by_owner_by_name","summary":"Update a asset","description":"Update one asset. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Asset"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_assets_by_owner_by_name","summary":"Replace a asset","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Asset"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/assets/{owner}/{name}/scan":{"post":{"operationId":"post_ai_assets_by_owner_by_name_scan","summary":"Scan (asset)","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/chats":{"get":{"operationId":"get_ai_chats","summary":"List chats","description":"List the caller's chats.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Chat"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_chats","summary":"Create a chat","description":"Create one chat.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Chat"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/chats/global":{"get":{"operationId":"get_ai_chats_global","summary":"List chats across tenants","description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Chat"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/chats/{owner}/{name}":{"delete":{"operationId":"delete_ai_chats_by_owner_by_name","summary":"Delete a chat","description":"Delete one chat.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Chat"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_chats_by_owner_by_name","summary":"Retrieve a chat","description":"Read one chat by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Chat"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_chats_by_owner_by_name","summary":"Update a chat","description":"Update one chat. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Chat"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_chats_by_owner_by_name","summary":"Replace a chat","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Chat"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/connections":{"get":{"operationId":"get_ai_connections","summary":"Lists the org's connectable AI accounts and whether each is currently connected.","description":"Lists the org's connectable AI accounts and whether each is\ncurrently connected. Never returns a key or a kms:// reference.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/ai.AiConnResponse"},"type":"array"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_connections","summary":"Connects (or reconnects) a third-party AI account for the org by sealing the supplied key into KMS and upserting the org's provider row.","description":"Connects (or reconnects) a third-party AI account for the org by\nsealing the supplied key into KMS and upserting the org's provider row. The raw\nkey is sealed BEFORE the row is built and is never persisted or echoed.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/ai.AiConnResponse"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/connections/{provider}":{"delete":{"operationId":"delete_ai_connections_by_provider","summary":"Disconnects a third-party AI account: it deactivates the org's row so completion resolution falls back to the global Hanzo account (no BYO), and best-effort tombstones the sealed secret.","description":"Disconnects a third-party AI account: it deactivates the org's\nrow so completion resolution falls back to the global Hanzo account (no BYO), and\nbest-effort tombstones the sealed secret. Idempotent.","tags":["ai"],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/ai.AiConnResponse"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_connections_by_provider","summary":"Disconnects a third-party AI account: it deactivates the org's row so completion resolution falls back to the global Hanzo account (no BYO), and best-effort tombstones the sealed secret.","description":"Disconnects a third-party AI account: it deactivates the org's\nrow so completion resolution falls back to the global Hanzo account (no BYO), and\nbest-effort tombstones the sealed secret. Idempotent.","tags":["ai"],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/ai.AiConnResponse"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/connections/{provider}/authorize":{"get":{"operationId":"get_ai_connections_by_provider_authorize","summary":"Begins an OAuth connection for the caller's org: it binds the org into a signed state and sends the caller to the provider's authorize URL.","description":"Begins an OAuth connection for the caller's org: it binds the\norg into a signed state and sends the caller to the provider's authorize URL. By\ndefault it 302-redirects (a top-level browser \"connect your login\" click); a\nSPA/BFF that needs to drive the redirect itself passes ?format=json and gets\n{authorizeUrl} in the standard envelope. The org is the VERIFIED principal's, and\nonly its admins may begin one (requireConnectionAdmin), so the state this signs\nnames an org its holder administers.","tags":["ai"],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"additionalProperties":{"type":"string"},"type":"object"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/connections/{provider}/callback":{"get":{"operationId":"get_ai_connections_by_provider_callback","summary":"Completes OAuth: the org is recovered from the SIGNED state (not a header), the code is exchanged for a token, the token is SEALED into KMS (never the row/logs) through the same path as a BYOK key, and the org's provider row is upserted to \"connected\".","description":"Completes OAuth: the org is recovered from the SIGNED state\n(not a header), the code is exchanged for a token, the token is SEALED into KMS\n(never the row/logs) through the same path as a BYOK key, and the org's provider\nrow is upserted to \"connected\". The browser is then redirected back to the console\nwith ?ai_connected=\u003cprovider\u003e (or ?ai_connect_error=\u003cprovider\u003e on failure). Because\nthe org comes from the state THIS server signed, an attacker cannot land their\ntoken in a victim org — which is why this endpoint is state-authenticated rather\nthan credential-gated.","tags":["ai"],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"ai","x-public":true}},"/v1/ai/connections/{provider}/usage":{"get":{"operationId":"get_ai_connections_by_provider_usage","summary":"Imports the caller org's usage for a connected third-party account.","description":"Imports the caller org's usage for a connected third-party\naccount. The org is resolved from the VERIFIED principal (requireConnectionOrg), so a\ntenant reads only its own connection. The key is unsealed SERVER-SIDE and never\nreturned. An unconnected account, a missing importer, or a scope-denied provider all\nreturn a 200 ProviderUsage with connected/available flags + a human note — the UI's\nhonest-empty states — never a fabricated figure.","tags":["ai"],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/ai.ProviderUsage"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/dashboards/agents":{"get":{"operationId":"get_ai_dashboards_agents","summary":"Dashboards Agents","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/dashboards/vm":{"get":{"operationId":"get_ai_dashboards_vm","summary":"Dashboards Vm","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/deployments":{"get":{"operationId":"get_ai_deployments","summary":"List deployments","description":"List the caller's deployments.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/App"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_deployments","summary":"Create a application","description":"Create one application.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/App"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/deployments/{owner}/{name}":{"delete":{"operationId":"delete_ai_deployments_by_owner_by_name","summary":"Delete a application","description":"Delete one application.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/App"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_deployments_by_owner_by_name","summary":"Retrieve a application","description":"Read one application by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/App"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_deployments_by_owner_by_name","summary":"Update a application","description":"Update one application. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/App"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_deployments_by_owner_by_name","summary":"Replace a application","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/App"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/deployments/{owner}/{name}/deploy":{"post":{"operationId":"post_ai_deployments_by_owner_by_name_deploy","summary":"Deploy (application)","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/deployments/{owner}/{name}/undeploy":{"post":{"operationId":"post_ai_deployments_by_owner_by_name_undeploy","summary":"Undeploy (application)","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/feedback":{"post":{"operationId":"post_ai_feedback","summary":"Attaches a per-request outcome reward to the routing decision that served request_id — the enso training loop's quality signal.","description":"Attaches a per-request outcome reward to the routing decision\nthat served request_id — the enso training loop's quality signal. Org-scoped via\nthe same session-OR-Bearer principal the usage read uses (RequirePrincipal): the\nreward lands only on the caller's OWN org's event, so a request_id from another\norg (or unknown) is a 404 — cross-org writes are impossible and unknown ids are\nindistinguishable from foreign ones. Idempotent: a repeat overwrites. The body\ncarries NO prompt text — only {request_id, reward|rating}.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.RoutingRewardRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/ai.RoutingRewardResult"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/files":{"get":{"operationId":"get_ai_files","summary":"List files","description":"List the caller's files.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/File"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_files","summary":"Create a file","description":"Create one file.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/File"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/files/activate":{"post":{"operationId":"post_ai_files_activate","summary":"Activate (file)","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/files/active":{"get":{"operationId":"get_ai_files_active","summary":"Active (file)","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/files/global":{"get":{"operationId":"get_ai_files_global","summary":"List files across tenants","description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/File"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/files/upload":{"post":{"operationId":"post_ai_files_upload","summary":"Upload (file)","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/files/{owner}/{name}":{"delete":{"operationId":"delete_ai_files_by_owner_by_name","summary":"Delete a file","description":"Delete one file.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/File"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_files_by_owner_by_name","summary":"Retrieve a file","description":"Read one file by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/File"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_files_by_owner_by_name","summary":"Update a file","description":"Update one file. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/File"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_files_by_owner_by_name","summary":"Replace a file","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/File"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/files/{owner}/{name}/vectors":{"post":{"operationId":"post_ai_files_by_owner_by_name_vectors","summary":"Vectors (file)","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/finetune/cancel":{"post":{"operationId":"post_ai_finetune_cancel","summary":"Deletes the TrainJob CR, meters the GPU-hours used so far, and marks the job cancelled.","description":"Deletes the TrainJob CR, meters the GPU-hours used so far, and\nmarks the job cancelled. ?id= or ?name=","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/FinetuneJob"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/finetune/deploy":{"post":{"operationId":"post_ai_finetune_deploy","summary":"Serves a completed job's checkpoints and registers the result as a routable model on api.hanzo.ai.","description":"Serves a completed job's checkpoints and registers the result\nas a routable model on api.hanzo.ai. ?id= or ?name=","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/cluster.Serving"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/finetune/hf/datasets":{"get":{"operationId":"get_ai_finetune_hf_datasets","summary":"Proxies a HuggingFace dataset search (dataset picker).","description":"Proxies a HuggingFace dataset search (dataset picker).","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/HfDataset"},"type":"array"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/finetune/hf/models":{"get":{"operationId":"get_ai_finetune_hf_models","summary":"Proxies a HuggingFace model search (base-model picker).","description":"Proxies a HuggingFace model search (base-model picker).","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/HfModel"},"type":"array"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/finetune/hf/repo":{"get":{"operationId":"get_ai_finetune_hf_repo","summary":"Returns a repo's detail (files, gated/private state).","description":"Returns a repo's detail (files, gated/private state). ?id=\u0026kind=model|dataset","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/HfRepoInfo"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/finetune/job":{"get":{"operationId":"get_ai_finetune_job","summary":"Returns one job with refreshed live status.","description":"Returns one job with refreshed live status. ?id=owner/name or ?name=","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/FinetuneJob"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/finetune/jobs":{"get":{"operationId":"get_ai_finetune_jobs","summary":"Returns the org's jobs, refreshing live status for active ones.","description":"Returns the org's jobs, refreshing live status for active ones.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/FinetuneJob"},"type":"array"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_finetune_jobs","summary":"Validates the request, resolves efficient defaults, persists the job, and submits a real TrainJob CR.","description":"Validates the request, resolves efficient defaults, persists the\njob, and submits a real TrainJob CR. A submit failure (e.g. no cluster wired) is\nsurfaced honestly: the job is saved with status \"failed\" + the reason, never faked.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/FinetuneJob"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/finetune/presets":{"get":{"operationId":"get_ai_finetune_presets","summary":"Returns the new-job catalog plus, when a selection is passed (?baseModel\u0026method\u0026task\u0026preset[\u0026datasetExamples]), the recommended config so the console can render \"Recommended\" as a one-click, ready-to-run default.","description":"Returns the new-job catalog plus, when a selection is passed\n(?baseModel\u0026method\u0026task\u0026preset[\u0026datasetExamples]), the recommended config so the\nconsole can render \"Recommended\" as a one-click, ready-to-run default.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"additionalProperties":{},"type":"object"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/forms":{"get":{"operationId":"get_ai_forms","summary":"List forms","description":"List the caller's forms.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Layout"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_forms","summary":"Create a form","description":"Create one form.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Layout"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/forms/data":{"get":{"operationId":"get_ai_forms_data","summary":"Data (form)","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/forms/global":{"get":{"operationId":"get_ai_forms_global","summary":"List forms across tenants","description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Layout"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/forms/{owner}/{name}":{"delete":{"operationId":"delete_ai_forms_by_owner_by_name","summary":"Delete a form","description":"Delete one form.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Layout"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_forms_by_owner_by_name","summary":"Retrieve a form","description":"Read one form by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Layout"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_forms_by_owner_by_name","summary":"Update a form","description":"Update one form. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Layout"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_forms_by_owner_by_name","summary":"Replace a form","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Layout"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/graphs":{"get":{"operationId":"get_ai_graphs","summary":"List graphs","description":"List the caller's graphs.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Graph"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_graphs","summary":"Create a graph","description":"Create one graph.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Graph"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/graphs/global":{"get":{"operationId":"get_ai_graphs_global","summary":"List graphs across tenants","description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Graph"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/graphs/{owner}/{name}":{"delete":{"operationId":"delete_ai_graphs_by_owner_by_name","summary":"Delete a graph","description":"Delete one graph.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Graph"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_graphs_by_owner_by_name","summary":"Retrieve a graph","description":"Read one graph by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Graph"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_graphs_by_owner_by_name","summary":"Update a graph","description":"Update one graph. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Graph"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_graphs_by_owner_by_name","summary":"Replace a graph","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Graph"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/k8s-status":{"get":{"operationId":"get_ai_k8s-status","summary":"K8s Status","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/limits":{"get":{"operationId":"aiLimits","summary":"Reads the caller's plan usage: for each class of model the plan includes, the share used of the billing period and of its short window, who pays for the next request, and whether the caller is in limited mode and why; the share used of the session and the day; and the ways on.","description":"Reads the caller's plan usage: for each class of model the plan includes, the\nshare used of the billing period and of its short window, who pays for the next\nrequest, and whether the caller is in limited mode and why; the share used of the\nsession and the day; and the ways on. Shares only, never amounts.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/aiLimits"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ai","x-public":true,"x-tool":true},"put":{"operationId":"aiSetLimits","summary":"Sets the payer's choice to keep using a model on credits once the plan's included usage of it is spent.","description":"Sets the payer's choice to keep using a model on credits once the plan's included\nusage of it is spent. A pooled org wallet is its org admin's to set; a person's own\nwallet is theirs. Every change is on the audit trail, before and after; no trail,\nno change. Answers the limits as they read after it.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/aiLimitsSet"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/aiLimits"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ai","x-public":true,"x-tool":true}},"/v1/ai/mcp/chat":{"post":{"operationId":"aiChat","summary":"Asks one model one prompt and answers the reply, which model served it and who paid.","description":"Asks one model one prompt and answers the reply, which model served it and who\npaid. The call is the caller's own POST /v1/chat/completions, run as the caller,\nso it is gated, billed and refused exactly as that route is; a refusal names its\ncode and what lifts it, never an amount. An empty model asks the deployment's\ndefault Hanzo model.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/aiChatIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/aiChat"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ai","x-public":true,"x-tool":true}},"/v1/ai/mcp/decisions":{"post":{"operationId":"aiDecide","summary":"Runs one decision — the caller's own POST /v1/decisions, gated and billed exactly as that route is — and answers the decision, which model served it and who paid.","description":"Runs one decision — the caller's own POST /v1/decisions, gated and billed\nexactly as that route is — and answers the decision, which model served it and\nwho paid. A refusal names its code and what lifts it, never an amount.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/aiDecideIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/aiDecision"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ai","x-public":true,"x-tool":true}},"/v1/ai/mcp/models":{"get":{"operationId":"aiModels","summary":"Searches the model catalog — the one GET /v1/models lists, every OpenRouter model among it as last synced — by text, class, family, capability or free, and answers each match with its class, family, whether it is free, its list price (per token and per million; variable for a router billed at the answering model's price; a resold model's every vendor rate and conditional rate as billed), context window, output bound, expiry and capabilities.","description":"Searches the model catalog — the one GET /v1/models lists, every OpenRouter model\namong it as last synced — by text, class, family, capability or free, and answers\neach match with its class, family, whether it is free, its list price (per token\nand per million; variable for a router billed at the answering model's price; a\nresold model's every vendor rate and conditional rate as billed), context window,\noutput bound, expiry and capabilities.","tags":["ai"],"parameters":[{"name":"q","in":"query","required":false,"description":"Q matches the model's id, name, description or owner, ignoring case.","schema":{"type":"string"}},{"name":"class","in":"query","required":false,"description":"Class keeps one class: premium (third-party frontier models), ours (Hanzo's\npriced models) or free.","schema":{"type":"string"}},{"name":"family","in":"query","required":false,"description":"Family keeps one Hanzo family: enso, zen, kai or zoo.","schema":{"type":"string"}},{"name":"capability","in":"query","required":false,"description":"Capability keeps the models that have it: tools, vision or reasoning, or a\nmodality they take or give (text, image, audio, file, video, decision).","schema":{"type":"string"}},{"name":"free","in":"query","required":false,"description":"Free keeps the models a call to which bills nothing (bounded by the free\nallowances instead of a balance).","schema":{"type":"boolean"}},{"name":"limit","in":"query","required":false,"description":"Limit is the most models to answer, 1 to 500; 0 answers 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/aiModels"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ai","x-public":true,"x-tool":true}},"/v1/ai/mcp/tools":{"get":{"operationId":"aiMCPTools","summary":"Reports what THIS PROCESS's MCP server carries: how many tools its own registry projects, optionally their names, and which subsystems this process composed.","description":"Reports what THIS PROCESS's MCP server carries: how many tools its own\nregistry projects, optionally their names, and which subsystems this process\ncomposed. It is the answer to \"is this MCP server up and does it have anything\nbehind it\" — a question a status code cannot answer, since an empty server and\na full one are both 200. What the FLEET's server carries is the fleet server's\nown answer: POST /v1/mcp, tools/list, which asks every subsystem and names the\nones that did not reply.","tags":["ai"],"parameters":[{"name":"names","in":"query","required":false,"description":"Names asks for this process's tool NAMES and not only how many there are.\nOff by default: a list of names is a page, and the question this op exists to\nanswer (\"is the MCP server up and does it have anything behind it\") is\nanswered by the count.","schema":{"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/aiMCPSurface"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ai","x-public":true,"x-tool":true}},"/v1/ai/memory/delete":{"post":{"operationId":"post_ai_memory_delete","summary":"Delete one of the authenticated user's memories","description":"Delete one of the authenticated user's memories","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"type":"boolean"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/memory/facts":{"get":{"operationId":"get_ai_memory_facts","summary":"List the authenticated user's stored facts","description":"List the authenticated user's stored facts","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Memory"},"type":"array"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/memory/list":{"get":{"operationId":"get_ai_memory_list","summary":"List the authenticated user's memories, newest first","description":"List the authenticated user's memories, newest first","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Memory"},"type":"array"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/memory/recall":{"get":{"operationId":"get_ai_memory_recall","summary":"Recall recent/relevant memories for context injection; with q it","description":"Recall recent/relevant memories for context injection; with q it\nranks semantically, without q it returns the most recent","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Memory"},"type":"array"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/memory/remember":{"post":{"operationId":"post_ai_memory_remember","summary":"Store a memory for the authenticated user","description":"Store a memory for the authenticated user","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Memory"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/memory/search":{"get":{"operationId":"get_ai_memory_search","summary":"Search the authenticated user's memories (semantic, text fallback)","description":"Search the authenticated user's memories (semantic, text fallback)","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Memory"},"type":"array"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/memory/update":{"post":{"operationId":"post_ai_memory_update","summary":"Update one of the authenticated user's memories","description":"Update one of the authenticated user's memories","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"type":"boolean"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/messages":{"get":{"operationId":"get_ai_messages","summary":"List messages","description":"List the caller's messages.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Message"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_messages","summary":"Create a message","description":"Create one message.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Message"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/messages/welcome":{"delete":{"operationId":"delete_ai_messages_welcome","summary":"Welcome (message)","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/messages/{owner}/{name}":{"delete":{"operationId":"delete_ai_messages_by_owner_by_name","summary":"Delete a message","description":"Delete one message.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Message"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_messages_by_owner_by_name","summary":"Retrieve a message","description":"Read one message by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Message"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_messages_by_owner_by_name","summary":"Update a message","description":"Update one message. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Message"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_messages_by_owner_by_name","summary":"Replace a message","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Message"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/messages/{owner}/{name}/answer":{"get":{"operationId":"get_ai_messages_by_owner_by_name_answer","summary":"Answer (message)","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/nodes":{"get":{"operationId":"get_ai_nodes","summary":"List nodes","description":"List the caller's nodes.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Node"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_nodes","summary":"Create a node","description":"Create one node.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Node"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/nodes/{owner}/{name}":{"delete":{"operationId":"delete_ai_nodes_by_owner_by_name","summary":"Delete a node","description":"Delete one node.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Node"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_nodes_by_owner_by_name","summary":"Retrieve a node","description":"Read one node by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Node"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_nodes_by_owner_by_name","summary":"Update a node","description":"Update one node. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Node"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_nodes_by_owner_by_name","summary":"Replace a node","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Node"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/nodes/{owner}/{name}/tunnel":{"get":{"operationId":"get_ai_nodes_by_owner_by_name_tunnel","summary":"Tunnel (node)","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_nodes_by_owner_by_name_tunnel","summary":"Tunnel (node)","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/org/settings":{"delete":{"operationId":"delete_ai_org_settings","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_org_settings","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_org_settings","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_org_settings","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_org_settings","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/org/settings/list":{"delete":{"operationId":"delete_ai_org_settings_list","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_org_settings_list","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_org_settings_list","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_org_settings_list","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_org_settings_list","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/preferences":{"patch":{"operationId":"patch_ai_preferences","summary":"Preferences","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_preferences","summary":"Preferences","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/prometheus":{"get":{"operationId":"get_ai_prometheus","summary":"Prometheus","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/providers":{"get":{"operationId":"get_ai_providers","summary":"List providers","description":"List the caller's providers.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Provider"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_providers","summary":"Create a provider","description":"Create one provider.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Provider"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/providers/global":{"get":{"operationId":"get_ai_providers_global","summary":"List providers across tenants","description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Provider"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/providers/mcp-tools":{"post":{"operationId":"post_ai_providers_mcp-tools","summary":"Mcp Tools (provider)","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/providers/{owner}/{name}":{"delete":{"operationId":"delete_ai_providers_by_owner_by_name","summary":"Delete a provider","description":"Delete one provider.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Provider"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_providers_by_owner_by_name","summary":"Retrieve a provider","description":"Read one provider by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Provider"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_providers_by_owner_by_name","summary":"Update a provider","description":"Update one provider. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Provider"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_providers_by_owner_by_name","summary":"Replace a provider","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Provider"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/rag/context":{"get":{"operationId":"get_ai_rag_context","summary":"Return every stored chunk of one file_id (full document context).","description":"Return every stored chunk of one file_id (full document context).\nConsolidates the retired chat-rag-api GET /documents/{id}/context.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/DocSearchResult"},"type":"array"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/rag/delete":{"post":{"operationId":"post_ai_rag_delete","summary":"Delete all chunks of one or more uploaded files (by file_id) from the owner's Search+Vector index.","description":"Delete all chunks of one or more uploaded files (by file_id) from\nthe owner's Search+Vector index. Consolidates the retired chat-rag-api\nDELETE /documents.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"additionalProperties":{},"type":"object"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/rag/embed":{"post":{"operationId":"post_ai_rag_embed","summary":"Parse, chunk, and embed one uploaded file under its file_id into the unified Search+Vector index, scoped to the authenticated owner.","description":"Parse, chunk, and embed one uploaded file under its file_id into\nthe unified Search+Vector index, scoped to the authenticated owner. Provide\ninline `content` or a `url` to fetch+parse (PDF/CSV/XLSX/PPTX/…). Re-embedding\nthe same file_id replaces its chunks. Consolidates the retired chat-rag-api\nPOST /embed and /local/embed.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/RagEmbedResult"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/rag/ingest":{"post":{"operationId":"post_ai_rag_ingest","summary":"Unified RAG ingest: parse + chunk + embed documents and pipe them to BOTH Hanzo Vector (semantic) AND Hanzo Search (keyword) under the tenant index {owner}-{store}-docs — the same index /v1/chat retrieval reads.","description":"Unified RAG ingest: parse + chunk + embed documents and pipe them\nto BOTH Hanzo Vector (semantic) AND Hanzo Search (keyword) under the tenant\nindex {owner}-{store}-docs — the same index /v1/chat retrieval reads. The\nsource is pluggable: \"upload\" (inline files/documents), \"github\" (index a\nrepo), \"crawl\" (web), or \"s3\" (the store's object-storage space). The owner\nis bound to the authenticated principal; the client-supplied owner is never\ntrusted.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/IngestStats"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/rag/query":{"post":{"operationId":"post_ai_rag_query","summary":"Retrieve the top-K chunks relevant to a query, scoped to a single uploaded file (`file_id`).","description":"Retrieve the top-K chunks relevant to a query, scoped to a single\nuploaded file (`file_id`). Hybrid keyword+vector retrieval over the same\nindex. Consolidates the retired chat-rag-api POST /query.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/DocSearchResult"},"type":"array"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/rag/query-multiple":{"post":{"operationId":"post_ai_rag_query-multiple","summary":"Retrieve the top-K chunks relevant to a query, scoped to a SET of uploaded files (`file_ids`).","description":"Retrieve the top-K chunks relevant to a query, scoped to a SET of\nuploaded files (`file_ids`). Consolidates the retired chat-rag-api POST\n/query_multiple. Shares one retrieval path with /rag/query.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/DocSearchResult"},"type":"array"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/records":{"get":{"operationId":"get_ai_records","summary":"List records","description":"List the caller's records.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Audit"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_records","summary":"Create a record","description":"Create one record.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Audit"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/records/batch":{"post":{"operationId":"post_ai_records_batch","summary":"Batch (record)","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/records/commit":{"post":{"operationId":"post_ai_records_commit","summary":"Commit (record)","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/records/commit-second":{"post":{"operationId":"post_ai_records_commit-second","summary":"Commit Second (record)","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/records/query":{"get":{"operationId":"get_ai_records_query","summary":"Query (record)","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/records/query-second":{"get":{"operationId":"get_ai_records_query-second","summary":"Query Second (record)","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/records/{owner}/{name}":{"delete":{"operationId":"delete_ai_records_by_owner_by_name","summary":"Delete a record","description":"Delete one record.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Audit"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_records_by_owner_by_name","summary":"Retrieve a record","description":"Read one record by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Audit"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_records_by_owner_by_name","summary":"Update a record","description":"Update one record. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Audit"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_records_by_owner_by_name","summary":"Replace a record","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Audit"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/remote-connections":{"get":{"operationId":"get_ai_remote-connections","summary":"List remote-connections","description":"List the caller's remote-connections.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Connection"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_remote-connections","summary":"Create a connection","description":"Create one connection.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Connection"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/remote-connections/{owner}/{name}":{"delete":{"operationId":"delete_ai_remote-connections_by_owner_by_name","summary":"Delete a connection","description":"Delete one connection.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Connection"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_remote-connections_by_owner_by_name","summary":"Retrieve a connection","description":"Read one connection by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Connection"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_remote-connections_by_owner_by_name","summary":"Update a connection","description":"Update one connection. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Connection"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_remote-connections_by_owner_by_name","summary":"Replace a connection","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Connection"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/remote-connections/{owner}/{name}/start":{"post":{"operationId":"post_ai_remote-connections_by_owner_by_name_start","summary":"Start (connection)","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/remote-connections/{owner}/{name}/stop":{"post":{"operationId":"post_ai_remote-connections_by_owner_by_name_stop","summary":"Stop (connection)","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/router/artifact-meta":{"delete":{"operationId":"delete_ai_router_artifact-meta","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_router_artifact-meta","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_router_artifact-meta","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_router_artifact-meta","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_router_artifact-meta","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/router/catalog":{"get":{"operationId":"get_ai_router_catalog","summary":"Lists the Zen and Enso routing catalogs: what each serves, its accounts and model health, and its version history.","description":"Lists the Zen and Enso routing catalogs: what each serves, its\naccounts and model health, and its version history. SuperAdmin only.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/ai.RoutingView"},"type":"array"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_router_catalog","summary":"Applies an edited catalog to one family, made from its newest version, and records the new version.","description":"Applies an edited catalog to one family, made from its newest\nversion, and records the new version. SuperAdmin only.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.RoutingEdit"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/RoutingVersion"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/router/catalog/propose":{"post":{"operationId":"post_ai_router_catalog_propose","summary":"Answers the diff an edited catalog would apply to a family, and the version it would be made from.","description":"Answers the diff an edited catalog would apply to a family,\nand the version it would be made from. Nothing is applied. SuperAdmin only.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.RoutingEdit"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/ai.RoutingProposal"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/router/catalog/rollback":{"post":{"operationId":"post_ai_router_catalog_rollback","summary":"Applies an earlier version of a family's catalog again, as a new version.","description":"Applies an earlier version of a family's catalog again, as\na new version. SuperAdmin only.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.RoutingEdit"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/RoutingVersion"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/router/catalog/test":{"post":{"operationId":"post_ai_router_catalog_test","summary":"Sends one short turn to a SKU through its family and answers which upstream wrote it and how long it took.","description":"Sends one short turn to a SKU through its family and answers\nwhich upstream wrote it and how long it took. SuperAdmin only.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.RoutingEdit"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/ai.RoutingProbe"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/router/data":{"delete":{"operationId":"delete_ai_router_data","summary":"Router Data","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_router_data","summary":"Router Data","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/router/defaults":{"delete":{"operationId":"delete_ai_router_defaults","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_router_defaults","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_router_defaults","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_router_defaults","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_router_defaults","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/router/history":{"get":{"operationId":"get_ai_router_history","summary":"Returns the router-improvement time-series.","description":"Returns the router-improvement time-series. Two scopes, one route,\nmirroring /v1/ai/router/stats:\n\n  - ?scope=platform — PUBLIC-safe aggregate over ALL orgs, no authentication. Emits\n    the daily reward/cost-saved/adoption series (task mix included, model ids NOT)\n    and the retrain timeline. This is what world.hanzo.ai polls.\n  - default (org scope) — requires a signed-in principal, scoped to the caller's OWN\n    org (a super admin may pass ?org= to target another or \"\" for all).\n\nWindow: ?days=N (default 30, capped at 90). Aggregates only.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/ai.RouterHistory"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/router/judge-panel":{"get":{"operationId":"get_ai_router_judge-panel","summary":"Returns the LIVE Mean-Field Judge Panel state: the configured panel + dynamic judge posture (enabled/sample) resolved from the \"*\" GlobalDefaultOwner row, the live in-process per-judge calibration (weight/mean/n), and the static published benchmark.","description":"Returns the LIVE Mean-Field Judge Panel state: the configured\npanel + dynamic judge posture (enabled/sample) resolved from the \"*\"\nGlobalDefaultOwner row, the live in-process per-judge calibration (weight/mean/n),\nand the static published benchmark. PUBLIC-safe and platform-global (model ids +\nscalars only), so it rides the same unauthenticated, balance-exempt class as\n/v1/ai/router/stats?scope=platform — the world widget polls it with no auth. The judge\nstate is a single in-process population (not per-org), so there is nothing to scope;\n?scope=platform is accepted for symmetry with router-stats.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/ai.JudgePanelState"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/router/ledger":{"delete":{"operationId":"delete_ai_router_ledger","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_router_ledger","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_router_ledger","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_router_ledger","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_router_ledger","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/router/policy":{"delete":{"operationId":"delete_ai_router_policy","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_router_policy","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_router_policy","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_router_policy","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_router_policy","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/router/rewards":{"delete":{"operationId":"delete_ai_router_rewards","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_router_rewards","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_router_rewards","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_router_rewards","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_router_rewards","summary":"The HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]).","description":"The HTTP transport binding for the RESTful router-config\nnouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and\n/v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway —\nthe SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200\nhandler serves over the gateway transport. The native ZAP\nhandler is the ONE and ONLY implementation of these routes; this is purely the\napi.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the\nsplit-brain the router refactor removed stays removed.\n\nWhy a bridge and not a twin controller method: one handler serves both\ntransports, so the HTTP route and the ZAP message read and write router settings\nthrough the same code and cannot come to disagree about them. Routing these nouns\nthrough the ZAP handler over one adapter keeps a single source of truth.\n\nIdentity is the request's own Bearer credential (Authorization header), which\nthe native handlers resolve exactly as the gateway does — every caller\n(console, chat, app) already sends it. The dispatched handler returns a ZAP\nmessage whose status is field 0 and body is field 4 (BuildCloudResponse /\nBuildGatewayResponse layout); both are relayed verbatim. The route is mapped\n\"*\" (any verb) because the native handler is method-aware: /v1/ai/router/policy\nsplits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns\n405 for a verb it does not own.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Response"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/router/stats":{"get":{"operationId":"get_ai_router_stats","summary":"Returns the router observability aggregate.","description":"Returns the router observability aggregate. Two scopes, one route:\n\n  - ?scope=platform — PUBLIC-safe aggregate over ALL orgs, no authentication.\n    Emits rates, shares, per-task/per-model counts, throughput, and the cost\n    RATIO (saved_pct) + counterfactual model id, but NEVER absolute $ levels,\n    org identity, raw events, or feature vectors. This is what world.hanzo.ai\n    polls.\n  - default (org scope) — requires a signed-in principal; scoped to the caller's\n    OWN org (a super admin may pass ?org= to target another org or \"\" for all).\n    Carries the absolute $/MTok indices for the admin savings panel.\n\nWindow: ?since= (RFC3339) or ?hours= (default 24, capped). Aggregates only.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/ai.RouterStats"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/routes":{"get":{"operationId":"get_ai_routes","summary":"List routes","description":"List the caller's routes.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/ModelRoute"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_routes","summary":"Create a model-route","description":"Create one model-route.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/ModelRoute"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/routes/{owner}/{name}":{"delete":{"operationId":"delete_ai_routes_by_owner_by_name","summary":"Delete a model-route","description":"Delete one model-route.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/ModelRoute"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_routes_by_owner_by_name","summary":"Retrieve a model-route","description":"Read one model-route by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/ModelRoute"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_routes_by_owner_by_name","summary":"Update a model-route","description":"Update one model-route. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/ModelRoute"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_routes_by_owner_by_name","summary":"Replace a model-route","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/ModelRoute"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/scales":{"get":{"operationId":"get_ai_scales","summary":"List scales","description":"List the caller's scales.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Scale"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_scales","summary":"Create a scale","description":"Create one scale.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Scale"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/scales/global":{"get":{"operationId":"get_ai_scales_global","summary":"List scales across tenants","description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Scale"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/scales/public":{"get":{"operationId":"get_ai_scales_public","summary":"Public (scale)","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/scales/{owner}/{name}":{"delete":{"operationId":"delete_ai_scales_by_owner_by_name","summary":"Delete a scale","description":"Delete one scale.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Scale"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_scales_by_owner_by_name","summary":"Retrieve a scale","description":"Read one scale by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Scale"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_scales_by_owner_by_name","summary":"Update a scale","description":"Update one scale. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Scale"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_scales_by_owner_by_name","summary":"Replace a scale","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Scale"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/scans":{"get":{"operationId":"get_ai_scans","summary":"List scans","description":"List the caller's scans.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Sweep"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_scans","summary":"Create a scan","description":"Create one scan.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Sweep"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/scans/{owner}/{name}":{"delete":{"operationId":"delete_ai_scans_by_owner_by_name","summary":"Delete a scan","description":"Delete one scan.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Sweep"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_scans_by_owner_by_name","summary":"Retrieve a scan","description":"Read one scan by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Sweep"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_scans_by_owner_by_name","summary":"Update a scan","description":"Update one scan. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Sweep"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_scans_by_owner_by_name","summary":"Replace a scan","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Sweep"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/signin":{"post":{"operationId":"post_ai_signin","summary":"Signin","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/signin-sessions":{"get":{"operationId":"get_ai_signin-sessions","summary":"List signin-sessions","description":"List the caller's signin-sessions.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Session"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_signin-sessions","summary":"Create a session","description":"Create one session.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Session"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/signin-sessions/duplicated":{"get":{"operationId":"get_ai_signin-sessions_duplicated","summary":"Duplicated (session)","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/signin-sessions/{owner}/{name}":{"delete":{"operationId":"delete_ai_signin-sessions_by_owner_by_name","summary":"Delete a session","description":"Delete one session.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Session"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_signin-sessions_by_owner_by_name","summary":"Retrieve a session","description":"Read one session by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Session"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_signin-sessions_by_owner_by_name","summary":"Update a session","description":"Update one session. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Session"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_signin-sessions_by_owner_by_name","summary":"Replace a session","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Session"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/signout":{"post":{"operationId":"post_ai_signout","summary":"Signout","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/stores":{"get":{"operationId":"get_ai_stores","summary":"List stores","description":"List the caller's stores.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Store"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_stores","summary":"Create a store","description":"Create one store.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Store"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/stores/global":{"get":{"operationId":"get_ai_stores_global","summary":"List stores across tenants","description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Store"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/stores/names":{"get":{"operationId":"get_ai_stores_names","summary":"Names (store)","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/stores/providers":{"get":{"operationId":"get_ai_stores_providers","summary":"Providers (store)","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/stores/{owner}/{name}":{"delete":{"operationId":"delete_ai_stores_by_owner_by_name","summary":"Delete a store","description":"Delete one store.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Store"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_stores_by_owner_by_name","summary":"Retrieve a store","description":"Read one store by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Store"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_stores_by_owner_by_name","summary":"Update a store","description":"Update one store. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Store"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_stores_by_owner_by_name","summary":"Replace a store","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Store"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/stores/{owner}/{name}/vectors":{"post":{"operationId":"post_ai_stores_by_owner_by_name_vectors","summary":"Vectors (store)","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/system":{"get":{"operationId":"get_ai_system","summary":"System","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/tasks":{"get":{"operationId":"get_ai_tasks","summary":"List tasks","description":"List the caller's tasks.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Task"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_tasks","summary":"Create a task","description":"Create one task.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Task"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/tasks/global":{"get":{"operationId":"get_ai_tasks_global","summary":"List tasks across tenants","description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Task"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/tasks/{owner}/{name}":{"delete":{"operationId":"delete_ai_tasks_by_owner_by_name","summary":"Delete a task","description":"Delete one task.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Task"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_tasks_by_owner_by_name","summary":"Retrieve a task","description":"Read one task by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Task"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_tasks_by_owner_by_name","summary":"Update a task","description":"Update one task. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Task"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_tasks_by_owner_by_name","summary":"Replace a task","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Task"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/tasks/{owner}/{name}/analyze":{"post":{"operationId":"post_ai_tasks_by_owner_by_name_analyze","summary":"Analyze (task)","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/tasks/{owner}/{name}/document":{"post":{"operationId":"post_ai_tasks_by_owner_by_name_document","summary":"Document (task)","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/templates":{"get":{"operationId":"get_ai_templates","summary":"List templates","description":"List the caller's templates.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Template"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_templates","summary":"Create a template","description":"Create one template.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Template"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/templates/{owner}/{name}":{"delete":{"operationId":"delete_ai_templates_by_owner_by_name","summary":"Delete a template","description":"Delete one template.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Template"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_templates_by_owner_by_name","summary":"Retrieve a template","description":"Read one template by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Template"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_templates_by_owner_by_name","summary":"Update a template","description":"Update one template. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Template"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_templates_by_owner_by_name","summary":"Replace a template","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Template"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/traffic/globe":{"get":{"operationId":"get_ai_traffic_globe","summary":"Returns the PUBLIC live request-geo aggregate for the world.hanzo.ai \"Hanzo mode\" globe: WHERE requests to api.hanzo.ai are coming from, as country/region points with per-service-class counts, plus headline throughput rates.","description":"Returns the PUBLIC live request-geo aggregate for the\nworld.hanzo.ai \"Hanzo mode\" globe: WHERE requests to api.hanzo.ai are coming from,\nas country/region points with per-service-class counts, plus headline throughput\nrates.\n\nIt is AUTH-exempt and BALANCE-exempt exactly like /v1/ai/router/stats?scope=platform:\n  - auth: the controller name \"traffic/globe\" is neither a get-/update- CRUD name\n    nor a super-admin/present-credential endpoint, so the authz filter passes it\n    through, and this handler requires no principal.\n  - balance: isBalanceExempt(\"/v1/ai/traffic/...\") returns true.\n\nIt exposes ONLY aggregates — counts, rates, and country/region centroids — and\nNEVER any IP, per-request row, org, or user dimension (see object/traffic.go).\nMarketing telemetry; nothing sensitive.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/TrafficGlobe"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/training-contribution":{"get":{"operationId":"get_ai_training-contribution","summary":"Training Contribution","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_training-contribution","summary":"Training Contribution","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_training-contribution","summary":"Training Contribution","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/tree-files":{"post":{"operationId":"post_ai_tree-files","summary":"Create a tree-file","description":"Create one tree-file.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/TreeFile"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/tree-files/{owner}/{name}":{"delete":{"operationId":"delete_ai_tree-files_by_owner_by_name","summary":"Delete a tree-file","description":"Delete one tree-file.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/TreeFile"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_tree-files_by_owner_by_name","summary":"Update a tree-file","description":"Update one tree-file. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/TreeFile"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_tree-files_by_owner_by_name","summary":"Replace a tree-file","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/TreeFile"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/usages":{"get":{"operationId":"get_ai_usages","summary":"List usages","description":"List the caller's usages.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Count"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/usages/by-user":{"get":{"operationId":"get_ai_usages_by-user","summary":"By User (usage)","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/usages/cloud":{"get":{"operationId":"get_ai_usages_cloud","summary":"Cloud (usage)","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/usages/range":{"get":{"operationId":"get_ai_usages_range","summary":"Range (usage)","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/usages/user-names":{"get":{"operationId":"get_ai_usages_user-names","summary":"User Names (usage)","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/vectors":{"get":{"operationId":"get_ai_vectors","summary":"List vectors","description":"List the caller's vectors.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Vector"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_vectors","summary":"Create a vector","description":"Create one vector.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Vector"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/vectors/all":{"delete":{"operationId":"delete_ai_vectors_all","summary":"All (vector)","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/vectors/global":{"get":{"operationId":"get_ai_vectors_global","summary":"List vectors across tenants","description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Vector"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/vectors/{owner}/{name}":{"delete":{"operationId":"delete_ai_vectors_by_owner_by_name","summary":"Delete a vector","description":"Delete one vector.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Vector"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_vectors_by_owner_by_name","summary":"Retrieve a vector","description":"Read one vector by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Vector"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_vectors_by_owner_by_name","summary":"Update a vector","description":"Update one vector. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Vector"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_vectors_by_owner_by_name","summary":"Replace a vector","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Vector"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/version":{"get":{"operationId":"get_ai_version","summary":"Version","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/videos":{"get":{"operationId":"get_ai_videos","summary":"List videos","description":"List the caller's videos.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Video"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_videos","summary":"Create a video","description":"Create one video.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Video"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/videos/global":{"get":{"operationId":"get_ai_videos_global","summary":"List videos across tenants","description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Video"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/videos/upload":{"post":{"operationId":"post_ai_videos_upload","summary":"Upload (video)","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/videos/{owner}/{name}":{"delete":{"operationId":"delete_ai_videos_by_owner_by_name","summary":"Delete a video","description":"Delete one video.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Video"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_videos_by_owner_by_name","summary":"Retrieve a video","description":"Read one video by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Video"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_videos_by_owner_by_name","summary":"Update a video","description":"Update one video. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Video"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_videos_by_owner_by_name","summary":"Replace a video","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Video"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/workflows":{"get":{"operationId":"get_ai_workflows","summary":"List workflows","description":"List the caller's workflows.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Workflow"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_ai_workflows","summary":"Create a workflow","description":"Create one workflow.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Workflow"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/workflows/global":{"get":{"operationId":"get_ai_workflows_global","summary":"List workflows across tenants","description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"items":{"$ref":"#/components/schemas/Workflow"},"type":"array"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ai/workflows/{owner}/{name}":{"delete":{"operationId":"delete_ai_workflows_by_owner_by_name","summary":"Delete a workflow","description":"Delete one workflow.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Workflow"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"get":{"operationId":"get_ai_workflows_by_owner_by_name","summary":"Retrieve a workflow","description":"Read one workflow by its (owner, name) key.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Workflow"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"patch":{"operationId":"patch_ai_workflows_by_owner_by_name","summary":"Update a workflow","description":"Update one workflow. PATCH and PUT reach the same handler, which has always taken a whole object.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Workflow"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"put":{"operationId":"put_ai_workflows_by_owner_by_name","summary":"Replace a workflow","description":"Identical to PATCH — the handler takes a whole object either way.","tags":["ai"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/Workflow"}},"type":"object"}]}}},"description":"Envelope. `status` is \"ok\" or \"error\" — check it; a handled failure is still HTTP 200."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/allowance":{"get":{"operationId":"get_allowance","summary":"Answers what the CALLER has left of their plan's free-call allowance this period, and the instant the count starts again.","description":"Answers what the CALLER has left of their plan's free-call allowance this period,\nand the instant the count starts again.\n\nThis is the number a product shows beside the composer — \"17 of 20 left today\" —\nand the moment to offer a plan is when it reaches zero. It READS: asking does not\nspend, so a page that polls it costs the caller nothing.\n\nA bounded caller is POOLED: the Free plan is limited usage from one pool every\nfree user shares — the platform's vendor accounts for free models — so the answer\nsays so (pooled) and carries that pool's standing: available, busy or exhausted,\nand when it refills. The pool is read from the process that spends it and is\nabsent when that process does not answer, never guessed. A paid plan is not\npooled and carries no pool: its usage is metered in money.\n\nThe subject is the caller's own, resolved from the verified credential, and can\nnever be named in the request — so this is a mirror, not a lookup of someone else.\nAn unauthenticated caller is refused: there is no allowance without someone to\nhold it.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["allowance"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/allowance.Allowance"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"allowance","x-public":true,"x-tool":true}},"/v1/ask":{"post":{"operationId":"post_ask","summary":"Ask a grounded question about your own org","description":"Answers a natural-language question about the CALLER'S OWN org, from real figures rather than from the model's memory.\n\nThe question is classified to a grounded domain, that domain's read runs IN-PROCESS under the caller's own credentials, and only then is the result narrated. So the figures and their sources are the domain's, resolved before any model call and never altered by one — a wrong answer is a wrong query, never an invention.\n\nDomains: books (the org's ledger), projects (what is built and what of it is deployed), git (the org's repositories and what changed in them), and web (search, news, research, deep). A validated principal is required; the answer is scoped to that principal's org and nothing else.","tags":["ask"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/askRequest"}}}},"x-app":"ask","x-public":true}},"/v1/ask/web":{"post":{"operationId":"research_web","summary":"Research a question on the live web and answer it with sources cited","description":"Researches a question on the live web and answers it with its\nsources cited.\n\nThis is the DEEP one. It plans the question into topics, runs several web\nsearches, FETCHES AND READS the pages it finds, ranks them, and writes a\ngrounded answer with inline markdown citations. Use it for anything that needs\nevidence, comparison or current fact — \"what changed in X\", \"compare A and B\",\n\"is this claim true\". For a plain list of links, use search_web instead; for\none page you already have the URL of, use read_page.\n\n`mode` buys depth: `search` is a single fast pass, `news` biases to recency,\n`research` plans and iterates, `deep` surveys widest. `sources` narrows the\nevidence to `web`, `news`, `academic`, `github`, `reddit` or `x` — each becomes\na site-scoped search, which is how this reaches X/Twitter posts.\n\nEVERY CITATION IS A PAGE THIS CALL FETCHED. That is a property of the text and\nnot an instruction to the model: each source is fenced with a per-request nonce\nso a crawled page cannot print itself a source number, and every markdown link\nin the answer is checked against the gathered set before it is returned. So a\nlink in `answer` always appears in `sources`, and a page that was not read\ncannot be cited.\n\nIt is BOUNDED and it degrades rather than failing: a mode's rounds, wall clock\nand token ceiling all cap it, and a search that finds little or a page that\nwill not load yields a thinner answer, never an error. A validated principal is\nrequired, and the answer is billed once to that principal's org.","tags":["ask"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ask.webQuestion"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ask.Report"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ask","x-public":true,"x-tool":true}},"/v1/audio/foley":{"post":{"operationId":"post_audio_foley","summary":"Serves the generative audio verbs — /v1/audio/voice (TTS), /music, /foley — that the Zen family serves natively.","description":"Serves the generative audio verbs — /v1/audio/voice (TTS), /music,\n/foley — that the Zen family serves natively. It resolves the SKU and, for a Zen\nmodel, forwards to zen's matching verb billed per call at the discovered price.\nThese verbs are Zen-native; a non-Zen model is rejected.","tags":["ai"],"x-app":"ai","x-public":true}},"/v1/audio/music":{"post":{"operationId":"post_audio_music","summary":"Serves the generative audio verbs — /v1/audio/voice (TTS), /music, /foley — that the Zen family serves natively.","description":"Serves the generative audio verbs — /v1/audio/voice (TTS), /music,\n/foley — that the Zen family serves natively. It resolves the SKU and, for a Zen\nmodel, forwards to zen's matching verb billed per call at the discovered price.\nThese verbs are Zen-native; a non-Zen model is rejected.","tags":["ai"],"x-app":"ai","x-public":true}},"/v1/audio/speech":{"post":{"operationId":"post_audio_speech","summary":"The OpenAI-compatible TTS endpoint (POST /v1/audio/speech).","description":"The OpenAI-compatible TTS endpoint (POST /v1/audio/speech). It\nauthenticates the caller, resolves `model` to its TTS provider (the SAME model-route\nresolution the chat/images/video endpoints use — so a BYO node registered as a TTS\nprovider works transparently), synthesizes the audio, and streams the bytes back.\nThis is the ONE way to synthesize speech: OpenAI-shaped, with no store or\nmessage coupling, so a caller needs no chat to speak.","tags":["ai"],"x-app":"ai","x-public":true}},"/v1/audio/transcript":{"post":{"operationId":"post_audio_transcript","summary":"Serves the growing transcript over HTTP: POST opens one, POST to its id pushes raw pcm16 at 16 kHz, and DELETE closes it with the settled text.","description":"Serves the growing transcript over HTTP: POST opens one, POST to\nits id pushes raw pcm16 at 16 kHz, and DELETE closes it with the settled text.\nThe one implementation is zapTranscriptHandler below; this binds it to\napi.hanzo.ai through the in-process gateway bridge, as the router nouns are.","tags":["ai"],"x-app":"ai","x-public":true}},"/v1/audio/transcript/{id}":{"delete":{"operationId":"delete_audio_transcript_by_id","summary":"Serves the growing transcript over HTTP: POST opens one, POST to its id pushes raw pcm16 at 16 kHz, and DELETE closes it with the settled text.","description":"Serves the growing transcript over HTTP: POST opens one, POST to\nits id pushes raw pcm16 at 16 kHz, and DELETE closes it with the settled text.\nThe one implementation is zapTranscriptHandler below; this binds it to\napi.hanzo.ai through the in-process gateway bridge, as the router nouns are.","tags":["ai"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"ai","x-public":true},"post":{"operationId":"post_audio_transcript_by_id","summary":"Serves the growing transcript over HTTP: POST opens one, POST to its id pushes raw pcm16 at 16 kHz, and DELETE closes it with the settled text.","description":"Serves the growing transcript over HTTP: POST opens one, POST to\nits id pushes raw pcm16 at 16 kHz, and DELETE closes it with the settled text.\nThe one implementation is zapTranscriptHandler below; this binds it to\napi.hanzo.ai through the in-process gateway bridge, as the router nouns are.","tags":["ai"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"ai","x-public":true}},"/v1/audio/transcriptions":{"post":{"operationId":"post_audio_transcriptions","summary":"The OpenAI-compatible STT endpoint (POST /v1/audio/transcriptions, multipart: file + model [+ language + response_format]).","description":"The OpenAI-compatible STT endpoint\n(POST /v1/audio/transcriptions, multipart: file + model [+ language +\nresponse_format]). It mirrors AudioSpeech exactly: authenticate the caller,\nresolve `model` to its STT provider through the SAME model-route resolution\n(so the in-cluster speech service — or any BYO node registered as an STT\nprovider — works transparently), transcribe, and return the OpenAI body.\nThis is the ONE way to transcribe: OpenAI-shaped, with no store coupling, so a\ncaller needs no chat to be heard.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/openai.AudioResponse"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/audio/transcriptions/public":{"post":{"operationId":"post_audio_transcriptions_public","summary":"Transcribes up to a minute of audio for a caller with no account, on Hanzo's own transcriber, within a daily allowance per visitor.","description":"Transcribes up to a minute of audio for a caller with no\naccount, on Hanzo's own transcriber, within a daily allowance per visitor.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/openai.AudioResponse"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/audio/voice":{"post":{"operationId":"post_audio_voice","summary":"Serves the generative audio verbs — /v1/audio/voice (TTS), /music, /foley — that the Zen family serves natively.","description":"Serves the generative audio verbs — /v1/audio/voice (TTS), /music,\n/foley — that the Zen family serves natively. It resolves the SKU and, for a Zen\nmodel, forwards to zen's matching verb billed per call at the discovered price.\nThese verbs are Zen-native; a non-Zen model is rejected.","tags":["ai"],"x-app":"ai","x-public":true}},"/v1/audit":{"get":{"operationId":"get_audit","summary":"Reads the caller's OWN org audit trail, newest first, with the total the filter matched so a console can page it.","description":"Reads the caller's OWN org audit trail, newest first, with the total the\nfilter matched so a console can page it.\n\nEvery filter is optional and applies WITHIN the caller's org — the org itself is\nthe validated principal's and can never be widened by a request. Fails closed:\nan absent principal is a true \"not signed in\" (401), and a deployment with no\nlocal tamper-evident store answers an honest 501 rather than silently serving\nsomebody else's trail.","tags":["audit"],"parameters":[{"name":"sub","in":"query","required":false,"description":"Sub narrows the trail to one actor — the validated subject that made the\nrequest. Blank means every actor in the org.","schema":{"type":"string"}},{"name":"action","in":"query","required":false,"description":"Action narrows it to one action name, e.g. \"machine.create\".","schema":{"type":"string"},"example":"machine.create"},{"name":"resource","in":"query","required":false,"description":"Resource narrows it to one resource TYPE, e.g. \"apikey\".","schema":{"type":"string"}},{"name":"resourceId","in":"query","required":false,"description":"ResourceID narrows it to one resource instance.","schema":{"type":"string"}},{"name":"result","in":"query","required":false,"description":"Result narrows it to one outcome: \"success\", \"deny\" or \"error\".","schema":{"type":"string"},"example":"success"},{"name":"since","in":"query","required":false,"description":"Since is the inclusive lower time bound, RFC3339. An unparseable value is\nignored rather than refused — one malformed filter must not hide the trail.","schema":{"type":"string"},"example":"2026-07-01T00:00:00Z"},{"name":"until","in":"query","required":false,"description":"Until is the upper time bound, RFC3339, with the same tolerance.","schema":{"type":"string"}},{"name":"pageSize","in":"query","required":false,"description":"PageSize is rows per page, default 100. A value that is not a positive\ninteger falls back to the default.","schema":{"type":"string"},"example":"50"},{"name":"p","in":"query","required":false,"description":"Page is the 1-based page number, driving the offset. Anything below 2 reads\nthe first page.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/audit.trailPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"audit","x-public":true,"x-tool":true}},"/v1/author":{"get":{"operationId":"get_author","summary":"Returns the caller's author-program dashboard: enrolment status, linked forge login, verified repositories and owner-wide claims, recorded deploys, accrued / pending / paid royalty, and the payout history.","description":"Returns the caller's author-program dashboard: enrolment status,\nlinked forge login, verified repositories and owner-wide claims, recorded deploys,\naccrued / pending / paid royalty, and the payout history.\n\nIt answers ONE OF TWO SHAPES from this address. An org that has never connected\ngets {\"isAuthor\": false, \"defaultShareBps\", \"badgeBase\"} — an honest \"not enrolled\"\nrather than a 404, so the console can render the connect form. An enrolled org gets\nthe dashboard: isAuthor, id, status, githubLogin, verified, verifyCode, verifyFile,\nverifySnippet, shareBps, badgeBase, repos, orgs, deploys, accruedCents,\npendingCents, paidCents, payouts and ledger.\n\nFor an APPROVED author this read ALSO runs the accrual sweep opportunistically, so\nthe dashboard is self-updating. That is why the royalty AUDIT lives at its own\naddress: an audit must not move the money it is auditing.","tags":["author"],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"author","x-public":true,"x-tool":true}},"/v1/author/basis":{"get":{"operationId":"get_author_basis","summary":"Returns the AUDIT TRAIL behind the caller's own royalty: every ledger row with the spend it was computed from, the share applied at the time, the platform's matching half, whether each row satisfies the formula, and the attribution edges that already existed when the row was written.","description":"Returns the AUDIT TRAIL behind the caller's own royalty: every\nledger row with the spend it was computed from, the share applied at the time, the\nplatform's matching half, whether each row satisfies the formula, and the\nattribution edges that already existed when the row was written.\n\nIt answers ONE OF TWO SHAPES. An org that has never connected gets\n{\"isAuthor\": false, \"defaultShareBps\"} — never a 404, which would answer \"is this\norg an author?\" for anyone who asked. An enrolled org gets the basis: isAuthor, id,\nstatus, asOf, shareBps, platformShareBps, defaultShareBps, shareSource, settlesTo,\nmethod (the formula, the rate card and the sizing), ledger, reconciliation, window,\nand period when one was requested.\n\nThis read NEVER sweeps, and that is the point of it being a separate address from\nthe dashboard: an audit must not move the money it is auditing, so calling it N\ntimes leaves the balances and the ledger byte-identical.","tags":["author"],"parameters":[{"name":"period","in":"query","required":false,"description":"Period is the UTC accrual month, YYYY-MM. Empty means every period; any other\nshape is refused with 400, because the period is echoed back and used as a SQL\nfilter and is only ever accepted in the one form the accrual latch mints.","schema":{"type":"string"},"example":"2026-07"}],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"author","x-public":true,"x-tool":true}},"/v1/author/connect":{"post":{"operationId":"post_author_connect","summary":"Enrols the caller's org in the author program at status \"connected\" and returns its enrolment, including the verify code the file method needs.","description":"Enrols the caller's org in the author program at status \"connected\"\nand returns its enrolment, including the verify code the file method needs. It is\nIDEMPOTENT: a second call returns the same enrolment rather than a conflict.\n\nThe forge login is taken from IAM's LINKED account for the provider when there is\none — that is identity proof, not a claim — and only otherwise from the login in\nthe body, which then has to be proven per repository. Connecting does not admit an\norg to earning: a platform reviewer approves that separately.\n\nAnswers 201 when it enrolled the org and 200 when it found an existing enrolment.","tags":["author"],"requestBody":{"content":{"application/json":{"example":{"login":"octocat","provider":"github"},"schema":{"$ref":"#/components/schemas/author.connectRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/author.enrolment"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"author","x-public":true,"x-tool":true}},"/v1/author/deploys/record":{"post":{"operationId":"post_author_deploys_record","summary":"Records that the caller's org deployed a project built from a source repository, which is the edge that makes an author's work earn royalty.","description":"Records that the caller's org deployed a project built from a\nsource repository, which is the edge that makes an author's work earn royalty.\n\nIt is deliberately NOT an error for a deploy to attribute to nobody: a project\nbuilt from no repository, or from one no author has verified, answers\n{\"recorded\": false, \"reason\"} so a deploy pipeline can fire this on every deploy\nwithout branching. Attribution resolves per-repository first, then owner-wide, so a\nrepository with its own claim always earns for its own author.\n\nA deploy of a Hanzo-maintained template attributes to the platform treasury, and a\nself-deploy (the author's own org deploying its own repository) is recorded for\nprovenance but excluded from accrual. The edge is idempotent per\nrepository+project+org.\n\nAnswers 201 when it recorded a new edge and 200 otherwise.","tags":["author"],"requestBody":{"content":{"application/json":{"example":{"project":"prj_1f…","repoUrl":"github.com/octocat/hello-world"},"schema":{"$ref":"#/components/schemas/author.deployRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/author.deployRecord"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"author","x-public":true,"x-tool":true}},"/v1/author/repos/verify":{"post":{"operationId":"post_author_repos_verify","summary":"Proves that the caller owns a repository — or a whole OWNER — and records the claim, which is what makes deploys of that code earn royalty.","description":"Proves that the caller owns a repository — or a whole OWNER — and\nrecords the claim, which is what makes deploys of that code earn royalty.\n\nOwnership is proven the SAME two ways in both cases, tried in order: an IAM-linked\nforge token with admin or push permission, or a hanzo.json on the default branch\ncarrying the author's verify code. Claiming an OWNER proves it against that\nowner's \".github\" control repository, and is exactly as strong as a per-repository\nclaim — an owner the caller cannot prove is refused with 422, never assumed.\n\nA per-repository claim wins over an owner-wide one, so a specifically-claimed\nrepository always earns for its own author. A repository another author has\nalready verified is a 409. The org must have connected first.\n\nAnswers 201 when it recorded a new claim and 200 when the claim already existed.","tags":["author"],"requestBody":{"content":{"application/json":{"example":{"repoUrl":"github.com/octocat/hello-world"},"schema":{"$ref":"#/components/schemas/author.verifyRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/author.claim"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"author","x-public":true,"x-tool":true}},"/v1/authz/check":{"post":{"operationId":"post_authz_check","summary":"Ask whether a subject may act on an object","description":"Answers one policy question — may this subject take this action on this object — against the CALLER'S OWN org policy set, and answers it with a bare allow/deny.\n\nThe org comes from the gateway-minted X-Org-Id and picks the per-org enforcer, so a decision is always rendered by that tenant's policies and never by another's. A request carrying no org is refused rather than answered from a shared or default set: collapsing tenants together is the one failure a policy engine must not have.\n\nBody: {sub, obj, act}, all three required. The reply echoes them beside `allow` so a cached or logged decision carries the question it answered.","tags":["authz"],"x-app":"authz","x-public":true}},"/v1/authz/health":{"get":{"operationId":"get_authz_health","summary":"Liveness of the policy engine","description":"Reports that the authz process is up. Unauthenticated by design and never org-scoped: it answers while every tenant's enforcer is still cold, because a probe that needed a tenant would fail for reasons that have nothing to do with the process being alive.","tags":["authz"],"x-app":"authz","x-public":true}},"/v1/authz/readyz":{"get":{"operationId":"get_authz_readyz","summary":"Readiness of the policy engine","description":"Reports that the authz process is ready to serve decisions. Unauthenticated and not org-scoped, for the same reason health is: readiness is a property of this process, not of any one tenant's policy set.","tags":["authz"],"x-app":"authz","x-public":true}},"/v1/auto/automations":{"get":{"operationId":"get_auto_automations","summary":"Returns your automations — another member's are never listed.","description":"Returns your automations — another member's are never listed.\n`q` keeps those whose name or instructions contain it, ignoring case; `source`\nkeeps those made in one product; `sort` is `updated` (the default, newest\nfirst), `name`, or `next` (soonest first, unscheduled last).","tags":["auto"],"parameters":[{"name":"q","in":"query","required":false,"description":"Q keeps the automations whose name or instructions contain it, ignoring case.","schema":{"type":"string"}},{"name":"sort","in":"query","required":false,"description":"Sort is name, next or updated (the default, newest first).","schema":{"type":"string"}},{"name":"source","in":"query","required":false,"description":"Source keeps the automations made in one product: chat, dev, studio or workflow.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.automationPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true},"post":{"operationId":"post_auto_automations","summary":"Creates an automation and arms its schedule.","description":"Creates an automation and arms its schedule. It runs as the\ncaller: their Dev run, in this org, each time it fires. `name` and\n`instructions` are required; no `schedule` runs it only on demand, no\n`permissions` is ask: it proposes what it would do and changes nothing, and\n`enabled: false` creates it off, its schedule unarmed.","tags":["auto"],"requestBody":{"content":{"application/json":{"example":{"instructions":"What needs my attention today across calendar, email and messages.","name":"Daily briefing","notify":true,"permissions":"ask","schedule":{"at":"08:00","kind":"weekdays","tz":"America/Los_Angeles"}},"schema":{"$ref":"#/components/schemas/auto.automationIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.Automation"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true}},"/v1/auto/automations/{id}":{"delete":{"operationId":"delete_auto_automations_by_id","summary":"Deletes an automation, its schedule and its run history, and stops a Dev run it has going.","description":"Deletes an automation, its schedule and its run history, and\nstops a Dev run it has going. It answers no content.","tags":["auto"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the automation, from the path.","schema":{"type":"string"},"example":"flow_1"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true},"get":{"operationId":"get_auto_automations_by_id","summary":"Returns one automation.","description":"Returns one automation. A flow of the org that is not an\nautomation, and anything of another org, answers not-found.","tags":["auto"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the automation, from the path.","schema":{"type":"string"},"example":"flow_1"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.Automation"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true},"patch":{"operationId":"patch_auto_automations_by_id","summary":"Changes an automation, for the person it runs as: any field it was created with, and `enabled`, which arms or disarms its schedule.","description":"Changes an automation, for the person it runs as: any field\nit was created with, and\n`enabled`, which arms or disarms its schedule. A field the request omits is\nleft alone; `project` or `model` sent as null (or \"\") clears it. Any change\nbut `enabled` makes the caller the person it runs as from then on. A draft is\nfinished by saving its `instructions`: it becomes an automation in place, on\nunless `enabled` says otherwise.","tags":["auto"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the automation, from the path.","schema":{"type":"string"},"example":"flow_1"}],"requestBody":{"content":{"application/json":{"example":{"id":"flow_1","schedule":{"at":"16:00","day":"fri","kind":"weekly","tz":"Europe/London"}},"schema":{"$ref":"#/components/schemas/auto.automationPatch"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.Automation"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true}},"/v1/auto/automations/{id}/run":{"post":{"operationId":"post_auto_automations_by_id_run","summary":"Starts one run now, whether or not its schedule is armed.","description":"Starts one run now, whether or not its schedule is armed. Only\nthe person it runs as may start one; who did is kept. An\nautomation runs one at a time: while a run is going, this records a skipped\nstart and answers it. Every run first asks IAM whether the person it runs as\nis still a member of the org; one who is not makes the run refused and turns\nthe automation off.","tags":["auto"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the automation, from the path.","schema":{"type":"string"},"example":"flow_1"}],"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.runStarted"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true}},"/v1/auto/automations/{id}/runs":{"get":{"operationId":"get_auto_automations_by_id_runs","summary":"Returns one automation's runs, newest first, to the person it runs as.","description":"Returns one automation's runs, newest first, to the person\nit runs as. Each links the\nDev run it started as `transcript`. The optional `limit` bounds the page.","tags":["auto"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the automation, from the path.","schema":{"type":"string"},"example":"flow_1"},{"name":"limit","in":"query","required":false,"description":"Limit bounds the page (default 200, maximum 1000).","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.automationRunPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true}},"/v1/auto/automations/{id}/runs/{run}/review":{"post":{"operationId":"post_auto_automations_by_id_runs_by_run_review","summary":"Answers a run that holds a post for review, for the person the automation runs as: `post` true posts it to the automation's accounts and answers the run while it posts; false discards it.","description":"Answers a run that holds a post for review, for the person the\nautomation runs as: `post` true posts it to the\nautomation's accounts and answers the run while it posts; false discards it.\nA run not in review answers 409; one held longer than a day is not posted.","tags":["auto"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the automation, and Run its run in review, from the path.","schema":{"type":"string"},"example":"flow_1"},{"name":"run","in":"path","required":true,"schema":{"type":"string"},"example":"run_1"}],"requestBody":{"content":{"application/json":{"example":{"id":"flow_1","post":true,"run":"run_1"},"schema":{"$ref":"#/components/schemas/auto.reviewIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.AutomationRun"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true}},"/v1/auto/cron":{"post":{"operationId":"post_auto_cron","summary":"Reads a schedule said in words — \"every 5 minutes\", \"weekdays at 8:30\", \"every monday at 9am\", \"tomorrow at 7pm\", \"in 20 minutes\", or a five-field cron expression — in your time zone, and answers the schedule an automation takes, said back in plain words, with when it would first run.","description":"Reads a schedule said in words — \"every 5 minutes\", \"weekdays at 8:30\",\n\"every monday at 9am\", \"tomorrow at 7pm\", \"in 20 minutes\", or a five-field\ncron expression — in your time zone, and answers the schedule an automation\ntakes, said back in plain words, with when it would first run. Nothing is\ncreated: send the schedule to POST /v1/auto/automations. A phrase that no rule\nreads is read by a model; a phrase that names no schedule answers 422.","tags":["auto"],"requestBody":{"content":{"application/json":{"example":{"text":"every monday at 9am","tz":"America/Los_Angeles"},"schema":{"$ref":"#/components/schemas/auto.whenIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.whenOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true}},"/v1/auto/events":{"get":{"operationId":"get_auto_events","summary":"Stream your jobs and automations as they change, as Server-Sent Events","description":"Holds one text/event-stream open and writes a frame each time one of your jobs or automations changes: `event: job` with the job as GET /v1/auto/jobs/{id} answers it, and `event: automation` with the automation as GET /v1/auto/automations/{id} answers it. Only your own rows are sent; another member's never are. Authenticate with `Authorization: Bearer` — a fetch-based reader, since a browser EventSource cannot set it. A `: ping` comment is written every 15 seconds, and the server closes the stream after 15 minutes; reconnect and re-read the lists. Frames carry no `id`: the lists are the truth, and the stream is a live hint over them.","tags":["auto"],"responses":{"2XX":{"content":{"text/event-stream":{"schema":{"format":"binary","type":"string"}}},"description":"Success"}},"x-app":"auto","x-public":true}},"/v1/auto/flows":{"get":{"operationId":"get_auto_flows","summary":"Returns the caller org's automations, most-recently-updated first.","description":"Returns the caller org's automations, most-recently-updated first. The\noptional `limit` query bounds the page.","tags":["auto"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit bounds the page (default 200, maximum 1000).","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.flowPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true},"post":{"operationId":"post_auto_flows","summary":"Creates an automation and its initial DRAFT version in one call.","description":"Creates an automation and its initial DRAFT version in one call. The\nnew flow is DISABLED — creating it does not arm its trigger; POST\n/v1/auto/flows/{id}/enable does that.","tags":["auto"],"requestBody":{"content":{"application/json":{"example":{"displayName":"Nightly Sync","trigger":{"displayName":"Start","name":"trigger","settings":{"pieceName":"core","triggerName":"manual"},"strategy":"MANUAL","type":"PIECE_TRIGGER"}},"schema":{"$ref":"#/components/schemas/auto.createFlowReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.populatedFlow"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true}},"/v1/auto/flows/{id}":{"delete":{"operationId":"delete_auto_flows_by_id","summary":"Deletes one automation, its versions and its run history.","description":"Deletes one automation, its versions and its run history. It answers\nno content, and a flow of another org answers not-found.","tags":["auto"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the flow to act on, from the path.","schema":{"type":"string"},"example":"flow_1"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true},"get":{"operationId":"get_auto_flows_by_id","summary":"Returns one automation and its latest version.","description":"Returns one automation and its latest version. That is the flow record\nplus the step tree the builder edits; a flow of another org answers not-found.","tags":["auto"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the flow to act on, from the path.","schema":{"type":"string"},"example":"flow_1"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.populatedFlow"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true},"patch":{"operationId":"patch_auto_flows_by_id","summary":"Updates one automation's metadata in place.","description":"Updates one automation's metadata in place. Every field is optional; a\nfield the request omits is left alone. Publishing a version pins which one runs,\nand is refused unless that version belongs to this flow.","tags":["auto"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the flow to update, from the path.","schema":{"type":"string"},"example":"flow_1"}],"requestBody":{"content":{"application/json":{"example":{"folderId":"ops","id":"flow_1"},"schema":{"$ref":"#/components/schemas/auto.patchFlowIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.Flow"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true}},"/v1/auto/flows/{id}/disable":{"post":{"operationId":"post_auto_flows_by_id_disable","summary":"Disarms a flow's trigger and marks it DISABLED.","description":"Disarms a flow's trigger and marks it DISABLED. Its schedule and its\nevent subscriptions are dropped, so a disabled flow is never a live target; runs\nalready in flight are unaffected, and it can still be started on demand.","tags":["auto"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the flow to act on, from the path.","schema":{"type":"string"},"example":"flow_1"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.Flow"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true}},"/v1/auto/flows/{id}/enable":{"post":{"operationId":"post_auto_flows_by_id_enable","summary":"Arms a flow's trigger and marks it ENABLED.","description":"Arms a flow's trigger and marks it ENABLED. A POLLING trigger gets a\ncron schedule on the durable engine; a WEBHOOK trigger gets a subscription in the\nrouting index, so an inbound event starts it; a MANUAL trigger arms nothing and\nstill runs on demand.","tags":["auto"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the flow to act on, from the path.","schema":{"type":"string"},"example":"flow_1"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.Flow"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true}},"/v1/auto/flows/{id}/operations":{"post":{"operationId":"post_auto_flows_by_id_operations","summary":"Edit a flow — rename it, retarget its trigger, or add, move and delete steps","description":"Applies ONE flow operation and answers the thing it changed. The operation is named by `type`, with its arguments under `request`: `CHANGE_NAME`, `UPDATE_TRIGGER`, `ADD_ACTION`, `UPDATE_ACTION`, `MOVE_ACTION`, `DELETE_ACTION` edit the flow's LATEST version and answer with that version, and `CHANGE_STATUS` instead enables or disables the flow and answers with the FLOW. Two response shapes on one address is the rule a reader would otherwise get wrong, and it is why this route is not a typed op.\n\nEdits land on the latest version only — the published version a run executes is untouched until it is republished — and the whole resulting step tree is re-validated against the step-count and size caps after every operation, so a long sequence of `ADD_ACTION` calls cannot grow a flow past a bound one step at a time (422 when it would). Org-scoped and fails closed: a validated principal is required (401 without one), the flow and its version are read under the caller's OWN org so another tenant's id is a 404, and an operation whose `request` does not decode is a 400.","tags":["auto"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"auto","x-public":true}},"/v1/auto/flows/{id}/run":{"post":{"operationId":"post_auto_flows_by_id_run","summary":"Starts one durable run of a flow now.","description":"Starts one durable run of a flow now. It runs the flow's published\nversion if one is pinned, else its latest, and answers the run record it created.\nThe run is bounded by the org's per-minute run-start budget and its in-flight\nconcurrency ceiling; over either, or with the engine not ready, no run is started\nand no run id is burned.","tags":["auto"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the flow to act on, from the path.","schema":{"type":"string"},"example":"flow_1"}],"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.FlowRun"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true}},"/v1/auto/flows/{id}/versions":{"get":{"operationId":"get_auto_flows_by_id_versions","summary":"Returns one flow's versions, newest first.","description":"Returns one flow's versions, newest first. The optional `limit`\nquery bounds the page.","tags":["auto"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the flow whose versions to list, from the path.","schema":{"type":"string"},"example":"flow_1"},{"name":"limit","in":"query","required":false,"description":"Limit bounds the page (default 200, maximum 1000).","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.versionPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true},"post":{"operationId":"post_auto_flows_by_id_versions","summary":"Adds a new DRAFT version to a flow.","description":"Adds a new DRAFT version to a flow. The version is created invalid\nunless it carries a trigger, and it does not become the running version until it\nis published (PATCH the flow's publishedVersionId) or becomes the latest.","tags":["auto"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the flow to add a version to, from the path.","schema":{"type":"string"},"example":"flow_1"}],"requestBody":{"content":{"application/json":{"example":{"displayName":"v2","id":"flow_1"},"schema":{"$ref":"#/components/schemas/auto.createVersionIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.FlowVersion"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true}},"/v1/auto/hooks/{source}/{event}":{"post":{"operationId":"post_auto_hooks_by_source_by_event","summary":"Fire an event that starts every enabled flow subscribed to it","description":"Delivers one event to the org's automation triggers and answers `{matched:n}` — how many enabled flows had a webhook trigger on this `(source, event)` key and were started by it. A zero match is a success, not an error: nothing was subscribed.\n\nThe path is the trigger key and the JSON object body is the event payload, threaded into each started run as `{{trigger.*}}` with all of its keys intact — which is why this is not a typed op, since a declared input struct would silently DISCARD every payload key it had no field for. Re-delivery is a no-op: an `X-Idempotency-Key` header dedupes, and with none the body is content-hashed instead, so a hammer of identical posts collapses to ONE run rather than minting a fresh one per post. An in-platform producer may propagate `X-Causation-Depth` so a firing that a flow caused is bounded against a loop; an absent or invalid header reads as depth 0, an external origin.\n\nAuthenticated and org-scoped, unlike a provider's public webhook URL: a validated principal is required (401 without one) and the org is that principal's, never the body's, so a producer can only fire into its own tenant's flows. Both path segments are required (400) and a payload over the size limit is a 413.","tags":["auto"],"parameters":[{"name":"source","in":"path","required":true,"schema":{"type":"string"}},{"name":"event","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"auto","x-public":true}},"/v1/auto/jobs":{"get":{"operationId":"get_auto_jobs","summary":"Lists everything of yours that runs without you watching, across every product: each run of your automations and workflows, and every Studio render, long video or other background run a product recorded for you.","description":"Lists everything of yours that runs without you watching, across\nevery product: each run of your automations and workflows, and every Studio\nrender, long video or other background run a product recorded for you. Each\nis in one of five states — scheduled, running, succeeded, failed, cancelled —\nwith what it made (Library item ids) and what it cost when that is known.\nAnother member's jobs are never listed.","tags":["auto"],"parameters":[{"name":"product","in":"query","required":false,"description":"Product keeps one product's jobs: chat, dev, studio or workflow.","schema":{"type":"string"},"example":"studio"},{"name":"state","in":"query","required":false,"description":"State keeps one state: scheduled, running, succeeded, failed or cancelled.","schema":{"type":"string"},"example":"running"},{"name":"limit","in":"query","required":false,"description":"Limit bounds the page (default 100, at most 500).","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.jobPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true}},"/v1/auto/jobs/{id}":{"get":{"operationId":"get_auto_jobs_by_id","summary":"Reads one of your jobs.","description":"Reads one of your jobs. A job that is not yours answers 404, as one that\ndoes not exist.","tags":["auto"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the job, from the path: a run_ or a job_ id.","schema":{"type":"string"},"example":"run_3f7a…"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.Job"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true}},"/v1/auto/provider":{"get":{"operationId":"get_auto_provider","summary":"Returns the connector catalogue.","description":"Returns the connector catalogue. Each entry is an external service a\nflow step can invoke, carrying its auth descriptor and the input properties of its\nactions and triggers. The catalogue is the same for every tenant, so the gate is a\nvalidated principal rather than a per-org view.","tags":["auto"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.Catalog"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true}},"/v1/auto/provider/{id}/run":{"post":{"operationId":"post_auto_provider_by_id_run","summary":"Executes one provider action in-process and answers the outcome.","description":"Executes one provider action in-process and answers the outcome. The\ncaller's resolved credential travels in `auth`, delivered to the action\nverbatim — the runtime resolves no credential itself. An action that ran and\nfailed (or an action name the provider does not have) answers ok:false with\nthe failure message, not an HTTP error; an unknown provider is 404 and a\nmissing action 422.","tags":["auto"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the provider to run, from the path.","schema":{"type":"string"},"example":"notion"}],"requestBody":{"content":{"application/json":{"example":{"action":"create_page","auth":"secret-token","id":"notion","props":{"title":"Hello"}},"schema":{"$ref":"#/components/schemas/auto.runIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.runResp"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true}},"/v1/auto/runs":{"get":{"operationId":"get_auto_runs","summary":"Returns your run history, newest first: the runs of the flows you hold.","description":"Returns your run history, newest first: the runs of the flows you\nhold. The optional `flowId` query narrows it to one of them and `limit` bounds\nthe page.","tags":["auto"],"parameters":[{"name":"flowId","in":"query","required":false,"description":"FlowID narrows the history to one flow. Omit it for the whole org's runs.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit bounds the page (default 200, maximum 1000).","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.runPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true}},"/v1/auto/runs/{id}":{"get":{"operationId":"get_auto_runs_by_id","summary":"Returns one run.","description":"Returns one run. A run that has not reached a terminal status is refreshed\nfrom the durable engine first — scoped to the org's own namespace — so the caller\nsees live progress rather than the last status that happened to be persisted.","tags":["auto"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the run to read, from the path.","schema":{"type":"string"},"example":"run_1"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.FlowRun"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true}},"/v1/auto/runs/{id}/resume":{"post":{"operationId":"post_auto_runs_by_id_resume","summary":"Release a run waiting at an approval step, with the approval payload","description":"Delivers the durable `resume` signal to a run parked on a `wait_for_approval` waitpoint and answers `{resumed:true}` once the engine has taken it.\n\nThe body is an ARBITRARY JSON value — object, array, string, number — delivered VERBATIM into the workflow as that waitpoint's output, so it is what the steps after the approval read as their input. An empty body resumes with no payload. That open shape is why this route is not a typed op: an operation's input can carry the payload or the run address, never both.\n\nOrg-scoped and fails closed: a validated principal is required (401 without one), the run is read under the caller's OWN org so another tenant's run id is a 404, a body that is not JSON is a 400, and a payload over the size limit is a 413 — it becomes durable engine state, so it is bounded here rather than after it lands. The resume is audited as `automations.run.resume`.","tags":["auto"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"auto","x-public":true}},"/v1/auto/templates":{"get":{"operationId":"get_auto_templates","summary":"Returns the starter automations: a name, what it does, the instructions it runs and the schedule it suggests, in the caller's own zone.","description":"Returns the starter automations: a name, what it does, the\ninstructions it runs and the schedule it suggests, in the caller's own zone.","tags":["auto"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auto.starterPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"auto","x-public":true,"x-tool":true}},"/v1/base/bases":{"get":{"operationId":"get_base_bases","summary":"Lists every Base the caller can reach, one per org their token carries.","description":"Lists every Base the caller can reach, one per org their token carries.\n\nThe orgs come from IAM's signed membership set, so the list is exactly the\norgs the caller is a member of and cannot be widened by asking. It is the\naccount-wide view: a Base is per org, so this is one entry per org and there\nis nothing to page.\n\nA caller with no membership set — a machine credential, an API key — reaches\nno Base and receives an empty list rather than a refusal, because holding no\nmembership is an answer and not a failure.","tags":["base"],"responses":{"200":{"content":{"application/json":{"example":[{"bytes":430080,"exists":true,"org":"hanzo"}],"schema":{"items":{"$ref":"#/components/schemas/base.baseView"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"base","x-public":true,"x-tool":true}},"/v1/base/bases/{org}":{"get":{"operationId":"get_base_bases_by_org","summary":"Describes ONE org's Base — whether its store exists, and what it occupies.","description":"Describes ONE org's Base — whether its store exists, and what it occupies.\n\nThe org must be one the caller's token carries; any other is not found, so\nthis cannot be used to learn which orgs exist. That check is the same\nmembership set the listing is built from, which is why the two can never\ndisagree about what a caller may see.","tags":["base"],"parameters":[{"name":"org","in":"path","required":true,"description":"Org is the org whose Base to describe, from the path. An org the caller's\ntoken does not carry is not found — the same answer a nonexistent one\ngets, so the listing cannot be used to discover which orgs exist.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"bytes":430080,"exists":true,"org":"hanzo"},"schema":{"$ref":"#/components/schemas/base.baseView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"base","x-public":true,"x-tool":true}},"/v1/base/graphql":{"get":{"operationId":"get_base_graphql","summary":"Read your org Base's GraphQL schema","description":"The schema of the caller's org Base as GraphQL SDL: a type per collection with its fields, relations and the records pointing at it, a filter input per collection, orderBy, connections, aggregates and the writes. It is that org's own, so it changes with its collections. /v1/graphql carries the same schema under `base`.","tags":["base"],"x-app":"base","x-public":true},"post":{"operationId":"post_base_graphql","summary":"Query or write your org Base with GraphQL","description":"Runs one GraphQL request against the caller's org Base. Every field is answered by the Base's own record, aggregate and history routes as the caller, so what a field reads or writes is what the same request over /v1/base/collections may. No subscriptions: realtime is /v1/base/realtime.","tags":["base"],"x-app":"base","x-public":true}},"/v1/base/health":{"get":{"operationId":"get_base_health","summary":"Reports that the base subsystem is serving.","description":"Reports that the base subsystem is serving.\n\nIt is deliberately INDEPENDENT of whether this deployment actually embeds the\nBase engine: the route answers before the CLOUD_BASE_EMBED gate and before the\n/v1/base/* wildcard, so a liveness probe measures the process rather than an\noptional feature, and the wildcard can never shadow it. It reads no tenant, so a\nprober that sends no principal is answered rather than refused.","tags":["base"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/base.baseHealth"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"base","x-public":true,"x-tool":true}},"/v1/benchmark/catalog":{"get":{"operationId":"get_benchmark_catalog","summary":"Is the canonical benchmarks this arena reads — the id, title, axis, item count, upstream source and direction of each, with native marking the ones the standardized harness runs today.","description":"Is the canonical benchmarks this arena reads — the id, title, axis, item\ncount, upstream source and direction of each, with native marking the ones the\nstandardized harness runs today. The first 14 are the public set every major\nprovider reports; the next 4 are the tests coding agents are judged on —\nDeepSWE, Terminal-Bench 4.0, SWE-Atlas QnA and SWE-Bench Pro v2 — published as\nclaims; the rest are the Decision Suite, scored by Kai's own harness and\npublished as claims citing the research run each number came from.\n\ndirection is \"higher\" or \"lower\": which way a score improves, and so which way\nthe leaderboard orders its rows. Every score is a percentage; a latency is a\nfact about serving and lives in the research plane's runs, not here.\n\nThese ids are the vocabulary the rest of the surface takes: a run and a claim\nname them, and the leaderboard and compare read them from ?benchmark=. The\ncatalog is deployment-wide and identical for every caller — there is no tenant\nin it.","tags":["benchmark"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/benchmark.benchmarkCatalog"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"benchmark","x-public":true,"x-tool":true}},"/v1/benchmark/claims":{"get":{"operationId":"get_benchmark_claims","summary":"Lists the effective claims the caller may read, each labelled with the org that made it and the user who recorded it.","description":"Lists the effective claims the caller may read, each labelled with the\norg that made it and the user who recorded it.\n\nAnyone reads the public claims. A signed-in caller also reads its own org's\nprivate ones. No caller reads another org's private claims — a SuperAdmin\nacting in that org included, since acting in an org is not membership of it.\nRows under org \"admin\" are the platform's own curated readings: the compiled\nseed and any correction a SuperAdmin wrote.\n\nEffective values only. The history of a key lives in the append-only file and\nis not what this op is for; a list that returned every superseded row would\nmake the common question the hard one.","tags":["benchmark"],"parameters":[{"name":"Benchmark","in":"query","required":false,"description":"Benchmark filters to one benchmark id. Empty returns every benchmark.","schema":{"type":"string"}},{"name":"Model","in":"query","required":false,"description":"Model filters to one model. Empty returns every model.","schema":{"type":"string"}},{"name":"Provider","in":"query","required":false,"description":"Provider filters to one lab or leaderboard — the way to read what a single\nsource claims across every model it covers.","schema":{"type":"string"}},{"name":"Source","in":"query","required":false,"description":"Source filters to one citation, which is the finest grain there is: a\nsource is what makes two claims about one model independent rather than a\nrestatement of each other.","schema":{"type":"string"}},{"name":"Protocol","in":"query","required":false,"description":"Protocol filters by HOW a claim was scored, so provider cards can be read\napart from third parties running their own harness.","schema":{"type":"string"}},{"name":"Org","in":"query","required":false,"description":"Org filters to the claims one org made; \"admin\" reads the platform's own.\nIt narrows what the caller may already read and never widens it.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/benchmark.claimsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"benchmark","x-public":true,"x-tool":true},"post":{"operationId":"post_benchmark_claims","summary":"Records claims for the caller's org: one to correct a number, many to import a leaderboard.","description":"Records claims for the caller's org: one to correct a number, many to\nimport a leaderboard. Any signed-in caller may write; a caller with no verified\nprincipal is refused 401.\n\nThe org and the author are the verified caller's. Nothing in the body names\neither, and a body that tries is not read. Claims are private to that org unless\nvisibility is \"public\". Writing as org \"admin\" curates the leaderboard, so it\ntakes a SuperAdmin; anyone else acting there is refused 403, and the refusal is\naudited.\n\nEvery row must carry a Source, because a claim without its citation is a\nnumber nobody can check, and a benchmark id from /catalog, because an unknown\nid would sit in the store invisible to every read. A row names its benchmark,\nmodel, provider and protocol in at most 128 characters each, cites a source of\nat most 2048 bytes, and scores a percentage from 0 to 100; a row outside that is\nrejected by number.\n\nA request carries at most 500 rows in at most 1 MiB (413 past either), and an\norg writes at most 2000 rows per UTC day (429 past that, and nothing from the\nrequest is written).\n\nThe trail takes the call's intent, naming every row, BEFORE the first row\nlands; a trail that cannot take it answers 503 and nothing is written. A second\nrecord then names which rows were stored and which failed.\n\nWrites are append-only, so this never destroys the value it replaces. A\nvendor restating a score leaves both rows on disk, which is how the restating\nitself becomes visible.","tags":["benchmark"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/benchmark.putClaimsIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/benchmark.putClaimsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"benchmark","x-public":true,"x-tool":true}},"/v1/benchmark/compare":{"get":{"operationId":"get_benchmark_compare","summary":"Is the ONLY valid arm-vs-arm test: it pairs the two models on the items BOTH completed, and answers rescue and damage counts with an exact-McNemar p.","description":"Is the ONLY valid arm-vs-arm test: it pairs the two models on the items\nBOTH completed, and answers rescue and damage counts with an exact-McNemar p.\n\nPairing is what prevents the subset artifact — comparing one model's easy subset\nagainst another's full run — so n_common, not either arm's own coverage, is the\nnumber to read this by.\n\nBoth a and b are required. The benchmark defaults to gpqa_diamond.","tags":["benchmark"],"parameters":[{"name":"benchmark","in":"query","required":false,"description":"Benchmark is the catalog id to compare on, defaulting to gpqa_diamond.","schema":{"type":"string"}},{"name":"a","in":"query","required":true,"description":"A is the first model id. It is required.","schema":{"type":"string"}},{"name":"b","in":"query","required":true,"description":"B is the second model id. It is required.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/benchmark.pairing"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"benchmark","x-public":true,"x-tool":true}},"/v1/benchmark/history":{"get":{"operationId":"get_benchmark_history","summary":"Returns each model's measured score per run over time, oldest first, with the change between runs.","description":"Returns each model's measured score per run over time, oldest first,\nwith the change between runs.\n\nThis is the counterweight to a leaderboard: the board shows the latest run\nbecause that is what \"how good is it\" means, and a single latest number cannot\ndistinguish a model that has always been strong from one that just improved,\nor from one that regressed after a provider changed something. Both matter for\nrouting, and only one of them is visible on a board.\n\nRuns with no id — attempts recorded before runs existed — group under the\nempty run, which is honestly what they are: one undated measurement.","tags":["benchmark"],"parameters":[{"name":"Benchmark","in":"query","required":false,"description":"Benchmark is the catalog id to read, defaulting to gpqa_diamond.","schema":{"type":"string"}},{"name":"Model","in":"query","required":false,"description":"Model filters to one model. Empty returns every model measured.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/benchmark.historyOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"benchmark","x-public":true,"x-tool":true}},"/v1/benchmark/leaderboard":{"get":{"operationId":"get_benchmark_leaderboard","summary":"Answers one row per model for the benchmark named — what our own harness measured, beside what the vendor claims, and the gap between them.","description":"Answers one row per model for the benchmark named — what our own\nharness measured, beside what the vendor claims, and the gap between them.\n\nThe gap is the point of the arena; provider-reported claims have run materially\nhot against one standardized harness.\n\nThe two planes are NEVER blended, and that is the rule to read the rows by: a\nmodel we have measured but no vendor has claimed for shows published null, a\nmodel with only a claim shows measured null, and gap exists only where both do.\n\nPublished, Claims, Spread and Mean read the platform's own public claims (org\n\"admin\") and nothing else, whoever asks. Other orgs' claims are at\n/v1/benchmark/claims, labelled, and reach this board only when a SuperAdmin\npublishes them: writing under org admin, or promoting an org's public claims\nwith POST /v1/benchmark/claims/promote, which keeps the org they came from in\nthe row's from.\n\nRows are best first. A benchmark whose score improves downward — a false-alarm\nrate, a share of answers that moved — is ordered lowest first, and the answer\nsays which with direction.\n\nn is coverage and is not decoration: two measured numbers taken over different\nitem counts are not comparable, so read the row's n before reading its accuracy.","tags":["benchmark"],"parameters":[{"name":"benchmark","in":"query","required":false,"description":"Benchmark is the catalog id to read, defaulting to gpqa_diamond.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/benchmark.leaderboard"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"benchmark","x-public":true,"x-tool":true}},"/v1/benchmark/presets":{"get":{"operationId":"get_benchmark_presets","summary":"Are the router blends available to compose from — a named set of model arms, the rank they escalate through and the panel width that bounds fan-out — each named for the model layer as enso-\u003cname\u003e.","description":"Are the router blends available to compose from — a named set of model\narms, the rank they escalate through and the panel width that bounds fan-out —\neach named for the model layer as enso-\u003cname\u003e.\n\nThe first row is the reference blend: a worked example written in models we\nname, published as an example of the FORM. It is deliberately not the\ncomposition of a Hanzo-served tier — the tier name exists to abstract that — so\nfork it and swap arms by what the leaderboard measures on your own tasks rather\nthan reading it as a disclosure.\n\nThe rows after it are the caller's org's stored blends, by name, the latest\nversion of each. Anyone reads the reference; only a member of the org reads the\norg's own, and a SuperAdmin acting in an org it does not belong to reads what a\nstranger reads.","tags":["benchmark"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/benchmark.presetList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"benchmark","x-public":true,"x-tool":true},"post":{"operationId":"post_benchmark_presets","summary":"Stores a router blend for the caller's org — its name, its arms, the rank they escalate through and the panel fan-out width — and answers with the stored blend and the enso-\u003cname\u003e it would be resolved under.","description":"Stores a router blend for the caller's org — its name, its arms, the\nrank they escalate through and the panel fan-out width — and answers with the\nstored blend and the enso-\u003cname\u003e it would be resolved under.\n\nStoring is not serving: the model layer resolves no stored preset, and the\nanswer's note says so.\n\nAny signed-in caller may compose; a caller with no verified principal is refused\n401. Owner, At and By are the server's, whatever the body says, so a blend is\nnever stored as another org's. Posting a name the org already holds replaces\nthat blend; an org holds at most 100 names and stores at most 500 versions per\nUTC day (429 past that).\n\nDefaults fill the shape rather than refusing it: an omitted rank becomes the arms\nin declared order and a panel below 1 becomes 1. A blend with no name or no arms\nis a 400. A name is the part after enso-: 1 to 64 lowercase letters, digits and\ninner hyphens, never one of Hanzo's own tiers (auto, flash, pro, ultra, free,\nembed) and never beginning with enso-, or it is a 422. So is a blend of more\nthan 32 arms, an arm named twice or past 128 characters, a rank naming an arm\nthe blend does not declare, a panel wider than the rank, or a note past 1024\ncharacters.","tags":["benchmark"],"requestBody":{"content":{"application/json":{"example":{"arms":["enso-ultra","zen5-pro"],"name":"research","panel":2},"schema":{"$ref":"#/components/schemas/benchmark.Preset"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/benchmark.presetStored"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"benchmark","x-public":true,"x-tool":true}},"/v1/benchmark/runs":{"post":{"operationId":"post_benchmark_runs","summary":"Answers what the arena already holds for a model on each benchmark asked about, and spends nothing.","description":"Answers what the arena already holds for a model on each benchmark asked\nabout, and spends nothing.\n\nFor a benchmark the store holds attempts for, the answer is the model's latest\nrun — its id, when it was recorded, its accuracy and how many items it covered\n— served from the attempts already recorded. A measurement held is never run\nagain from here.\n\nFor a benchmark it holds none for, nothing is queued, because this arena has\nno executor: the answer says so and names the harness that measures the\nbenchmark, or, where none here does, the import a published run's items take.\nThere is no flag to force a run, because nothing here would act on it.\n\nAny signed-in caller may ask; a caller with no verified principal is refused\n401. The answer names the caller's verified org and user — nothing in the\nbody names either — and stores nothing.\n\nValidation is up front and total — a request with no model is a 400, one with\nno benchmarks is a 400, and any benchmark id outside the catalog is a 422\nnaming exactly which ids were unknown.","tags":["benchmark"],"requestBody":{"content":{"application/json":{"example":{"benchmarks":["gpqa_diamond"],"model":"grok-4.5"},"schema":{"$ref":"#/components/schemas/benchmark.suite"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/benchmark.measurements"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"benchmark","x-public":true,"x-tool":true}},"/v1/billing/accounts":{"get":{"operationId":"get_billing_accounts","summary":"Answers the caller's billing accounts: the org itself, its currency, when it was opened, and the caller's own standing in it.","description":"Answers the caller's billing accounts: the org itself, its currency, when it\nwas opened, and the caller's own standing in it.\n\nThe standing is the caller's, resolved from the validated principal here and\nsent to the store rather than looked up there — the membership roster is IAM's\nand commerce keeps none, so a callee that answered \"what role is this\" would\nbe inventing it. An anonymous read gets the account with no role rather than\nan implied membership.\n\nScoped to the caller's own org, which is the whole tenancy story: there is no\norg field on the wire and none on the input.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/billing.BillingAccount"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/accounts/{id}/members":{"get":{"operationId":"get_billing_accounts_by_id_members","summary":"Answers one billing account's roster.","description":"Answers one billing account's roster.\n\ncommerce stores no roster — that is IAM's — so the only member it can name is\nthe caller, and that is what comes back. What it does enforce is that the\naccount named in the path is the caller's own: a foreign id is 403, not an\nempty list, because \"no members\" and \"not your account\" are different answers.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the billing account id, which for this store is the org's own id.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/billing.Holder"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/alerts":{"get":{"operationId":"get_billing_alerts","summary":"Lists this org's spend caps: the ceiling, its scope, whether it enforces, and how much of it has been spent this period.","description":"Lists this org's spend caps: the ceiling, its scope, whether it enforces, and\nhow much of it has been spent this period.\n\n`periodSpentCents`, `over` and `warn` are ABSENT rather than zero when the\nspend could not be read, because \"nothing spent\" and \"spend unknown\" are\ndifferent answers and a customer acting on the first when the second is true\nwould be reading a ceiling that is not there. The policy row is reported\neither way.\n\nThe period is the UTC calendar month and `resetsAt` is when the count starts\nagain, so a surface can say \"resets on\" without a second call.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/billing.Alert"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true},"post":{"operationId":"post_billing_alerts","summary":"Opens a spend cap on the caller's own org.","description":"Opens a spend cap on the caller's own org.\n\nAt least one limit must mean something: a threshold above zero (a spend cap)\nor a requests-per-minute above zero (a rate limit). A row that bounds neither\nis refused rather than stored, because a ceiling nothing measures against is a\nceiling a customer believes in and does not have.\n\nThe cap is keyed on the caller's own billing subject, resolved server-side —\nthe SAME key the verdict looks it up under, which is what makes enforcement\nbind rather than merely record.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.AlertSpec"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Alert"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/alerts/authorize":{"get":{"operationId":"get_billing_alerts_authorize","summary":"Answers whether one proposed spend fits inside this org's caps.","description":"Answers whether one proposed spend fits inside this org's caps.\n\nIt is the per-request verdict the metering edge consumes before every priced\ncall, and its caller is a SERVICE rather than a person: the platform, stating\nthe org over the plane, with no user behind it. So this admits that principal\nwhere the CRUD beside it does not.\n\nEvery covering row is evaluated, most-restrictive-wins, and the tightest one\nis what `capCents`, `spentCents` and `reason` describe. Soft rows never deny;\nnor does a project-scoped enforcing row whose project axis the caller could\nnot establish — `pv=1` is how a caller states that it did, and an unproven\nclaim must not be able to refuse traffic.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"parameters":[{"name":"project","in":"query","required":false,"description":"Project narrows the verdict to one project's caps. Empty is the org-wide row.","schema":{"type":"string"}},{"name":"service","in":"query","required":false,"description":"Service narrows it to one service's caps. Empty is every service.","schema":{"type":"string"}},{"name":"amount","in":"query","required":false,"description":"Amount is the proposed spend in cents.","schema":{"type":"string"}},{"name":"pv","in":"query","required":false,"description":"PV is \"1\" when the caller ESTABLISHED the project rather than merely\ncarrying a claim of one. An unproven project may not deny traffic.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.CapVerdict"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/alerts/{id}":{"delete":{"operationId":"delete_billing_alerts_by_id","summary":"Removes one of the caller's spend caps and answers 204.","description":"Removes one of the caller's spend caps and answers 204.\n\nRemoving a cap RAISES what the org may spend, so it takes the same authority\nsetting one does. The caps that remain still bind: this drops one, never the\nwhole policy.","tags":["billing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the cap to remove, from the path.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true},"patch":{"operationId":"patch_billing_alerts_by_id","summary":"Changes one spend cap: raise or lower the ceiling, flip enforcement, retune the rate limit.","description":"Changes one spend cap: raise or lower the ceiling, flip enforcement, retune\nthe rate limit.\n\nOnly the fields the body carries move. Every mutable field is optional, and an\nabsent one is PRESERVED rather than reset — so a change that flips enforcement\ncannot silently wipe the threshold it enforces.\n\nA cap belonging to another org is a 404, not a 403: a guessed id must not\nbecome an oracle for what anyone else holds.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.AlertPatch"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Alert"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/balance":{"get":{"operationId":"get_billing_balance","summary":"Prepaid credit the caller's org can still spend","description":"Answers the spendable prepaid balance of the wallet this caller bills from — the same wallet the AI prepaid gate reads before admitting a paid request, the edge meter debits, and a top-up credits.\n\nThe wallet is an ADDRESS, not an org: `account` echoes the key resolved within the ledger — the org's shared pool for a tenant org, a personal account for a member of the shared signup org. The echo is the point. A browser could only GUESS its own payer by decoding its own token, and a guess that disagrees with the server is how money lands in an account the gate never reads.\n\n`balance`, `holds` and `available` are whole USD cents, ROUNDED from the ledger's exact 18-decimal value. On the co-resident ledger `holds` is 0 and `available` equals `balance`: the gate's reservations live in its own pod and are never posted, so the settled balance IS the spendable one.\n\n`cash`, `line` and `credit` say where `available` came from, and add up to it. `cash` is money the customer paid — a settled card payment or a recorded wire. `credit` is money Hanzo minted: signup and promotional credit, admin grants. `line` is what is left of the org's postpaid credit line (`creditLimit`), and `due` what the account owes on it: usage the line paid for, invoiced, and paid down first by the next payment. A debit draws cash, then the line, then credit; granted credit never pays what is due. The three line fields are absent when the ledger did not report them.\n\nThe ledger is the caller's own org, taken from the VALIDATED IAM owner claim and never from a client header. No validated principal is 401. A balance that cannot be READ is 502, never 0: unknown is not broke.","tags":["billing"],"x-app":"billing","x-public":true}},"/v1/billing/credit-balance":{"get":{"operationId":"get_billing_credit-balance","summary":"Answers what the caller can spend right now, one entry per currency.","description":"Answers what the caller can spend right now, one entry per currency.\n\nOnly ACTIVE grants count: a voided, exhausted or lapsed grant contributes\nnothing, which is why this number can be smaller than the grant list suggests\nand why the two reads exist separately. It is credit, not prepaid balance —\n/v1/billing/balance is the wallet, and the two are added by the gate, never by\na reader.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.CreditBalance"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/credit-balance/breakdown":{"get":{"operationId":"get_billing_credit-balance_breakdown","summary":"Answers that same spendable credit split by grant tag, with the earliest expiry under each and the total across all of them.","description":"Answers that same spendable credit split by grant tag, with the earliest\nexpiry under each and the total across all of them.\n\nThe split is the point: it is how trial credit is told apart from bought\ncredit, which is what a surface asks before it decides whether to spend any.\nAn unregistered address answers 404 and a caller reads that as \"no credit\", so\nthis being served is the difference between a customer with a trial grant\nbeing offered their trial and being told they have none.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/credits":{"get":{"operationId":"get_billing_credits","summary":"Lists the caller's credit grants — every one of them, spent and lapsed and voided included.","description":"Lists the caller's credit grants — every one of them, spent and lapsed and\nvoided included.\n\nThat is deliberate and it is what makes the list useful: a grant list is a\nLEDGER, and one that hid its spent rows could not be reconciled against a\nburn-down. What is spendable right now is the sibling read, /v1/billing/\ncredit-balance, and the two are different questions.\n\nScoped to the caller's own wallet, resolved server-side.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.CreditGrants"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/crypto/deposit":{"post":{"operationId":"post_billing_crypto_deposit","summary":"Issues a deposit address the caller can send crypto to, on the asset they ask for.","description":"Issues a deposit address the caller can send crypto to, on the asset they ask\nfor.\n\nThe address credits the CALLER'S own wallet and nobody else's: the payer is\nthe validated principal, never a body value. Asking again reuses the caller's\nopen intent rather than minting a second address, so a refresh cannot spray\nkey generations — and a payer who sent to the address they saw earlier is\nstill credited.\n\nNo balance moves here. The chain watcher credits on real confirmations, so\nwhat comes back is an address and a status, not a receipt.\n\nAn asset this rail cannot mint on is 400 — ask for another. A rail that is\nshut for that asset is 503 — nothing sent now can be credited.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.cryptoAsset"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.CryptoDeposit"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/crypto/deposit/{id}":{"get":{"operationId":"get_billing_crypto_deposit_by_id","summary":"Reads one of the caller's own deposit intents back — pending, confirming, or succeeded.","description":"Reads one of the caller's own deposit intents back — pending, confirming, or\nsucceeded.\n\nAn intent belonging to another payer answers 404, exactly as an id that names\nnothing, so a guessed id cannot confirm that somebody else's deposit exists.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the deposit intent id.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.CryptoDeposit"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/crypto/gateway":{"get":{"operationId":"get_billing_crypto_gateway","summary":"Answers the terms to sign a USDC top-up against, for an agent or a person paying from a wallet: the treasury to pay, the networks and USDC contracts, the EIP-712 domain and types, the limits, and a nonce issued to the caller.","description":"Answers the terms to sign a USDC top-up against, for an agent or a person\npaying from a wallet: the treasury to pay, the networks and USDC contracts,\nthe EIP-712 domain and types, the limits, and a nonce issued to the caller.\n\nSign TransferWithAuthorization {from, to: payTo, value, validAfter,\nvalidBefore, nonce} under one network's domain, then POST it here with the\nsalt. The nonce is the caller's own: a payment signed against it credits the\ncaller and cannot be presented by anyone else.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.GatewayTerms"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true},"post":{"operationId":"post_billing_crypto_gateway","summary":"Takes a signed USDC payment from the caller's Circle Gateway balance to the treasury, and answers what became of it.","description":"Takes a signed USDC payment from the caller's Circle Gateway balance to the\ntreasury, and answers what became of it.\n\naccepted: Circle Gateway LOCKED the USDC and the caller is credited — or,\nonce the caller holds $1,000 of credit Gateway has not confirmed, credited\nwhen Gateway confirms this payment (deferred). pending: the outcome is not\nknown yet; read it back or present the same payment again — it resolves to\none credit either way. A refusal is 4xx with Gateway's reason\n(insufficient_balance, invalid_signature, …) or ours (nonce_not_issued,\nrecipient_mismatch, amount_below_minimum, …); 503 means the rail is shut.\n\nWho is credited is the caller, never a body value: the payer is resolved\nserver-side, and the payment's own nonce must be the one issued to it.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.signedPayment"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.GatewayPayment"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/crypto/gateway/{id}":{"get":{"operationId":"get_billing_crypto_gateway_by_id","summary":"Reads one of the caller's own USDC top-ups back: pending, accepted (credited or deferred), settled, failed or refused.","description":"Reads one of the caller's own USDC top-ups back: pending, accepted (credited\nor deferred), settled, failed or refused.\n\nA payment belonging to another payer answers 404, exactly as an id that names\nnothing, so a guessed id cannot confirm somebody else's payment exists.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the top-up's id, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.GatewayPayment"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/crypto/options":{"get":{"operationId":"get_billing_crypto_options","summary":"Answers which chains and tokens the crypto rail accepts — what an asset picker renders.","description":"Answers which chains and tokens the crypto rail accepts — what an asset picker\nrenders.\n\nIt is the intersection of two live facts rather than a configured list: an\nasset appears only if something is WATCHING it and the custody processor\nsupports it. An address nobody watches credits nobody, so offering one would\ntake a customer's money and lose it. A rail with nothing armed answers 503,\nnot an empty menu — \"no rail\" and \"no assets\" are different, and only one of\nthem means try again later.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.CryptoOptions"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/invoices":{"get":{"operationId":"get_billing_invoices","summary":"Lists the caller's invoices, newest first, with the count beside them.","description":"Lists the caller's invoices, newest first, with the count beside them.\n\nIt is scoped to the caller's own billing subject — the wallet this request\nbills from, resolved server-side — so a query cannot widen it to another\ncustomer of the same org. An org with no invoices is an empty list, not a\nrefusal.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"parameters":[{"name":"subject","in":"query","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"subscriptionId","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"format":"int64","type":"integer"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Invoices"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true},"post":{"operationId":"raiseInvoice","summary":"Raise a draft invoice against a customer","description":"Raises a DRAFT invoice against a customer in the caller's own org. It is the\norg admin's act; a member is refused 403.\n\nThe invoice is not collectible yet: a draft exists so it can be read and\ncorrected, and issueInvoice is the separate act that turns it into a demand for\npayment. The subtotal and amount due are computed from the lines, so there is\nno total to send and none to get wrong.\n\nThe billing org is the caller's, taken from the validated principal, so an\ninvoice can only ever be raised on the caller's own books.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.RaiseIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Invoice"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/invoices/{id}":{"get":{"operationId":"getInvoice","summary":"Read one invoice","description":"Reads one invoice out of the caller's org.\n\nThe org scopes the read by construction — the store is namespaced to it — so an\nid belonging to another tenant is not found rather than found and then filtered.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the invoice id.","schema":{"type":"string"}},{"name":"brand","in":"query","required":false,"description":"Brand is the brand that bills (hanzo, lux, zoo, pars), whose mark and\naddress a rendered invoice carries. The edge sets it from the caller's\nissuer; empty is Hanzo.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Invoice"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/invoices/{id}/collect":{"post":{"operationId":"collectInvoice","summary":"Collect an issued invoice from credits, balance, then card","description":"Collects an issued invoice: credit grants first, then prepaid balance, then the\ncard on file — the same waterfall the dunning workflow runs. It spends the\nnamed customer's money, so it is the org admin's act; a member is refused 403.\n\nA DECLINE IS NOT AN ERROR. It answers with paid=false, a reason, and the\ninvoice still open, because a declined collection is a normal business outcome\nthat must remain retryable — and because sealing it as a failure would wedge\ndunning behind a replayed decline. Only a successful collection is sealed, so a\nretry of a paid invoice replays the receipt instead of charging again.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the invoice id.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.InvoiceRef"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Collected"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/invoices/{id}/issue":{"post":{"operationId":"issueInvoice","summary":"Issue a draft invoice, making it collectible","description":"Issues a draft invoice: moves it to OPEN, assigns its number, and makes it\ncollectible. It is the org admin's act; a member is refused 403.\n\nOnly a draft can be issued. An invoice already open, paid or void is refused\nwith the state machine's own reason rather than being silently re-issued, which\nwould mint a second number for one debt.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the invoice id.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.InvoiceRef"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Invoice"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/invoices/{id}/pdf":{"get":{"operationId":"get_billing_invoices_by_id_pdf","summary":"Download one invoice as a PDF","description":"Answers the invoice as an attachment — `application/pdf` under a Content-Disposition naming the invoice number — rather than as a JSON value, which is why this one route is untyped where its five siblings are typed: a PDF is bytes with a filename, and the two headers are the whole contract.\n\nThe render is a PURE function of the invoice: one page, no timestamps and no random ids, so the same invoice renders the same bytes however often it is asked for and a retry after a dropped connection costs a re-render and nothing else.\n\nThe invoice is read from the caller's own org, taken from the VALIDATED IAM owner claim and never from a client header, and the lookup is scoped at the storage layer — so an id belonging to another customer resolves to nothing and answers 404 rather than being found and then refused.","tags":["billing"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"billing","x-public":true}},"/v1/billing/invoices/{id}/void":{"post":{"operationId":"voidInvoice","summary":"Void a draft or issued invoice","description":"Voids a draft or issued invoice — the cancel. It is the org admin's act; a\nmember is refused 403.\n\nA paid invoice cannot be voided: money has moved, and the correction for that\nis a refund, not an erasure. The state machine refuses it and that refusal is\nthe answer.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the invoice id.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.InvoiceRef"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Invoice"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/ledger":{"get":{"operationId":"get_billing_ledger","summary":"Answers the org's own postings inside `range=`, each as a signed entry: a DEPOSIT CREDITS the wallet (positive, account `credits:\u003corg\u003e`), a HOLD sets money aside for a payment agreed and not yet made (negative, account `held:\u003corg\u003e`) and its return gives it back (positive), and every other posting DEBITS it (negative, account `usage:\u003corg\u003e`), described by its notes or its tags.","description":"Answers the org's own postings inside `range=`, each as a signed\nentry: a DEPOSIT CREDITS the wallet (positive, account `credits:\u003corg\u003e`), a\nHOLD sets money aside for a payment agreed and not yet made (negative, account\n`held:\u003corg\u003e`) and its return gives it back (positive), and every other posting\nDEBITS it (negative, account `usage:\u003corg\u003e`), described by its notes or its\ntags. The sign is the posting's own meaning, read through ONE\nvocabulary shared with the ledger that wrote it — a reader with its own\nspelling for `deposit` rendered a customer's grant as a charge.\n\nThis is the closest projection of the truth. The org's double-entry postings\nare the source of record — balanced, only ever appended, one file per org —\nand this lane is that list, wider than either half of it: the deposits are the\ngrants /v1/billing/credits lists and the debits are the spend /v1/billing/usage\nrolls up. It answers 503 where this deployment runs no ledger, rather than\nreporting an empty wallet.\n\nA row whose timestamp will not parse is KEPT rather than dropped — a malformed\ndate must show up in a money list, not vanish from it. `balanceCents` is\nomitted: these are MOVEMENTS, and the standing balance is /v1/billing/balance.\n\nCents are ROUNDED from the ledger's exact 18-decimal USD. Scoped to the\ncaller's own org, where the org's ledger file is the tenant boundary; 401\nwithout a validated principal.","tags":["billing"],"parameters":[{"name":"range","in":"query","required":false,"description":"Range is the window: 24h, 7d, 30d or 90d. Anything else — including\nabsent — is 30d, so a typo silently widens the window to a month rather\nthan failing.","schema":{"type":"string"},"example":"30d"}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/billing.financeLedgerEntry"},"type":"array"}}},"description":"ok","headers":{"Cache-Control":{"description":"Set by GET /v1/billing/ledger.","schema":{"type":"string"}}}},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/methods":{"get":{"operationId":"get_billing_methods","summary":"Cards and accounts on file for the caller","description":"Answers every payment method the caller has saved, newest first.\n\nA saved method is a card or account VAULTED at the processor: what is stored here is the processor's token for it plus the last four digits and the expiry a customer recognises it by, never a card number.\n\nThe list is the caller's OWN — the wallet this request bills from, resolved server-side — so a query cannot widen it to another customer of the same org.\n\n`/v1/billing/portal/methods` answers the same list under the name a hosted checkout addresses it by. One set of rows, two spellings; a card added at either is present at both.\n\nA store that cannot be read answers an EMPTY LIST rather than a failure: the saved-cards panel renders empty instead of breaking the page around it.","tags":["billing"],"x-app":"billing","x-public":true},"post":{"operationId":"post_billing_methods","summary":"Save a card or account for the caller","description":"Vaults the instrument at the processor and stores the row.\n\nA saved method is a card or account VAULTED at the processor: what is stored here is the processor's token for it plus the last four digits and the expiry a customer recognises it by, never a card number.\n\nThe list is the caller's OWN — the wallet this request bills from, resolved server-side — so a query cannot widen it to another customer of the same org.\n\n`/v1/billing/portal/methods` answers the same list under the name a hosted checkout addresses it by. One set of rows, two spellings; a card added at either is present at both.\n\nSaving a card ALREADY on file answers with the row that already holds it rather than stacking a duplicate — 200 for that, 201 for a genuinely new row, so a client can tell which happened. A card the processor declines is 402 and nothing is stored.\n\nThe org's cards are an admin's to add: a member billed from the org's account is refused 403 with a sentence naming who to ask. A member billed from a wallet of their own saves cards to that wallet.","tags":["billing"],"x-app":"billing","x-public":true}},"/v1/billing/methods/{id}":{"delete":{"operationId":"delete_billing_methods_by_id","summary":"Removes one card or account the caller has saved.","description":"Removes one card or account the caller has saved.\n\nIt detaches only the CALLER'S own — the wallet this request bills from,\nresolved server-side — so an id belonging to another customer of the same org\nis not something this operation can reach. The org's cards are removed only\nby an admin of the org or the platform; a member is refused with 403 and told\nto ask an admin. A platform or service caller\ndetaches on the subject's behalf, and that authority is decided HERE, where the\ncredential is, and travels as a value: authority decided twice is authority\nthat eventually disagrees with itself.\n\nThe card is vaulted at the processor, so what goes is our token for it.","tags":["billing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the saved method to detach, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Detachment"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/mode":{"post":{"operationId":"post_billing_mode","summary":"Moves this org between sandbox money and real money.","description":"Moves this org between sandbox money and real money.\n\nIt decides whether a charge hits a real card, so it is the one posture change\nthat is not self-service: the platform bar, never an org owner, because an org\nthat could put itself in test mode could take priced work for free.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.ModeIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Mode"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/payouts":{"get":{"operationId":"get_billing_payouts","summary":"Answers the org's outbound payouts, newest first — amount, destination, status, and the failure reason where one applies.","description":"Answers the org's outbound payouts, newest first — amount, destination,\nstatus, and the failure reason where one applies.\n\nA payout is ORG-scoped rather than subject-scoped, so there is nothing to pin\nbeyond the tenant the caller already is, and no query can widen it.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/billing.Payout"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/plans":{"get":{"operationId":"get_billing_plans","summary":"The plan catalog, priced with whatever offer is in force","description":"Answers every plan on sale — its price, what it includes, and the limits it carries — optionally narrowed to one `?category=`.\n\nThe prices are what the CHECKOUT will charge: any active promotion is applied before they leave the store, so a reader never applies a discount a second time and a quote can never disagree with the sale.\n\n`?coupon=` quotes the catalog under a plan coupon code: each paid plan it covers carries `couponCode`, `couponPercent`, `couponMonths` (how many monthly periods it discounts, from the first paid one; 1 for a first-month coupon), `couponFirstCents` (what each of those months charges under it) and `couponEnds`; every other row carries `couponError` — `unknown`, `expired`, `exhausted` or `not_applicable`. Nothing is reserved by a quote. Without the parameter the catalog is unchanged.\n\nIt is public and needs no tenant, and it is the catalog of the brand the request's host resolves to — the same brand `/v1/commerce/org` answers there. A brand that publishes no plans answers an empty list.","tags":["billing"],"x-app":"billing","x-public":true}},"/v1/billing/portal/methods":{"get":{"operationId":"get_billing_portal_methods","summary":"Cards and accounts on file for the caller","description":"Answers every payment method the caller has saved, newest first.\n\nA saved method is a card or account VAULTED at the processor: what is stored here is the processor's token for it plus the last four digits and the expiry a customer recognises it by, never a card number.\n\nThe list is the caller's OWN — the wallet this request bills from, resolved server-side — so a query cannot widen it to another customer of the same org.\n\n`/v1/billing/portal/methods` answers the same list under the name a hosted checkout addresses it by. One set of rows, two spellings; a card added at either is present at both.\n\nA store that cannot be read answers an EMPTY LIST rather than a failure: the saved-cards panel renders empty instead of breaking the page around it.","tags":["billing"],"x-app":"billing","x-public":true},"post":{"operationId":"post_billing_portal_methods","summary":"Save a card or account for the caller","description":"Vaults the instrument at the processor and stores the row.\n\nA saved method is a card or account VAULTED at the processor: what is stored here is the processor's token for it plus the last four digits and the expiry a customer recognises it by, never a card number.\n\nThe list is the caller's OWN — the wallet this request bills from, resolved server-side — so a query cannot widen it to another customer of the same org.\n\n`/v1/billing/portal/methods` answers the same list under the name a hosted checkout addresses it by. One set of rows, two spellings; a card added at either is present at both.\n\nSaving a card ALREADY on file answers with the row that already holds it rather than stacking a duplicate — 200 for that, 201 for a genuinely new row, so a client can tell which happened. A card the processor declines is 402 and nothing is stored.\n\nThe org's cards are an admin's to add: a member billed from the org's account is refused 403 with a sentence naming who to ask. A member billed from a wallet of their own saves cards to that wallet.","tags":["billing"],"x-app":"billing","x-public":true}},"/v1/billing/portal/methods/{id}":{"delete":{"operationId":"delete_billing_portal_methods_by_id","summary":"Removes one card or account the caller has saved, at the address a hosted checkout reaches it by.","description":"Removes one card or account the caller has saved, at the\naddress a hosted checkout reaches it by. One set of rows, two spellings: a card\ndetached at either is gone from both, because there is one store behind them.","tags":["billing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the saved method to detach, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Detachment"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/recharge":{"get":{"operationId":"get_billing_recharge","summary":"Reads the org's auto-reload rule: top the balance up by `amountCents` whenever it falls below `thresholdCents`, charging the card on file off-session, at most `perDay` times in a UTC day.","description":"Reads the org's auto-reload rule: top the balance up by `amountCents`\nwhenever it falls below `thresholdCents`, charging the card on file\noff-session, at most `perDay` times in a UTC day. It is the same setting every\nprepaid AI account calls auto-reload.\n\nAn org that has never set one reads as disabled with zeroes rather than as an\nerror — \"no rule\" answers the question — and `stored` is how a caller tells\nnever-configured from deliberately-off.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.AutoRecharge"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true},"put":{"operationId":"put_billing_recharge","summary":"Sets the org's auto-reload rule, and answers with the rule as stored.","description":"Sets the org's auto-reload rule, and answers with the rule as stored.\n\nONLY AN ADMIN OF THE ORG, or the platform, may (403 otherwise, with the plain\nsentence \"Only an admin of \u003corg\u003e can change its auto-reload. Ask an admin to do\nit.\"): the sweep charges the org's default card with nobody there.\n\nENABLING REQUIRES A CARD ON FILE (400), because the sweep charges off-session:\na rule naming no chargeable method is a promise the schedule cannot keep. The\namount is a top-up's own range, $5 to $5,000, and the balance it reloads below\nis $0 to $5,000; a value outside either is refused the same way, the range in\nthe sentence. The sweep reloads at most `perDay` times in a UTC day.\n\nThe rule is the org's OWN. The org comes from the validated principal and the\nbody names none, so there is no field a write could be steered through onto\nanother tenant's schedule.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.AutoRechargeEdit"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.AutoRecharge"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/recharge/run-all":{"post":{"operationId":"post_billing_recharge_run-all","summary":"Sweeps every org's auto-recharge and answers what it did.","description":"Sweeps every org's auto-recharge and answers what it did.\n\nPLATFORM AUTHORITY ONLY. It charges saved cards across every tenant, so an org\nowner reaching it could sweep-charge the estate; a caller without it is\nrefused before anything is charged.\n\nThe answer explains a sweep that charged nobody as readily as one that\ncharged: it names how many orgs were considered and how many needed charging,\nwith a row each.","tags":["billing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Recharge"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/settings":{"get":{"operationId":"get_billing_settings","summary":"Answers the PUBLIC half of this org's processor configuration — the ids a browser needs to tokenize a card, and the environment it must tokenize against.","description":"Answers the PUBLIC half of this org's processor configuration — the ids a\nbrowser needs to tokenize a card, and the environment it must tokenize\nagainst.\n\nIt carries no secret: an application id is published to every checkout page by\ndesign. What matters is that it names the SAME processor account the charge\nwill be made on, because a card vaulted against one account and charged\nagainst another is a card that saves and then cannot be used.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.PaymentConfig"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/subscribe/card":{"post":{"operationId":"post_billing_subscribe_card","summary":"Buy a plan with a card","description":"Vaults the card (or reuses one already on file), charges the plan's FIRST period at the catalog price, and opens the subscription — one act, all of it server-side.\n\nThere is NO AMOUNT in the request. `level` picks which of the plan's published prices to buy at — an index, never a number — so what the card is charged is decided by the catalog and underpaying cannot be expressed.\n\n`interval` picks the term: \"month\" (the default) or \"year\", which charges the plan's annual total now and renews yearly. A plan with no annual price refuses \"year\".\n\n`lines` are a team's other seat types, bought on the same subscription: `[{\"planId\":\"team-premium\",\"quantity\":1}]` beside `planId` \"team\" and `quantity` 1 is a team of one standard and one premium seat, charged both seats' prices. A team is at least two members across every seat type and at most 100; a line of a plan that is not a seat type of the team is 400 before any card is charged.\n\n`coupon` is a plan coupon code (case-insensitive) for a percent off the FIRST month only; renewals bill the catalog price. It is a code, never an amount. A code that is unknown, expired, used up, not for this plan, or sent with annual billing or prepaid credit is 400, and one this org or this card has already redeemed is 409 — before any card is charged, never a silent full-price sale. The receipt names the coupon and its percent.\n\n`wallet: true` says `sourceId` is a wallet's single-use token (Apple Pay, Google Pay, Cash App Pay). The first period is authorized on the wallet, any coupon is held against the org and the card behind it, and only then is the payment captured; a coupon already used by either voids the hold and is 409. Cash App Pay names no card, so a coupon with it is 400. The token is kept nowhere: renewals are drawn from the prepaid balance.\n\n`consent` is the choice the checkout page holds, as @hanzo/event spells it (\"analytics,marketing,ads\"). The sale reaches an ad platform only under it. It counts only from a browser (a request with Sec-Fetch-Site), and a browser that sends GPC or DNT has allowed nothing, whatever the page says.\n\nA fresh sale answers 201 with the receipt. An identical retry answers 200 with the FIRST sale's body, byte for byte, so a client cannot read a replay as a second subscription having been opened. A caller already on a paid plan is 409 rather than charged again.\n\nThe org's plan is bought only by an admin of the org or the platform: a member billed from the org's account is refused 403, before any card is charged, with a sentence naming who to ask. A member billed from a wallet of their own buys a plan for that wallet.","tags":["billing"],"x-app":"billing","x-public":true}},"/v1/billing/subscriptions":{"get":{"operationId":"get_billing_subscriptions","summary":"Lists the plans the caller may see, with the count beside them.","description":"Lists the plans the caller may see, with the count beside them.\n\nAn admin of the org, and the platform, see every plan the org holds, and may\nnarrow to one wallet with `userId`. A member sees the plans of the wallet they\npay from — the org's own for a member of a pooled org, their own in the shared\nsignup org — and never another member's; the card a plan renews on is left off\na row the member cannot change. A query cannot widen any of it to another\ncustomer's org. An org on nothing is an empty list, not a refusal — being on no\nplan is an answer.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Subscriptions"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/subscriptions/{id}/cancel":{"post":{"operationId":"cancelSubscription","summary":"End a subscription","description":"Ends a subscription.\n\nIt cancels at the END OF THE PAID PERIOD by default, because a customer who\ncancels has already paid for the period they are in and taking it away is\ntaking money for nothing. `atPeriodEnd: false` ends it at once, which is the\ncaller asking for that.\n\nThe org's plan is its admins' to end, and the platform's in support mode. A\nmember is refused with 403 and told to ask an admin; a member billed from a\nwallet of their own may end that wallet's plan. Every one is on the audit\ntrail, the operator named when it is the platform acting inside the org.\n\nA subscription from another org, or held by a wallet the caller may not\nchange, is not found rather than refused, so an id cannot be probed for\nexistence.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the subscription, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.subscriptionAct"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Subscription"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/subscriptions/{id}/reactivate":{"post":{"operationId":"reactivateSubscription","summary":"Put a canceled subscription back on its plan","description":"Puts a canceled subscription back on its plan.\n\nWhat asks for this is usually a recovered payment method or a support tool\nrather than a browser, which is most of the argument for it having an address\nat all. The engine decides whether the move is legal; a row it will not\nreactivate comes back with its own reason.\n\nResuming the org's plan commits its card to the next renewal, so it takes the\nauthority ending it does: an admin of the org or the platform, or a member for\na wallet of their own. A member is refused with 403 and told to ask an admin.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the subscription, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.subscriptionAct"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Subscription"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/subscriptions/{id}/resize":{"post":{"operationId":"resizeSubscription","summary":"Change a team's seats","description":"Changes a team's seats: how many standard and premium seats its next period\nopens at.\n\n`quantity` is the subscription's own seat type, 0 to keep it, and `lines` each\nother seat type: `{\"lines\":[{\"planId\":\"team-premium\",\"quantity\":1}]}` adds a\npremium seat to a team bought with standard ones. The renewal that opens the\nnext period charges the seats asked for, and the period in hand keeps the ones\nit was paid for, so nothing is charged now. A team is at least 2 seats and at\nmost 100 across every seat type; past either, or naming a plan that is not a\nseat type of the team, is 400 and nothing changes.\n\nThe team's seats are its admins' to change, and the platform's. A member is\nrefused with 403 and told to ask an admin. A subscription from another org, or\nheld by a wallet the caller may not change, is not found.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.resize"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Subscription"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/subscriptions/{id}/seats":{"put":{"operationId":"assignSeats","summary":"Assign a team's seats","description":"Assigns a team's seats: which member holds a standard seat and which a premium\none, replacing what was assigned.\n\nA seat type is given no more members than the seats of it paid for — the fewer\nof the period in hand's and the next one's — and a member holds one seat; past\neither the request is 400 and nothing changes. Which member holds a seat moves\nno money and bounds no usage: a team's usage is all of its seats' together.\n\nThe team's seats are its admins' to assign, and the platform's. A member is\nrefused with 403 and told to ask an admin. A subscription from another org, or\nheld by a wallet the caller may not change, is not found.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.assignment"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Subscription"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/tier":{"get":{"operationId":"get_billing_tier","summary":"Answers which tier the caller is on, what it allows, and what is left to spend.","description":"Answers which tier the caller is on, what it allows, and what is left to spend.\n\n`effectiveAvailable` is the ONLY figure to compare against zero. The others are\nits parts — prepaid money, granted credits and the daily term are three sources\nof one spend, not three balances to add up a second time.\n\nA tier that cannot be READ is an error, never Free. The router in front of the\nmodels maps any non-2xx to Free, so answering Free from a question nobody could\nanswer would pin every paying customer to the most restrictive row with nothing\nanywhere to find.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Tier"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/topup":{"post":{"operationId":"post_billing_topup","summary":"Charges a card the caller already saved and credits the balance.","description":"Charges a card the caller already saved and credits the\nbalance. Same receipt and the same retry safety as the token endpoint; the only\ndifference is which card, so a caller topping up from a saved method never\nre-enters one.\n\nThe org's card on file is charged only by an admin of the org or the platform;\na member is refused with 403 and told to ask an admin. A member billed from a\nwallet of their own charges that wallet's card.","tags":["billing"],"parameters":[{"name":"X-Idempotency-Key","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.topupIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Charged"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/topup/token":{"post":{"operationId":"post_billing_topup_token","summary":"Charges a single-use card token and credits the caller's balance.","description":"Charges a single-use card token and credits the caller's\nbalance.\n\nThe token comes from the payment form and is vaulted as part of the charge, so\nno card number reaches this service and none is stored here. The receipt names\nthe ledger entry, the new balance, and the PROCESSOR's own reference — which is\nthe only field that proves money moved at the gateway rather than only in our\nledger.\n\nRetry-safe on X-Idempotency-Key: the same key settles one charge and returns\nthe first receipt.","tags":["billing"],"parameters":[{"name":"X-Idempotency-Key","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.topupIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Charged"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/transactions":{"get":{"operationId":"get_billing_transactions","summary":"Answers one page of the caller's own ledger, newest first: what moved, how much, when, and what it was tagged with.","description":"Answers one page of the caller's own ledger, newest first: what moved, how\nmuch, when, and what it was tagged with.\n\n`count` is the size of the WHOLE history rather than of the page, which is how\na reader knows there is more to ask for, and `user` echoes the wallet the page\nwas read for — the same subject the spend gate debits, so a customer can see\nwhich account answered rather than guessing from their own token.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"parameters":[{"name":"currency","in":"query","required":false,"description":"Currency filters to one currency. Empty reads every currency.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit is the page size; absent or non-positive takes the default 100.","schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"description":"Offset is how far into the history the page starts.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Transactions"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/transactions/{id}":{"get":{"operationId":"get_billing_transactions_by_id","summary":"Reads one ledger entry by its id.","description":"Reads one ledger entry by its id.\n\nIt is the MEMBER of the collection beside it rather than a second way to ask —\nthe same rows GET /v1/billing/transactions lists, addressed one at a time. A\ntop-up receipt is read here, because a receipt IS a ledger entry: the id this\ntakes is the `transactionId` a top-up hands back.\n\nThe read is narrower than the list: commerce's core loads the row and refuses\nanything that is not a deposit, so a row that exists but is not a top-up\nanswers 404. That asymmetry is stated rather than closed, because widening a\nmoney read to make two shapes match is not a change worth making for symmetry.\n\nThe books are the caller's own and cannot be named, so a guessed id misses\nrather than reaching another tenant's ledger.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Transaction"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/usage":{"get":{"operationId":"get_billing_usage","summary":"Every billed call the caller's org made, attributed to a product","description":"Answers one row per BILLED call against the caller's org — transaction id, amount, timestamp and the metered unit. This is the raw charged ledger, not a rollup.\n\nEach row is stamped with a canonical `metadata.product` derived from what the meter persisted: `agent` becomes agents, `provisioning` becomes the provisioned kind, a token-metered row becomes inference, anything else keeps its metering surface. The ledger has no product field of its own, so this read is where that dimension is made real — from the SAME charged rows, never a second meter. A row that already carries its own product WINS, so the derivation stops the day the meter records one.\n\nEach row carries `name`: what its metered unit (`metadata.model`) reads as on a bill — `Desktop sandbox` for `desktop/visor`, `Agent sessions` for `session`. An AI model is its own name. Show `name`; `metadata.model` stays the unit the ledger keys on.\n\n`product=\u003cid\u003e` filters to one product server-side. `groupBy=product` reduces to `{product,requests,amountCents}` rollups instead of rows.\n\n`amount` is whole USD cents, ROUNDED; `decimal` beside it is the SAME debit exact, as an 18-decimal USD string. Sum `decimal`. A page of sub-cent token calls totals correctly there and totals ZERO in `amount` — that difference is real money.\n\nScoped to the caller's own org's books, where the org's ledger file IS the tenant boundary; no client-supplied subject is ever forwarded. 401 without a validated principal. The co-resident read returns the 2000 most recent debits, newest first; `start` and `end` narrow the window only on the split-deploy upstream.","tags":["billing"],"x-app":"billing","x-public":true},"post":{"operationId":"post_billing_usage","summary":"Debits one act an application metered to the org it acts for, and answers the receipt.","description":"Debits one act an application metered to the org it acts for, and\nanswers the receipt.\n\nThe caller is an application acting as itself — an IAM client_credentials\ntoken — and the org is the one that token acts in: the application's own, or\none that granted it membership, selected with X-Org-Id and named again in\n`org`. A person, an API key, an unauthenticated caller, and a body naming an\norg the token does not act in are all refused before anything is debited.\n\nThe debit lands in the same ledger every other meter writes, in the wallet GET\n/v1/billing/balance reports for the same caller. It is exactly-once on `id`: a\nretry answers the same receipt, and the same id for a different amount is 409.\nRecording does not gate — the work already happened — so a caller that must\nrefuse unfunded work asks GET /v1/billing/balance and GET\n/v1/billing/alerts/authorize first.","tags":["billing"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.usageReport"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.usageReceipt"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/usage/accounts":{"get":{"operationId":"get_billing_usage_accounts","summary":"Answers per-account totals for the linked provider accounts the gateway ROUTED this caller's traffic through — requests, prompt and completion tokens, recorded cost — plus their honest sum.","description":"Answers per-account totals for the linked provider accounts the\ngateway ROUTED this caller's traffic through — requests, prompt and completion\ntokens, recorded cost — plus their honest sum.\n\nThis is the one read in the billing namespace scoped to the PERSON, not the\norg. Rows are keyed on (validated org, validated user), so a caller sees the\naccounts THEY linked and never a colleague's, even inside one org — everything\nelse under /v1/billing is org-wide. Neither key is ever read from the request\nbody or the query.\n\nIt is a ROUTING counter, not the money ledger. `costCents` is 0 for an account\nbilled by its own subscription, where the plan pays the provider directly, so\nthese totals do not reconcile against what the org was charged.\n/v1/billing/usage is the charged ledger.\n\n401 without a validated principal. Where the linked-account plane is not\nresident the answer is an honest 501 — never an empty breakdown, which would\nread as no usage.","tags":["billing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.accounts"}}},"description":"ok","headers":{"Cache-Control":{"description":"Set by GET /v1/billing/usage/accounts.","schema":{"type":"string"}}}},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/usage/rollup":{"get":{"operationId":"get_billing_usage_rollup","summary":"Answers the caller's month: what their plan includes, what has been consumed against it, and the wallet beside it.","description":"Answers the caller's month: what their plan includes, what has been consumed\nagainst it, and the wallet beside it.\n\nThe two blocks are SEPARATE monies and are never added. One is usage a plan\ngranted; the other is prepaid credit bought with a card. Their sum is not a\nnumber anyone holds, and a reader that formed it would be inventing a balance.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.Rollup"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/billing/wire":{"get":{"operationId":"get_billing_wire","summary":"Answers where to send a wire top-up: the receiving bank details, with the caller's own payment reference.","description":"Answers where to send a wire top-up: the receiving bank details, with the\ncaller's own payment reference.\n\nThe account is the SERVING BRAND'S — resolved from the host the customer is\npaying on, so paying on one brand never shows another's bank — and the\nreference carries the caller's billing key, which is how an arriving wire\nnames who it credits. Nothing mints here; a receipt is settled by an operator\nonce the bank confirms it.\n\nIt is all-or-nothing: no configured account is 503 rather than a partial form,\nbecause nobody can wire to three fields out of five.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["billing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/billing.WireInstructions"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"billing","x-public":true,"x-tool":true}},"/v1/blueprint":{"get":{"operationId":"get_blueprint","summary":"Returns every deployable blueprint with its service count and estimated monthly compute cost.","description":"Returns every deployable blueprint with its service count and estimated\nmonthly compute cost.\n\nIt is the lightweight index the console renders as a template gallery before\ndrilling into one stack's bill of images — GET /v1/blueprint/sbom?template=\u003cid\u003e\nis the detail view. The cost is the same figure the deploy path meters the\ndeploying org on and the 20% author royalty is taken from, priced from the\nactive rate card (GET /v1/blueprint/health echoes that card).","tags":["blueprint"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/blueprint.blueprintIndex"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"blueprint","x-public":true,"x-tool":true}},"/v1/blueprint/health":{"get":{"operationId":"get_blueprint_health","summary":"Reports blueprint liveness and echoes the compute rate card in force.","description":"Reports blueprint liveness and echoes the compute rate card in force.\n\nThe rate card is the one the estimator actually applies after the operator env\noverlay, so an operator can confirm a tuned knob took effect rather than\ninferring it from a price. Not JWT-gated — a liveness probe must be reachable —\nand it always answers 200 while the subsystem is mounted.","tags":["blueprint"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/blueprint.blueprintHealth"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"blueprint","x-public":true,"x-tool":true}},"/v1/blueprint/sbom":{"get":{"operationId":"get_blueprint_sbom","summary":"A blueprint's bill of images and what running it costs","description":"Answers a blueprint's SBOM — the container images its compose stack runs, each with the CPU/memory footprint that was applied to it — together with the compute cost that footprint prices out to on the active rate card.\n\nONE address, TWO shapes at 200: `?template=\u003cid\u003e` returns that blueprint's Estimate alone (404 on an id no embedded blueprint carries), and no `template` returns `{data:[Estimate]}` for every blueprint — the batch the console's template gallery reads in one round-trip.\n\nThe blueprints are reference content embedded in the binary and validated at mount, so this read is the same for every caller and is scoped to no tenant. The per-hour figure it returns is the one the deploy path meters the deploying org on and the 20% author royalty is taken from; GET /v1/blueprint/health echoes the rate card it was priced from.","tags":["blueprint"],"x-app":"blueprint","x-public":true}},"/v1/books/accounts":{"get":{"operationId":"get_books_accounts","summary":"Returns the org's chart of accounts — the seeded fixed chart every posting key in the ledger refers to.","description":"Returns the org's chart of accounts — the seeded fixed chart every\nposting key in the ledger refers to.","tags":["books"],"parameters":[{"name":"sandbox","in":"query","required":false,"description":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\"; anything else\nreads the live one.","schema":{"type":"string"},"example":"false"}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/books.Account"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true}},"/v1/books/ask":{"post":{"operationId":"post_books_ask","summary":"Answers a plain-language question about the caller's own books — \"what is my MRR?\", \"how long is my runway?\" — with figures taken from their ledger, never a guessed number.","description":"Answers a plain-language question about the caller's own books — \"what is my\nMRR?\", \"how long is my runway?\" — with figures taken from their ledger, never a guessed\nnumber. A deterministic keyword router picks the intent and reads the real metrics, and\nthose figures, followups and report sources are computed BEFORE any model call and are\nnever altered by one: the optional narration client only rephrases the sentence, and it\ndegrades silently to the templated answer when no AI plane is wired. It is strictly\nread-only — it restates the books, it never posts to them.","tags":["books"],"requestBody":{"content":{"application/json":{"example":{"question":"how long is my runway?"},"schema":{"$ref":"#/components/schemas/books.AskRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/books.AskResponse"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true}},"/v1/books/bank/import":{"post":{"operationId":"post_books_bank_import","summary":"Import a bank statement file into your books","description":"Takes a bank statement as RAW BYTES — the file exactly as downloaded, OFX, QFX or CSV, not wrapped in JSON — parses every row, books it against the caller org's own ledger, and answers the tally: how many rows were seen, how many vouchers posted, how many inflows reconciled, how many raised a question, how many were own-account transfers, and how many were skipped.\n\nRE-IMPORTING THE SAME STATEMENT DOES NOT DOUBLE-BOOK. Every row goes through the same posting choke point every other source uses, keyed idempotently, so an overlapping statement — the usual case, since exports overlap at the month boundary — lands its new rows and counts the rest as skipped. Skipped is the number to read on a second import.\n\nIt is READ-ONLY against the bank: this ingests, it never sends money. Scoped to the caller's own org from the validated principal, and refused without one; `sandbox=true` writes the org's sandbox ledger instead of its real books. An empty body is a 400, and a file the parser cannot read is a 400 carrying the parser's reason rather than a partial import. On a deployment whose import parser is not built, this answers 501 rather than mishandling the file.","tags":["books"],"requestBody":{"content":{"application/octet-stream":{"schema":{"format":"binary","type":"string"}}}},"responses":{"2XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BankTally"}}},"description":"Success"}},"x-app":"books","x-public":true}},"/v1/books/bank/sync":{"post":{"operationId":"post_books_bank_sync","summary":"Pulls every connected bank (Plaid/Teller) for the caller's org, maps each fetched transaction to a posting and books it idempotently, then advances that connector's cursor so the next sync resumes where this one stopped.","description":"Pulls every connected bank (Plaid/Teller) for the caller's org, maps each\nfetched transaction to a posting and books it idempotently, then advances that\nconnector's cursor so the next sync resumes where this one stopped. One connector's\noutage is skipped rather than failing the whole sync. It reports the batch: how many\ntransactions were seen, how many vouchers posted, how many inflows reconciled against\nthe processor clearing account, how many raised a question, how many were own-account\ntransfers, and how many were already-processed no-ops. It is READ-ONLY against the\nbank — it ingests, it never sends money.","tags":["books"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/books.BankTally"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true}},"/v1/books/bank/transactions":{"get":{"operationId":"get_books_bank_transactions","summary":"Returns the org's normalized bank transactions, newest first — every row the import and connector paths have ingested, with its amount in exact cents, its direction, and whether it has been matched to a voucher yet.","description":"Returns the org's normalized bank transactions, newest first —\nevery row the import and connector paths have ingested, with its amount in exact cents,\nits direction, and whether it has been matched to a voucher yet.","tags":["books"],"parameters":[{"name":"sandbox","in":"query","required":false,"description":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\".","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many rows come back; 500 when absent or not positive.","schema":{"format":"int64","type":"integer"},"example":100}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/books.BankTxnRow"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true}},"/v1/books/bank/unreconciled":{"get":{"operationId":"get_books_bank_unreconciled","summary":"Returns the org's unmatched bank inflows and their open clarifying questions — the queue a human answers so an unexplained deposit is never guessed into revenue.","description":"Returns the org's unmatched bank inflows and their open clarifying\nquestions — the queue a human answers so an unexplained deposit is never guessed into\nrevenue.","tags":["books"],"parameters":[{"name":"sandbox","in":"query","required":false,"description":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\"; anything else\nreads the live one.","schema":{"type":"string"},"example":"false"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/books.unreconciledOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true}},"/v1/books/export":{"get":{"operationId":"get_books_export","summary":"Returns the complete financial package for the caller's org over (from, to]: the trial balance, the P\u0026L, the balance sheet, and the GL detail behind them — the four statements a tax preparer or an investor asks for, assembled from the one ledger in a single read so they cannot disagree with each other.","description":"Returns the complete financial package for the caller's org over\n(from, to]: the trial balance, the P\u0026L, the balance sheet, and the GL detail behind\nthem — the four statements a tax preparer or an investor asks for, assembled from the\none ledger in a single read so they cannot disagree with each other.","tags":["books"],"parameters":[{"name":"sandbox","in":"query","required":false,"description":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\".","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"From is the RFC3339 start of the window, exclusive. Empty means all time.","schema":{"type":"string"},"example":"2026-01-01T00:00:00Z"},{"name":"to","in":"query","required":false,"description":"To is the RFC3339 end of the window, inclusive. Empty means up to now.","schema":{"type":"string"},"example":"2026-12-31T23:59:59Z"},{"name":"format","in":"query","required":false,"description":"Format is the export encoding. Only \"json\" is supported; empty means json.","schema":{"type":"string"},"example":"json"},{"name":"limit","in":"query","required":false,"description":"Limit caps the GL detail rows included as the audit trail; 5000 when absent\nor not positive.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/books.FinancialPackage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true}},"/v1/books/gl":{"get":{"operationId":"get_books_gl","summary":"Returns the org's most recent GL Entry rows, newest first.","description":"Returns the org's most recent GL Entry rows, newest first. This is the raw\ndouble-entry detail behind every statement: one row per leg, with its debit, credit,\nposting time and the source that booked it.","tags":["books"],"parameters":[{"name":"sandbox","in":"query","required":false,"description":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\".","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many rows come back; 500 when absent or not positive.","schema":{"format":"int64","type":"integer"},"example":100}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/books.GLRow"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true}},"/v1/books/inbox":{"get":{"operationId":"get_books_inbox","summary":"Returns the org's open document queue — everything uploaded but not yet booked, newest first, each with its extracted summary and the confidence the scanner resolved its category at.","description":"Returns the org's open document queue — everything uploaded but not yet\nbooked, newest first, each with its extracted summary and the confidence the scanner\nresolved its category at. A booked document drops out of the queue.","tags":["books"],"parameters":[{"name":"sandbox","in":"query","required":false,"description":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\"; anything else\nreads the live one.","schema":{"type":"string"},"example":"false"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/books.inboxOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true},"post":{"operationId":"post_books_inbox","summary":"Queue a document for later scanning","description":"Takes a document as RAW BYTES and queues it in the caller org's inbox as `unsorted`, answering the queued item. It is the drop box: get the paperwork in now, read it later.\n\nIt EXTRACTS NOTHING and calls no model — that is what separates it from the scan. Nothing is proposed and nothing is posted; the item simply waits to be scanned, and a booked document leaves the queue.\n\nIDEMPOTENT BY CONTENT: the item's id is the file hash, so re-uploading the same bytes answers the existing item rather than adding a duplicate row — and it is the same id a scan of those bytes uses, which is how the two routes address one document. Scoped to the caller's own org from the validated principal and refused without one; `sandbox=true` targets the sandbox ledger, and `filename` is recorded for display. An empty or oversized upload is a 400.","tags":["books"],"requestBody":{"content":{"application/octet-stream":{"schema":{"format":"binary","type":"string"}}}},"responses":{"2XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxItem"}}},"description":"Success"}},"x-app":"books","x-public":true}},"/v1/books/metrics":{"get":{"operationId":"get_books_metrics","summary":"Returns the org's deterministic SaaS-metrics snapshot over an optional (from, to] window — MRR, ARR, revenue, COGS, burn, gross margin, net income, cash, deferred revenue, monthly burn and runway — as raw int64-cent figures AND the same figures already formatted.","description":"Returns the org's deterministic SaaS-metrics snapshot over an optional\n(from, to] window — MRR, ARR, revenue, COGS, burn, gross margin, net income, cash,\ndeferred revenue, monthly burn and runway — as raw int64-cent figures AND the same\nfigures already formatted. Every number is the ledger, aggregated the one way the books\ndefine it, never a guess; it is the grounded read the unified /v1/ask advisor replays.","tags":["books"],"parameters":[{"name":"sandbox","in":"query","required":false,"description":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\".","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"From is the RFC3339 start of the window, exclusive. Empty means all time.","schema":{"type":"string"},"example":"2026-01-01T00:00:00Z"},{"name":"to","in":"query","required":false,"description":"To is the RFC3339 end of the window, inclusive. Empty means up to now.","schema":{"type":"string"},"example":"2026-06-30T23:59:59Z"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/books.MetricsResponse"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true}},"/v1/books/pnl":{"get":{"operationId":"get_books_pnl","summary":"Returns the org's accrual-basis Profit \u0026 Loss over an optional (from, to] window of RFC3339 posting times: recognized revenue, matched cost, and the net.","description":"Returns the org's accrual-basis Profit \u0026 Loss over an optional (from, to]\nwindow of RFC3339 posting times: recognized revenue, matched cost, and the net.","tags":["books"],"parameters":[{"name":"sandbox","in":"query","required":false,"description":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\".","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"From is the RFC3339 start of the window, exclusive. Empty means all time.","schema":{"type":"string"},"example":"2026-01-01T00:00:00Z"},{"name":"to","in":"query","required":false,"description":"To is the RFC3339 end of the window, inclusive. Empty means up to now.","schema":{"type":"string"},"example":"2026-03-31T23:59:59Z"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/books.PnL"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true}},"/v1/books/position":{"get":{"operationId":"get_books_position","summary":"Returns the org's Balance Sheet as of `to` (empty = all time), with the Assets == Liabilities + Equity equation proof.","description":"Returns the org's Balance Sheet as of `to` (empty = all time), with the\nAssets == Liabilities + Equity equation proof.","tags":["books"],"parameters":[{"name":"sandbox","in":"query","required":false,"description":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\".","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"To is the RFC3339 instant the statement is struck as of. Empty means all time.","schema":{"type":"string"},"example":"2026-03-31T23:59:59Z"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/books.BalanceSheet"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true}},"/v1/books/questions":{"get":{"operationId":"get_books_questions","summary":"Returns the clarifying questions the caller's own recent GL raises — the unusual postings a founder should look at (outliers, reversals, round-offs, uncosted revenue, an overdrawn wallet), sharpest first.","description":"Returns the clarifying questions the caller's own recent GL raises — the\nunusual postings a founder should look at (outliers, reversals, round-offs, uncosted\nrevenue, an overdrawn wallet), sharpest first. An empty list means the books look clean;\nthe detector is deterministic over the ledger and invents nothing.","tags":["books"],"parameters":[{"name":"sandbox","in":"query","required":false,"description":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\"; anything else\nreads the live one.","schema":{"type":"string"},"example":"false"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/books.QuestionsResponse"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true}},"/v1/books/rules":{"get":{"operationId":"get_books_rules","summary":"Returns the org's auto-categorization rules, highest priority first.","description":"Returns the org's auto-categorization rules, highest priority first. A rule\nis a standing instruction — \"anything whose merchant contains X books to category Y\" —\nand it overrides a vendor's default category, so this is the list that decides how a\nfuture bill classifies itself.","tags":["books"],"parameters":[{"name":"sandbox","in":"query","required":false,"description":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\"; anything else\nreads the live one.","schema":{"type":"string"},"example":"false"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/books.rulesOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true},"post":{"operationId":"post_books_rules","summary":"Creates or updates one auto-categorization rule, keyed by its pattern — writing a pattern that already exists REPLACES that row's category and priority.","description":"Creates or updates one auto-categorization rule, keyed by its pattern —\nwriting a pattern that already exists REPLACES that row's category and priority. The\ncategory is normalized to a real COA expense account, and anything unrecognized becomes\n5900 Uncategorized rather than a guessed real account. It answers the row exactly as\nstored, so the caller sees the normalization. A rule overrides a vendor's default\ncategory, so this is the standing instruction that decides how a future bill classifies.","tags":["books"],"requestBody":{"content":{"application/json":{"example":{"category":"cloud","pattern":"aws","priority":5},"schema":{"$ref":"#/components/schemas/books.Rule"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/books.Rule"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true}},"/v1/books/scan":{"post":{"operationId":"post_books_scan","summary":"Scan a receipt or invoice into a proposed voucher","description":"Takes a receipt or invoice as RAW BYTES — a PDF, an image or plain text, uploaded under its own content type, not wrapped in JSON — extracts what the document says, resolves the vendor's expense category, and answers a DRAFT carrying a balanced voucher proposed for it.\n\nNOTHING IS POSTED. That split is the whole design: the model only ever produces a structured reading of the document, the voucher is assembled deterministically in Go from that reading, and the ledger is written only by the separate book call a human confirms. So a misread scan can propose a wrong draft; it cannot move money. Amounts are exact integer cents end to end — the extraction returns cents, never a decimal — so no rounding enters the ledger.\n\nThe draft's id is the FILE HASH, and that is what makes booking idempotent: re-scanning the same bytes addresses the same draft rather than queuing a second one. A row is written to the org's document inbox as a side effect, moving it from unsorted to draft. Scoped to the caller's own org from the validated principal and refused without one; `sandbox=true` targets the sandbox ledger, and `filename` is recorded for the inbox. An empty or oversized upload is a 400, and a deployment with no scanner model answers 501.","tags":["books"],"requestBody":{"content":{"application/octet-stream":{"schema":{"format":"binary","type":"string"}}}},"responses":{"2XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanDraft"}}},"description":"Success"}},"x-app":"books","x-public":true}},"/v1/books/scan/book":{"post":{"operationId":"post_books_scan_book","summary":"Posts a reviewed scanned bill to the ledger.","description":"Posts a reviewed scanned bill to the ledger. It is the scanner's ONLY write:\nthe voucher goes through the same post() choke point every other source uses, so it is\nchecked to balance (Σdebit == Σcredit) and is idempotent by (scan, scanId) — re-booking\nthe same scan answers posted=false and writes nothing. A bill whose economic identity\n(vendor, total, issue date) already posted under a DIFFERENT scan is refused 409 unless\noverride is set, which is what stops the same receipt re-scanned into a new file hash\nfrom double-booking. An unbalanced voucher is refused 400.","tags":["books"],"requestBody":{"content":{"application/json":{"example":{"scanId":"a5f3c1","voucher":{"description":"GitHub","legs":[{"account":"5300","debit":1234},{"account":"2001","credit":1234}]}},"schema":{"$ref":"#/components/schemas/books.BookRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/books.BookResponse"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true}},"/v1/books/sync":{"post":{"operationId":"post_books_sync","summary":"Ingests the caller's OWN org from commerce into BOTH ledgers (live and sandbox) and reports how many new vouchers posted to each.","description":"Ingests the caller's OWN org from commerce into BOTH ledgers (live and sandbox)\nand reports how many new vouchers posted to each. It is idempotent — money that has\nalready been booked posts nothing on a repeat — and it is read-only against commerce:\nit never mints a deposit, a credit or a payout, only the accounting twin of money that\nalready moved.","tags":["books"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/books.syncTally"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true}},"/v1/books/transactions":{"get":{"operationId":"get_books_transactions","summary":"Returns the org's booked ledger as a single-line register, newest first: one row per voucher, with its date, description, vendor, category, source and amount in exact cents.","description":"Returns the org's booked ledger as a single-line register, newest\nfirst: one row per voucher, with its date, description, vendor, category, source and\namount in exact cents. It is the double-entry ledger projected to the register a human\nreads, filterable by posting-time window, category and vendor. Strictly read-only — it\nrestates the books, it never moves them.","tags":["books"],"parameters":[{"name":"sandbox","in":"query","required":false,"description":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\".","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"From is the RFC3339 start of the posting-time window, inclusive.","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"To is the RFC3339 end of the posting-time window, inclusive.","schema":{"type":"string"}},{"name":"category","in":"query","required":false,"description":"Category filters to one COA account, named by number (\"5300\") or by category\nslug (\"software\").","schema":{"type":"string"},"example":"software"},{"name":"vendor","in":"query","required":false,"description":"Vendor filters to rows whose vendor or description contains this text,\ncase-insensitively.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many rows come back; 200 when absent or not positive.","schema":{"format":"int64","type":"integer"},"example":50}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/books.transactionsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true}},"/v1/books/trial":{"get":{"operationId":"get_books_trial","summary":"Returns the org's trial balance over an optional [from, to] window of RFC3339 posting times, including the opening/closing columns and the TotalDebit == TotalCredit proof that the books balance.","description":"Returns the org's trial balance over an optional [from, to] window of\nRFC3339 posting times, including the opening/closing columns and the\nTotalDebit == TotalCredit proof that the books balance.","tags":["books"],"parameters":[{"name":"sandbox","in":"query","required":false,"description":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\".","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"From is the RFC3339 start of the window, exclusive. Empty means all time.","schema":{"type":"string"},"example":"2026-01-01T00:00:00Z"},{"name":"to","in":"query","required":false,"description":"To is the RFC3339 end of the window, inclusive. Empty means up to now.","schema":{"type":"string"},"example":"2026-03-31T23:59:59Z"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/books.TrialBalance"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true}},"/v1/books/vendors":{"get":{"operationId":"get_books_vendors","summary":"Returns the org's vendor book: each canonical vendor, the alias spellings a receipt may print it under, and the expense account new bills from it default to.","description":"Returns the org's vendor book: each canonical vendor, the alias spellings a\nreceipt may print it under, and the expense account new bills from it default to. A\nvendor here is what makes a scanned bill self-classify instead of asking again.","tags":["books"],"parameters":[{"name":"sandbox","in":"query","required":false,"description":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\"; anything else\nreads the live one.","schema":{"type":"string"},"example":"false"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/books.vendorsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true},"post":{"operationId":"post_books_vendors","summary":"Creates or updates one vendor in the org's vendor book, keyed by its canonical name — writing a canonical name that already exists REPLACES that row's aliases and default category.","description":"Creates or updates one vendor in the org's vendor book, keyed by its\ncanonical name — writing a canonical name that already exists REPLACES that row's\naliases and default category. A category given as a slug (\"software\") is normalized to\nits real COA expense account, and anything unrecognized becomes 5900 Uncategorized\nrather than a guessed real account. It answers the row exactly as stored, so the caller\nsees the normalization. Recording a vendor is what makes future bills from it\nself-classify instead of asking again.","tags":["books"],"requestBody":{"content":{"application/json":{"example":{"aliases":["github.com"],"canonical":"GitHub","defaultCategory":"software"},"schema":{"$ref":"#/components/schemas/books.VendorRow"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/books.VendorRow"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"books","x-public":true,"x-tool":true}},"/v1/bot/members":{"get":{"operationId":"get_bot_members","summary":"Returns the caller org's bots as space members — each with the member account uuid and the Person reference the roster addresses it by.","description":"Returns the caller org's bots as space members — each with the member\naccount uuid and the Person reference the roster addresses it by.\n\nA deployment that runs no team subsystem has no spaces and therefore no\nroster, which is an empty list rather than an error: ErrNoPeer is the ONE\nerror that means \"this deployment does not run that app\", and every other\nfailure is an outage and says so.","tags":["bot"],"responses":{"200":{"content":{"application/json":{"example":{"bots":[{"active":true,"id":"a1","name":"Concierge","personRef":"…","userId":"…"}]},"schema":{"$ref":"#/components/schemas/bot.BotRoster"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"bot","x-public":true,"x-tool":true}},"/v1/bot/members/sync":{"post":{"operationId":"post_bot_members_sync","summary":"Re-projects the caller org's bots as members into every space of the org and removes the ones whose agent is gone.","description":"Re-projects the caller org's bots as members into every space of the org\nand removes the ones whose agent is gone. Idempotent, and admin only — the\nadmin bit rides the caller to team, which is what decides it.","tags":["bot"],"responses":{"200":{"content":{"application/json":{"example":{"projected":12,"synced":true},"schema":{"$ref":"#/components/schemas/bot.BotSync"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"bot","x-public":true,"x-tool":true}},"/v1/bot/runs":{"get":{"operationId":"get_bot_runs","summary":"Returns the caller org's live bot runs, read from the bot runtime and projected into the console contract with each run's live session URL derived here.","description":"Returns the caller org's live bot runs, read from the bot runtime and projected\ninto the console contract with each run's live session URL derived here.\n\nThe org is ALWAYS the validated principal's org, NEVER a request field, and it is\nwhat scopes the runtime's answer — so one tenant can never enumerate another's\nruns. A runtime that cannot answer is an error, not an empty list: [] would tell\nthe caller \"your org has no runs\", which is a different claim from \"we could not\nask\", and the difference is the whole reason this endpoint exists.","tags":["bot"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/bot.BotRuns"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"bot","x-public":true,"x-tool":true}},"/v1/bot/runs/{runId}/stop":{"post":{"operationId":"post_bot_runs_by_runid_stop","summary":"Terminates one of the caller org's own bot runs and reports its terminal state.","description":"Terminates one of the caller org's own bot runs and reports its terminal state.\n\nThe own-key guard is the org: it is the caller's validated org, never theirs to\nchoose, and the runtime resolves the run id UNDER it. A run belonging to another\ntenant is not among this org's runs, so it answers absent — the same 404 a\nnonexistent id gets, which is what keeps this from being an oracle.\n\nAbsence is honoured ONLY when the runtime answers it. A runtime that does not\nserve stop reports nothing about the run, and reporting \"stopped\" on that basis\nwould be a stop that cannot fail — so it is a 502.","tags":["bot"],"parameters":[{"name":"runId","in":"path","required":true,"description":"RunID is the run to stop, as the bot runtime named it. It is read from the\nURL — the `{runId}` segment the router matched on — and a body carrying a\ndifferent id cannot redirect the stop.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/bot.BotStopped"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"bot","x-public":true,"x-tool":true}},"/v1/build":{"post":{"operationId":"post_build","summary":"Triggers a native build — an image, or the binaries a repo declares.","description":"Triggers a native build — an image, or the binaries a repo declares.\n\nThe fabric's own build trigger, and what `hanzo build` and git-push-to-deploy\ncall. It answers 202 with the build job id: a queued build, not a pushed\nartifact.\n\nTwo lanes, and a build is exactly one of them. The IMAGE lane takes `repo` and\nthe output `image` and launches a BuildKit Job that pushes it. The ARTIFACT lane\ntakes `binaries` — the same recipe the repo's hanzo.yml declares — and publishes\nto object storage instead; it must carry no `image`, because a build produces\nbinaries or an image, never both.\n\nPRIVILEGED, and A BUILD BELONGS TO THE ORGANIZATION ITS CREDENTIAL NAMES. Two\ncredentials, never a third:\n\n  - one that NAMES an organization — a person who administers it (the `hanzo\n    build` path, so one IAM login authorizes a build with no separate build\n    token), or that organization's own machine identity (the pipeline path). The\n    build is attributed to that org and confined to what it owns.\n  - the shared build-callback token, compared in constant time. It names NO\n    organization, which is both why the fabric's own release can publish across\n    brands with it and why anything that CAN name one is read first.\n\nBoth are bounded by the owned-registry allowlist. The org path is bounded again,\nby the org: the image's registry namespace must be one that organization owns, so\nit publishes into its own brand and can never overwrite another's through the\nshared push credential. The same confinement applies to the artifact lane's repo\nowner. There is no request field naming an organization — the attribution is read\noff the credential, so there is nothing for a caller to write it with.\n\nThe output image is parsed and validated as a single well-formed OCI ref before\nany authorization decision reads it, so a crafted ref cannot smuggle a\nbuild-exporter attribute past the check.","tags":["platform"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.runnerBuildReq"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.runnerBuildResp"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/build/{id}":{"get":{"operationId":"get_build_by_id","summary":"Answers one build: its status, and for a failed build the reason.","description":"Answers one build: its status, and for a failed build the reason.\n\nA build belongs to the organization its credential names, so it is read by the\ncredential that could have asked for it, and another organization's build is\n404 rather than 403: whether an id exists is not said to anyone it is not for.","tags":["platform"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the build's id, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.runnerBuildResp"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/campaign":{"get":{"operationId":"get_campaign","summary":"Returns the org's campaigns, newest first, optionally narrowed to one status.","description":"Returns the org's campaigns, newest first, optionally narrowed to\none status.\n\nA campaign is the top-level go-to-market object: a value that SPANS channels\n(paid, organic, email) and fans out to the executor for each. The listing is\norg-scoped server-side, so one org can never see another's campaigns.","tags":["campaign"],"parameters":[{"name":"status","in":"query","required":false,"description":"Status keeps only campaigns in that state: draft, live, paused or failed.\nEmpty means any.","schema":{"type":"string"},"example":"live"},{"name":"limit","in":"query","required":false,"description":"Limit bounds the page. 0 or less means the default of 200; anything above\n1000 is clamped to 1000.","schema":{"format":"int64","type":"integer"},"example":50}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/campaign.campaignPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"campaign","x-public":true,"x-tool":true},"post":{"operationId":"post_campaign","summary":"Creates a campaign as a DRAFT and returns it.","description":"Creates a campaign as a DRAFT and returns it.\n\nA draft is inert: nothing is sent, no connector is touched and no budget is\ncommitted until the campaign is launched. The channels named here are validated\nand de-duplicated by kind (one executor per kind), and every channel starts\n\"pending\" whatever the caller claims — a client can never assert a launched\nstate.","tags":["campaign"],"requestBody":{"content":{"application/json":{"example":{"budget":250000,"channels":[{"kind":"paid","platform":"meta"}],"content":["Ship faster"],"name":"Spring launch"},"schema":{"$ref":"#/components/schemas/campaign.campaignWrite"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/campaign.campaignRecord"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"campaign","x-public":true,"x-tool":true}},"/v1/campaign/summary":{"get":{"operationId":"get_campaign_summary","summary":"Returns the org's go-to-market roll-up: how many campaigns exist, how many are live, their total budget in cents, and which channel executors this deployment can actually reach.","description":"Returns the org's go-to-market roll-up: how many campaigns\nexist, how many are live, their total budget in cents, and which channel\nexecutors this deployment can actually reach.\n\nThe channel list is the deployment's honest capability, not a wish: a kind\nmissing from it is one a launch will record as \"unavailable\" rather than fail\non.","tags":["campaign"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/campaign.campaignSummary"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"campaign","x-public":true,"x-tool":true}},"/v1/campaign/{id}":{"delete":{"operationId":"delete_campaign_by_id","summary":"Removes one campaign of the caller's org and answers 204 with no body.","description":"Removes one campaign of the caller's org and answers 204 with no\nbody. 404 when the org has no campaign with that id.\n\nIt deletes the RECORD, not the executions: a campaign whose channels are live\non a provider should be paused first, or those executions keep running with\nnothing here to report them.","tags":["campaign"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the campaign's server-minted handle, \"cmp_\"-prefixed.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"campaign","x-public":true,"x-tool":true},"get":{"operationId":"get_campaign_by_id","summary":"Returns one campaign of the caller's org — its name, audience, creatives, channels with their per-channel launch state, schedule, budget and status.","description":"Returns one campaign of the caller's org — its name, audience,\ncreatives, channels with their per-channel launch state, schedule, budget and\nstatus. 404 when the org has no campaign with that id.","tags":["campaign"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the campaign's server-minted handle, \"cmp_\"-prefixed.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/campaign.campaignRecord"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"campaign","x-public":true,"x-tool":true},"put":{"operationId":"put_campaign_by_id","summary":"Rewrites a campaign's core fields — name, audience, creatives, schedule and budget — and returns the updated campaign.","description":"Rewrites a campaign's core fields — name, audience, creatives,\nschedule and budget — and returns the updated campaign.\n\nChannels are replaced ONLY while the campaign is still a draft. Once it is\nlaunched its channels carry provider state (an external id, a live status), so\nthey are added and removed explicitly through the channels sub-resource\ninstead; a whole-object write would silently orphan a running execution.","tags":["campaign"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the campaign to update, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"budget":500000,"name":"Spring launch"},"schema":{"$ref":"#/components/schemas/campaign.campaignUpdate"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/campaign.campaignRecord"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"campaign","x-public":true,"x-tool":true}},"/v1/campaign/{id}/channels":{"post":{"operationId":"post_campaign_by_id_channels","summary":"Adds a channel to a campaign, or REPLACES the one it already has of that kind, and returns the updated campaign.","description":"Adds a channel to a campaign, or REPLACES the one it already\nhas of that kind, and returns the updated campaign.\n\nA campaign carries at most one channel per kind, because the kind IS the\nexecutor: adding a second \"paid\" channel would mean two ad accounts running one\ncampaign with no way to tell their results apart. The new channel starts\n\"pending\" — adding it does not launch it.","tags":["campaign"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the campaign to add the channel to, from the path.","schema":{"type":"string"},"example":"cmp_1f…"}],"requestBody":{"content":{"application/json":{"example":{"account":"list_42","id":"cmp_1f…","kind":"email","platform":"sendgrid"},"schema":{"$ref":"#/components/schemas/campaign.channelAdd"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/campaign.campaignRecord"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"campaign","x-public":true,"x-tool":true}},"/v1/campaign/{id}/channels/{kind}":{"delete":{"operationId":"delete_campaign_by_id_channels_by_kind","summary":"Drops one channel from a campaign and returns the updated campaign.","description":"Drops one channel from a campaign and returns the updated\ncampaign. 404 when the campaign carries no channel of that kind.\n\nIt removes the channel from the PLAN. A channel that is live at its provider\nshould be paused first — dropping the row here leaves nothing to pause it with\nafterwards.","tags":["campaign"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the campaign, from the path.","schema":{"type":"string"}},{"name":"kind","in":"path","required":true,"description":"Kind is the channel to remove: paid, organic or email.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/campaign.campaignRecord"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"campaign","x-public":true,"x-tool":true}},"/v1/campaign/{id}/launch":{"post":{"operationId":"post_campaign_by_id_launch","summary":"Launch a campaign across every channel it declares","description":"Pushes the campaign live on each of its channels through that channel's executor and answers the whole campaign with the per-channel outcome written back onto it.\n\nThe fan-out is BEST-EFFORT PER CHANNEL, and the honest reading of the result is the rule most callers get wrong: one channel failing never aborts the others, so each channel row carries its own `live`, `failed` or `unavailable` status and detail, and a paid launch can be live while an email launch failed. The campaign itself is `live` when AT LEAST ONE channel launched and `failed` only when none did — `live` is not a claim that every channel launched. Repeating the call is safe: a channel already live is skipped, never re-launched. A campaign carrying more than one creative has its variant assigned here by the experiment client and tagged as `utm_content`.\n\nOrg-scoped and fails closed: a valid bearer is required (401 without one), the campaign is read under the caller's OWN org so another tenant's id is a 404, and a campaign with no channels is a 400 — there is nothing to launch. Each executor resolves its own org's connector token from the org passed to it, so a launch can never spend through another tenant's connector.","tags":["campaign"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"campaign","x-public":true}},"/v1/campaign/{id}/metrics":{"get":{"operationId":"get_campaign_by_id_metrics","summary":"Returns a campaign's results over a window: the analytics funnel (impressions, clicks, conversions, revenue, visitors), the spend each channel's connector reports, and the derived growth KPIs — CTR, CVR, CAC and ROAS.","description":"Returns a campaign's results over a window: the analytics\nfunnel (impressions, clicks, conversions, revenue, visitors), the spend each\nchannel's connector reports, and the derived growth KPIs — CTR, CVR, CAC and\nROAS.\n\nThere is exactly ONE metrics plane and nothing is stored here: the funnel is an\nanalytics query over the campaign's utm_campaign-tagged events, and the spend is\neach provider's own number read through the org's connector. A warehouse that is\nnot emitting yet degrades to available:false with zeroes — honest-empty, never a\n500 and never a fabricated number. When the campaign runs more than one creative\nand an experiment is wired, abTest carries the A/B analysis.","tags":["campaign"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the campaign to report on, from the path.","schema":{"type":"string"},"example":"cmp_1f…"},{"name":"range","in":"query","required":false,"description":"Range is the lookback window: 24h, 7d, 30d or 90d. Anything else, including\nempty, reads as 30d.","schema":{"type":"string"},"example":"7d"},{"name":"start","in":"query","required":false,"description":"Start is an explicit RFC3339 window start. Honored only together with End,\nand only when End is after it.","schema":{"type":"string"}},{"name":"end","in":"query","required":false,"description":"End is an explicit RFC3339 window end.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/campaign.campaignResults"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"campaign","x-public":true,"x-tool":true}},"/v1/campaign/{id}/pause":{"post":{"operationId":"post_campaign_by_id_pause","summary":"Pause every live channel on a campaign at its provider","description":"Pauses each live channel on its provider and answers the whole campaign, moved to `paused`, with the per-channel outcome written back onto it.\n\nOnly channels that are live and carry a provider reference are touched; a channel whose executor is no longer wired is marked `unavailable` and one whose pause errored is marked `failed`, with the reason on the row. The campaign still reports `paused` in both cases, and that is deliberate rather than sloppy: no live channel remains that this process will meter, and the rows say exactly which provider was not reached so it can be settled by hand.\n\nOrg-scoped and fails closed: a valid bearer is required (401 without one) and the campaign is read under the caller's OWN org, so another tenant's id is a 404.","tags":["campaign"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"campaign","x-public":true}},"/v1/capabilities":{"get":{"operationId":"capabilitiesList","summary":"Answers the org's capabilities by name, each with its state, its latest and installed versions, and what the installed one did live.","description":"Answers the org's capabilities by name, each with its state,\nits latest and installed versions, and what the installed one did live.","tags":["train"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.capabilitiesOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true},"post":{"operationId":"capabilitiesCreate","summary":"Makes a capability in draft from captured corrections of one question: that question (its key, type and labels) is the route it will be installed behind.","description":"Makes a capability in draft from captured corrections of one\nquestion: that question (its key, type and labels) is the route it will be\ninstalled behind. Refused: a name taken by another capability or by a\npublished job's output (409 name_taken), corrections of two questions or not\ncaptured (400), and a question another of the org's capabilities answers (409\nroute_conflict).","tags":["train"],"requestBody":{"content":{"application/json":{"example":{"corrections":["cor_0123456789abcdef"],"name":"refund-intent"},"schema":{"$ref":"#/components/schemas/train.createIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.Capability"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/capabilities/capture":{"get":{"operationId":"capabilitiesCapture","summary":"Answers whether the org's Kai decisions keep their states for its capabilities to learn from.","description":"Answers whether the org's Kai decisions keep their states for its\ncapabilities to learn from. Off until the org turns it on or files its first\ncorrection.","tags":["train"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.Capture"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true},"put":{"operationId":"capabilitiesSetCapture","summary":"Turns capture on or off for the org's Kai decisions from the next one.","description":"Turns capture on or off for the org's Kai decisions from the next\none. Off keeps what was captured until its retention ends.","tags":["train"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.captureIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.Capture"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/capabilities/corrections":{"get":{"operationId":"capabilitiesCorrections","summary":"Answers every correction of the org's decisions, newest first, each captured (it can teach) or missing (its decision was made with capture off), and the questions they ask, each counted: what a capability is made from.","description":"Answers every correction of the org's decisions, newest first,\neach captured (it can teach) or missing (its decision was made with capture\noff), and the questions they ask, each counted: what a capability is made from.","tags":["train"],"parameters":[{"name":"question","in":"query","required":false,"description":"Question keeps one question's corrections.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.correctionsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/capabilities/{name}":{"delete":{"operationId":"capabilitiesDelete","summary":"Deletes a capability and its versions; their artifacts go with the org's retention.","description":"Deletes a capability and its versions; their artifacts go\nwith the org's retention. Refused 409 installed while a version is in the set:\ndisable it first.","tags":["train"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.unmadeOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true},"get":{"operationId":"capabilitiesGet","summary":"Answers one capability: its versions with their evaluations, newest first, and what its installed version did live.","description":"Answers one capability: its versions with their evaluations,\nnewest first, and what its installed version did live.","tags":["train"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.Capability"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/capabilities/{name}/disable":{"post":{"operationId":"capabilitiesDisable","summary":"Takes a capability's installed version out of the org's published set: its questions are answered by base Kai, bit for bit, from the next decision.","description":"Takes a capability's installed version out of the org's\npublished set: its questions are answered by base Kai, bit for bit, from the\nnext decision. Its versions stay, and any one that passed can be published\nagain.","tags":["train"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.Capability"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/capabilities/{name}/publish":{"post":{"operationId":"capabilitiesPublish","summary":"Installs a version in the org's published set, where ai attaches it to the org's decisions: the version's evaluation must have passed, and it must have been taught over the base Kai serves now.","description":"Installs a version in the org's published set, where ai\nattaches it to the org's decisions: the version's evaluation must have passed,\nand it must have been taught over the base Kai serves now. Refused 409:\nnot_publishable (no passing version, or that one did not pass),\nneeds_validation (Kai's base moved since it was taught: train again),\nroute_conflict (a published job answers its question).","tags":["train"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.publishCapIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.Capability"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/capabilities/{name}/rollback":{"post":{"operationId":"capabilitiesRollback","summary":"Puts the version installed before the installed one back in the org's published set: exactly that version's artifact, nothing retrained.","description":"Puts the version installed before the installed one back\nin the org's published set: exactly that version's artifact, nothing retrained.\nRefused 409 no_previous when none was installed before it, and\nneeds_validation when that one was taught over another base than Kai serves.","tags":["train"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.Capability"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/capabilities/{name}/train":{"post":{"operationId":"capabilitiesTrain","summary":"Teaches a capability a new version from its corrections, on the CPU over the states its org's decisions captured: no row is encoded again.","description":"Teaches a capability a new version from its corrections, on\nthe CPU over the states its org's decisions captured: no row is encoded again.\nThe smallest correction that passes evaluation is kept (calibration, then a\nhead, then a boost and veto pair); its evaluation, held out against base Kai,\nsays what it repaired and damaged, how often it fires, that every other answer\nis base Kai's bit for bit, and what it costs. A version that passed is\npublishable; one that did not is evaluated, with the gate's reasons. An\ninstalled capability keeps serving its installed version until a new one is\npublished.","tags":["train"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"corrections":["cor_0123456789abcdef","cor_fedcba9876543210"]},"schema":{"$ref":"#/components/schemas/train.trainIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.Capability"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/captable/classes":{"get":{"operationId":"get_captable_classes","summary":"Returns the caller org's share classes, in creation order.","description":"Returns the caller org's share classes, in creation order. A\nshare class is what a certificate is issued in, and every class the company\nhas authorized appears. The response is a bare JSON array, not an envelope.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/captable.captableShareClass"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true},"post":{"operationId":"post_captable_classes","summary":"Defines a new class of shares.","description":"Defines a new class of shares.\n\nEvery field but convertsToShareClassId is required — a class is the instrument\nevery later issuance prices against, so a partially-specified one would silently\nmis-value every share issued into it. `seniority` orders liquidation preference\nwith LOWER first.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableShareClassIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableCreated"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/captable/classes/{id}":{"patch":{"operationId":"patch_captable_classes_by_id","summary":"Replaces one share class's terms.","description":"Replaces one share class's terms.\n\nIt is a full REPLACE and not a merge, despite the PATCH: every field is written\nas sent, so a field omitted is written empty rather than left alone. Send the\nwhole class. The method is PATCH because the resource is addressed by id, not\nbecause the body is partial — and getting that backwards silently blanks terms\nevery later issuance prices against.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID addresses the resource. The URL is the addressing authority — a path\nsegment binds after the body and after the query — so the address decides\nwhich row is written whatever a body claims.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableShareClassAmend"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableUpdated"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/captable/company":{"get":{"operationId":"get_captable_company","summary":"Returns the caller org's cap-table company record.","description":"Returns the caller org's cap-table company record. The row is\nseeded when the tenant's store first opens, so it always exists; its name and\nincorporation details are set with PUT /v1/captable/company.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableCompany"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true},"put":{"operationId":"put_captable_company","summary":"Sets the caller org's company name and incorporation details.","description":"Sets the caller org's company name and incorporation details.\nThe name is required; the three incorporation fields are optional and each is\nstored as empty when omitted, so a call that sends only a name CLEARS them.\nThe company row itself is seeded when the tenant's store first opens, so this\nnever creates one.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableCompanyUpdate"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableUpdated"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/captable/convertibles":{"get":{"operationId":"get_captable_convertibles","summary":"Returns the caller org's convertible notes, newest first.","description":"Returns the caller org's convertible notes, newest first. A\nnote's principal sits OUTSIDE issued equity until it converts, so it is not\npart of the share counts.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableNotes"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true},"post":{"operationId":"post_captable_convertibles","summary":"Records a convertible note.","description":"Records a convertible note.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableConvertibleIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableCreated"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/captable/convertibles/{id}":{"delete":{"operationId":"delete_captable_convertibles_by_id","summary":"Removes one of the caller org's convertible notes, taking its principal out of the cap table's unconverted-instrument totals.","description":"Removes one of the caller org's convertible notes, taking its\nprincipal out of the cap table's unconverted-instrument totals. An id this org\ndoes not hold is not found.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the convertible note to delete.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableDeleted"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/captable/investments":{"get":{"operationId":"get_captable_investments","summary":"Returns the caller org's investments, newest first.","description":"Returns the caller org's investments, newest first. It spans\nevery round, so it is the flat ledger of cheques written into the company,\neach naming its investor and the round it went into.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableInvestments"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/captable/options":{"get":{"operationId":"get_captable_options","summary":"Returns the caller org's option grants, newest first.","description":"Returns the caller org's option grants, newest first. Each row is\njoined to its grantee and its equity plan. Grants that are EXERCISED, EXPIRED\nor CANCELLED are listed here but do not dilute the cap table.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableOptions"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true},"post":{"operationId":"post_captable_options","summary":"Grants options to a stakeholder from an equity plan.","description":"Grants options to a stakeholder from an equity plan.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableOptionIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableCreated"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/captable/options/{id}":{"delete":{"operationId":"delete_captable_options_by_id","summary":"Removes one of the caller org's option grants, taking its shares out of the cap table's granted-options and fully-diluted counts.","description":"Removes one of the caller org's option grants, taking its shares\nout of the cap table's granted-options and fully-diluted counts. An id this org\ndoes not hold is not found.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the option grant to delete.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableDeleted"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/captable/plans":{"get":{"operationId":"get_captable_plans","summary":"Returns the caller org's equity plans, newest first.","description":"Returns the caller org's equity plans, newest first. An equity\nplan is an option pool: a reserve of shares, drawn from one share class, that\noption grants are written against.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableEquityPlans"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true},"post":{"operationId":"post_captable_plans","summary":"Opens an equity plan that options are granted from.","description":"Opens an equity plan that options are granted from.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableEquityPlanIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableCreated"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/captable/rounds":{"get":{"operationId":"get_captable_rounds","summary":"Returns the caller org's fundraising rounds, newest first.","description":"Returns the caller org's fundraising rounds, newest first. A round\ngroups a fundraising event; a PRICED round also carries the share class and\nprice per share it issues at.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableRounds"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true},"post":{"operationId":"post_captable_rounds","summary":"Opens a priced round that investments can be added to.","description":"Opens a priced round that investments can be added to.\n\nThe round opens OPEN; investing into a closed one is refused.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableRoundIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableCreated"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/captable/rounds/{id}":{"get":{"operationId":"get_captable_rounds_by_id","summary":"Returns one of the caller org's fundraising rounds together with every investment written into it, oldest first.","description":"Returns one of the caller org's fundraising rounds together with every\ninvestment written into it, oldest first. A round id that does not exist in the\ncaller's org is not found — including one that exists in another tenant, since\nthe org comes from the caller's principal and is part of the lookup.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the round to read. It is the path segment: the URL is the addressing\nauthority, and the org it is resolved in comes from the caller's principal,\nso an id from another tenant is simply not found.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableRoundDetail"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/captable/rounds/{id}/close":{"post":{"operationId":"post_captable_rounds_by_id_close","summary":"Closes one of the caller org's fundraising rounds, recording the close date and moving its status to CLOSED.","description":"Closes one of the caller org's fundraising rounds, recording the\nclose date and moving its status to CLOSED. Only an OPEN round can be closed:\na round that is already closed — like an id this org does not hold — is not\nfound. Closing a round does not change what was invested in it.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the round to close. It is the path segment: the URL is the\naddressing authority, and the org it is resolved in comes from the\ncaller's principal, so an id from another tenant is simply not found.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableRoundCloseRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableUpdated"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/captable/rounds/{id}/investments":{"post":{"operationId":"post_captable_rounds_by_id_investments","summary":"Records one investor's money into an open round.","description":"Records one investor's money into an open round.\n\nThe round must be OPEN; investing into a closed one is refused. Where the round\ncarries a price per share, the investment also issues the shares it buys and the\nanswer names them.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the round to invest in. The URL is the addressing authority — a path\nsegment binds after the body and after the query — so the address decides\nwhich round is written whatever a body claims.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableInvestmentIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableInvested"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/captable/safes":{"get":{"operationId":"get_captable_safes","summary":"Returns the caller org's SAFEs, newest first.","description":"Returns the caller org's SAFEs, newest first. A SAFE is a simple\nagreement for future equity: its capital sits OUTSIDE issued equity until it\nconverts, so it is not part of the share counts.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableSafes"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true},"post":{"operationId":"post_captable_safes","summary":"Records a SAFE — a simple agreement for future equity.","description":"Records a SAFE — a simple agreement for future equity.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableSafeIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableCreated"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/captable/safes/{id}":{"delete":{"operationId":"delete_captable_safes_by_id","summary":"Removes one of the caller org's SAFEs, taking its capital out of the cap table's unconverted-instrument totals.","description":"Removes one of the caller org's SAFEs, taking its capital out of the\ncap table's unconverted-instrument totals. An id this org does not hold is not\nfound.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the SAFE to delete.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableDeleted"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/captable/shares":{"get":{"operationId":"get_captable_shares","summary":"Returns the caller org's share certificates, newest first.","description":"Returns the caller org's share certificates, newest first. Each row\nis joined to its holder and its share class, so a certificate names who holds\nit and what class it is in without a second call.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableShares"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true},"post":{"operationId":"post_captable_shares","summary":"Issues a share certificate to a stakeholder.","description":"Issues a share certificate to a stakeholder.\n\nThe certificate id must be UNIQUE within the company — a duplicate is refused\n409, not silently merged — and both the stakeholder and the share class must\nbelong to this company, so an id from another tenant is a 400 rather than a\ncross-company issuance.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableShareIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableCreated"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/captable/shares/transfer":{"post":{"operationId":"post_captable_shares_transfer","summary":"Moves shares from one stakeholder to another.","description":"Moves shares from one stakeholder to another.\n\nOmit `quantity` to transfer the whole certificate, which REASSIGNS it and mints\nno new share. Send a quantity below the amount held to SPLIT it — the source\ncertificate keeps the remainder, and a split additionally requires\n`certificateId` for the new certificate, which must be unique in the company.\nA quantity outside 1..held is refused, so a transfer can never over-issue.\n\nBoth outcomes answer 200: a transfer records a movement between holders and\nmints no security of its own, which is why this is not a 201 the way an\ninvestment is.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableShareTransfer"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableTransferred"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/captable/shares/{id}":{"delete":{"operationId":"delete_captable_shares_by_id","summary":"Removes one of the caller org's share certificates, taking its shares out of the cap table's outstanding and fully-diluted counts.","description":"Removes one of the caller org's share certificates, taking its\nshares out of the cap table's outstanding and fully-diluted counts. An id this\norg does not hold is not found.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the share certificate to delete.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableDeleted"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/captable/stakeholders":{"get":{"operationId":"get_captable_stakeholders","summary":"Returns the caller org's stakeholders, newest first.","description":"Returns the caller org's stakeholders, newest first. The\nresponse is a bare JSON array, not an envelope. Each row carries the holder's\ncontact and address fields alongside the company's name.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/captable.captableStakeholder"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true},"post":{"operationId":"post_captable_stakeholders","summary":"Add stakeholders to the cap table","description":"Records the people and institutions that can hold equity — the rows every share, option, SAFE, note and investment is issued to.\n\nThe body is ONE stakeholder object or an ARRAY of them, and the array is the point: a whole roster loads in a single call. Email is the identity within the company, so a stakeholder whose email is already on the table is SKIPPED rather than duplicated or rejected — the 201 reports how many rows were actually inserted, which is what makes re-running an import safe. Validation is all-or-nothing across the batch: one bad entry refuses the whole array.\n\nWrites the caller's OWN cap table: the org resolved from the validated principal selects the tenant's store and scopes every row, so there is no field by which a caller can write into another company's table; a request with no validated org is refused 401, and one from a member who is neither a SuperAdmin nor an admin of the org is refused 403. The whole write runs in one transaction, so a refusal leaves nothing behind. Validation is the cap-table bundle's and so is its refusal: a bad body comes back as {success:false, message, errors:[…]} with the failing fields listed, and numeric fields accept a number OR a numeric string. Bodies are capped at 1 MiB.","tags":["captable"],"x-app":"captable","x-public":true}},"/v1/captable/stakeholders/{id}":{"delete":{"operationId":"delete_captable_stakeholders_by_id","summary":"Removes one of the caller org's stakeholders.","description":"Removes one of the caller org's stakeholders. It REFUSES to\norphan issued equity: a holder that still holds share certificates or option\ngrants cannot be deleted, and answers 400 saying so — release or transfer the\nholdings first. An id this org does not hold is not found.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the stakeholder to delete.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableDeleted"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true},"patch":{"operationId":"patch_captable_stakeholders_by_id","summary":"Changes one of the caller org's stakeholders.","description":"Changes one of the caller org's stakeholders. It is a\nPARTIAL update: only the fields the request names are written, and a field\nsent as null clears that column. A request that names no updatable field is\nrefused, and an id this org does not hold is not found.\n\nThe values are stored as sent. Unlike adding a stakeholder, this route does\nnot check the email's shape or the type and relationship vocabularies, so it\ncan record a value that adding one would have rejected.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the stakeholder to update. It is the path segment: the URL is the\naddressing authority, and the org it is resolved in comes from the\ncaller's principal, so an id from another tenant is simply not found.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableStakeholderPatch"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableUpdated"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/captable/summary":{"get":{"operationId":"get_captable_summary","summary":"Computes the caller org's cap table.","description":"Computes the caller org's cap table. It answers who owns what on a\nfully-diluted basis: outstanding shares, granted options, per-stakeholder\nownership percentages, each share class's authorized versus issued position,\nand the capital sitting on SAFEs and convertible notes that have not yet\nconverted. Only non-terminal option grants dilute — EXERCISED, EXPIRED and\nCANCELLED grants are excluded, so equity issued through an exercised option is\nnever counted twice.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["captable"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/captable.captableSummary"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"captable","x-public":true,"x-tool":true}},"/v1/catalog":{"get":{"operationId":"get_catalog","summary":"Searches AND browses the cross-org catalog: every project, app and site the fleet has built, whichever org built it.","description":"Searches AND browses the cross-org catalog: every project, app and site\nthe fleet has built, whichever org built it.\n\nIt reads TWO corpora and returns them as one page — the published,\nworld-readable catalog that every caller sees, plus the caller's OWN org's\nprivate entries when the request carries a validated principal. Each row says\nwhich it came from in `scope`, so a client can warn before sharing a link. An\nanonymous caller simply gets the published one; no filter can ever widen a\ncaller into another tenant's corpus, because the query that would return it is\nnever run for them.\n\nA request with no q is a browse rather than a search, and both answer the same\nshape: the page, the total before paging, and the facet counts over the whole\nmatching set.","tags":["catalog"],"parameters":[{"name":"q","in":"query","required":false,"description":"Q is the free-text query the lexical index scores relevance on. Empty is a\nbrowse rather than a search — the same request either way.","schema":{"type":"string"}},{"name":"org","in":"query","required":false,"description":"Org narrows to one builder org: hanzo | lux | zoo. Case-insensitive.","schema":{"type":"string"}},{"name":"kind","in":"query","required":false,"description":"Kind narrows to repo | site. Case-insensitive.","schema":{"type":"string"}},{"name":"origin","in":"query","required":false,"description":"Origin narrows to what a row IS to you: template | community | third-party |\nproduct. This is the axis the two hanzo.app lanes are cut on.","schema":{"type":"string"},"example":"template"},{"name":"archetype","in":"query","required":false,"description":"Archetype narrows to one project archetype. Case-insensitive.","schema":{"type":"string"}},{"name":"language","in":"query","required":false,"description":"Language narrows to one implementation language. Case-insensitive.","schema":{"type":"string"},"example":"typescript"},{"name":"template","in":"query","required":false,"description":"Template narrows a lane to ONE lineage: the id of the parent everything\nreturned was forked from.","schema":{"type":"string"}},{"name":"forkable","in":"query","required":false,"description":"Forkable is tri-state: \"true\" selects the forkable rows, \"false\" selects the\nrest, and anything else — including absent — applies no filter at all.","schema":{"type":"string"},"example":"true"},{"name":"limit","in":"query","required":false,"description":"Limit caps the page at 200, default 50. A value that is not a non-negative\ninteger falls back to the default.","schema":{"type":"string"},"example":"20"},{"name":"offset","in":"query","required":false,"description":"Offset is where the page starts, default 0, with the same tolerance.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/catalog.catalogPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"catalog","x-public":true,"x-tool":true}},"/v1/channel":{"get":{"operationId":"get_channel","summary":"Reports every chat channel this org can send through, and whether it can send through it right now.","description":"Reports every chat channel this org can send through, and whether it can\nsend through it right now.\n\nA channel appears here whether or not it is connected — an empty list would\nleave a caller unable to tell \"this org has no Slack\" from \"Slack is down\",\nwhich are different problems with different fixes. Each entry carries the\nconnection behind it, so the answer to \"why can I not post?\" is in the same\nresponse as the channel that cannot post.","tags":["channel"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/channel.chatChannels"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"channel","x-public":true,"x-tool":true}},"/v1/channel/agent":{"get":{"operationId":"get_channel_agent","summary":"Returns which agent answers the caller org's channel: the default and every room bound to another agent.","description":"Returns which agent answers the caller org's channel: the default and\nevery room bound to another agent.","tags":["channel"],"parameters":[{"name":"channel","in":"query","required":false,"description":"Channel is the transport: discord, github, linear, slack, teams, telegram or whatsapp.\nRequired; an unknown value is a 404.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"channel":"slack","default":"eng","rooms":{"C024BE91L":"des"}},"schema":{"$ref":"#/components/schemas/channel.channelAgents"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"channel","x-public":true,"x-tool":true},"put":{"operationId":"put_channel_agent","summary":"Binds agents to the caller org's channel and answers the bindings as GET would.","description":"Binds agents to the caller org's channel and answers the bindings as\nGET would. It requires ORG ADMIN. The agent is named by its ref — the name an\norg gave it at POST /v1/agent, or a built-in such as dev, des or vi.","tags":["channel"],"requestBody":{"content":{"application/json":{"example":{"channel":"slack","default":"eng","rooms":{"C024BE91L":"des"},"unbind":["C0OLD"]},"schema":{"$ref":"#/components/schemas/channel.channelAgentsPut"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/channel.channelAgents"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"channel","x-public":true,"x-tool":true}},"/v1/channel/allowlist":{"get":{"operationId":"get_channel_allowlist","summary":"Returns the caller org's access policy for one channel: whether DMs are pairing-gated, allowlisted or open, whether group rooms are open, allowlisted or disabled, the config-managed DM and group allow entries, the senders approved through PAIRING (read-only here), and the org's named access groups.","description":"Returns the caller org's access policy for one channel: whether\nDMs are pairing-gated, allowlisted or open, whether group rooms are open,\nallowlisted or disabled, the config-managed DM and group allow entries, the\nsenders approved through PAIRING (read-only here), and the org's named access\ngroups. An unknown channel is a 404. The entries name the people the org's\nbots admit, so reading them is an org admin's, as editing them is.","tags":["channel"],"parameters":[{"name":"channel","in":"query","required":false,"description":"Channel is the transport to read: discord, github, linear, slack, teams, telegram or whatsapp.\nRequired; an unknown value is a 404.","schema":{"type":"string"},"example":"slack"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/channel.allowlistView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"channel","x-public":true,"x-tool":true},"put":{"operationId":"put_channel_allowlist","summary":"Edits the caller org's access policy for one channel and answers the policy as GET would, so both verbs return ONE shape.","description":"Edits the caller org's access policy for one channel and answers\nthe policy as GET would, so both verbs return ONE shape. It requires ORG ADMIN.\nEvery field but `channel` is optional and applied only when provided: an empty\npolicy string leaves that policy alone, an absent or null list leaves that list\nalone, and an EMPTY list clears it. It writes only CONFIG-sourced allow entries\n— senders approved through pairing belong to the approval flow, so a policy\nedit can never revoke one. An unknown channel is a 404.","tags":["channel"],"requestBody":{"content":{"application/json":{"example":{"channel":"slack","dm":["U024BE7LH"],"dmPolicy":"allowlist"},"schema":{"$ref":"#/components/schemas/channel.allowlistPutIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/channel.allowlistView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"channel","x-public":true,"x-tool":true}},"/v1/channel/inbox":{"get":{"operationId":"get_channel_inbox","summary":"Returns the caller's own messages to the org's connected chat bots — those recorded on the caller's linked account — oldest first, in the portable envelope shape every transport normalises into.","description":"Returns the caller's own messages to the org's connected chat bots —\nthose recorded on the caller's linked account — oldest first, in the portable\nenvelope shape every transport normalises into. It is a CURSOR feed, not a\nsearch: pass the returned cursor back as `since` to get only what has arrived\nsince. A message is its person's: another member's is never listed, an admin\nof the org reads only their own, and one recorded on no account is listed to a\nSuperAdmin alone.","tags":["channel"],"parameters":[{"name":"since","in":"query","required":false,"description":"Since is the exclusive cursor: only messages with a higher row id come\nback. Empty starts at the beginning. Must parse as an integer.","schema":{"type":"string"},"example":"1042"},{"name":"limit","in":"query","required":false,"description":"Limit caps how many messages come back. Empty or 0 uses the store's\ndefault page size. Must parse as an integer.","schema":{"type":"string"},"example":"100"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/channel.inboxPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"channel","x-public":true,"x-tool":true}},"/v1/channel/pairing":{"get":{"operationId":"get_channel_pairing","summary":"Returns the pairing requests waiting for the caller org to approve — one per person who messaged a connected bot on a channel whose DM policy is \"pairing\" and who is not allowed yet.","description":"Returns the pairing requests waiting for the caller org to approve\n— one per person who messaged a connected bot on a channel whose DM policy is\n\"pairing\" and who is not allowed yet. Each row carries the CODE an org admin\npasses to POST /v1/channel/pairing/approve. Expired requests are not\nreturned. Codes are capability strings: they are shown here, and never logged.\nReading them is an org admin's, as approving them is.","tags":["channel"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/channel.pairingQueue"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"channel","x-public":true,"x-tool":true}},"/v1/channel/pairing/approve":{"post":{"operationId":"post_channel_pairing_approve","summary":"Turns one pending pairing code into a standing allow entry, so that person can DM the org's bot on that channel from now on.","description":"Turns one pending pairing code into a standing allow entry, so\nthat person can DM the org's bot on that channel from now on. It requires ORG\nADMIN, not merely membership. The first approval an org makes on a channel also\nbootstraps that sender as the channel's owner, which the answer reports. An\nunknown or expired code is a 404, and a code always belongs to exactly one\norg, so it can never approve someone into another tenant.","tags":["channel"],"requestBody":{"content":{"application/json":{"example":{"channel":"telegram","code":"PAIR-7Q2M"},"schema":{"$ref":"#/components/schemas/channel.approvePairingIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/channel.pairingApproved"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"channel","x-public":true,"x-tool":true}},"/v1/channel/{channel}/send":{"post":{"operationId":"post_channel_by_channel_send","summary":"Send a message from your org's bot to one chat room","description":"Delivers text, attachments and actions to one room on a connected chat transport — discord, github, linear, slack, teams, telegram or whatsapp — and answers that transport's own receipt, the `messageId` it assigned and the Unix second it landed. An unknown channel is a 404.\n\nThe body is the envelope's NARROW outbound projection: `room`, `text`, `attachments`, `actions`, `replyTo` and `idempotency`, and nothing else. Identity is not a field — the channel is the path segment and the sender is the caller's validated org — so a body carrying `sender`, `account` or `channel` is refused with 400 rather than having it silently dropped. `room.id` is required, and so is something to say: text, or at least one attachment.\n\nRequires a validated principal; 401 without one. The room must already belong to the caller's org — each transport verifies the binding itself, so a room this org has not bound is 403 and a room whose route the bot has never learned is 409, meaning someone has to message the bot there first. A route learned only so a pairing reply could be delivered lasts exactly as long as that pairing request does, so a room whose sender was never approved goes back to 409 within the hour. A transport that fails answers 502 carrying status and shape only, never a token.\n\nSending is at-most-once only if you ask for it: pass an `idempotency` string and a replay answers 200 with the PRIOR receipt instead of sending twice, while a send that fails releases the key so the caller can re-attempt. Bodies over 1 MiB are refused. Every transport currently renders text only, so attachments and actions are flattened deterministically to one line each after the text rather than dropped.","tags":["channel"],"parameters":[{"name":"channel","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"channel","x-public":true}},"/v1/chat":{"post":{"operationId":"post_chat","summary":"Implements the OpenAI-compatible chat completions API","description":"Implements the OpenAI-compatible chat completions API","tags":["ai"],"parameters":[{"name":"X-Max-Cost","in":"header","required":false,"description":"The most this request may cost, in USD per 1,000 tokens. Routing picks only models under it; an org's own ceiling fills it when it is absent, and the lower of the two holds.","schema":{"minimum":0,"type":"number"}},{"name":"X-Max-Latency-Ms","in":"header","required":false,"description":"The slowest model this request accepts, in milliseconds.","schema":{"minimum":0,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/openai.ChatCompletionRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/openai.ChatCompletionResponse"},{"properties":{"routing":{"description":"What the router decided for this request and why, present when one routed it (a model Enso routes by reasoning depth). Every field is one the router read or wrote; it reports no score, expected cost or latency because it weighs none.","properties":{"candidates":{"description":"Each model the router's table names, with the reasoning depths that read it, shallow to deep.","items":{"properties":{"depths":{"items":{"type":"string"},"type":"array"},"model":{"type":"string"}},"required":["model","depths"],"type":"object"},"type":"array"},"chosen":{"description":"The model the request is served at.","type":"string"},"inputs":{"properties":{"depth":{"description":"The reasoning depth the request states; default when it states none.","type":"string"},"key":{"description":"The table row that depth was read at.","type":"string"},"policy":{"description":"Whether the caller's plan or credit pays for the paid model at that depth.","enum":["funded","unfunded","n/a"],"type":"string"}},"required":["depth","key","policy"],"type":"object"},"reason":{"description":"How the inputs led to chosen, in a sentence.","type":"string"},"router":{"description":"The router that decided: enso.","type":"string"}},"required":["router","chosen","candidates","inputs","reason"],"type":"object"}},"type":"object"}]}}},"description":"Success.","headers":{"X-Routed-Model":{"description":"The model that served a routed request, one that named auto or an id the router resolves. The body's model field names the same id.","schema":{"type":"string"}}}},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/chat/completions":{"post":{"operationId":"post_chat_completions","summary":"Implements the OpenAI-compatible chat completions API","description":"Implements the OpenAI-compatible chat completions API","tags":["ai"],"parameters":[{"name":"X-Max-Cost","in":"header","required":false,"description":"The most this request may cost, in USD per 1,000 tokens. Routing picks only models under it; an org's own ceiling fills it when it is absent, and the lower of the two holds.","schema":{"minimum":0,"type":"number"}},{"name":"X-Max-Latency-Ms","in":"header","required":false,"description":"The slowest model this request accepts, in milliseconds.","schema":{"minimum":0,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/openai.ChatCompletionRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/openai.ChatCompletionResponse"},{"properties":{"routing":{"description":"What the router decided for this request and why, present when one routed it (a model Enso routes by reasoning depth). Every field is one the router read or wrote; it reports no score, expected cost or latency because it weighs none.","properties":{"candidates":{"description":"Each model the router's table names, with the reasoning depths that read it, shallow to deep.","items":{"properties":{"depths":{"items":{"type":"string"},"type":"array"},"model":{"type":"string"}},"required":["model","depths"],"type":"object"},"type":"array"},"chosen":{"description":"The model the request is served at.","type":"string"},"inputs":{"properties":{"depth":{"description":"The reasoning depth the request states; default when it states none.","type":"string"},"key":{"description":"The table row that depth was read at.","type":"string"},"policy":{"description":"Whether the caller's plan or credit pays for the paid model at that depth.","enum":["funded","unfunded","n/a"],"type":"string"}},"required":["depth","key","policy"],"type":"object"},"reason":{"description":"How the inputs led to chosen, in a sentence.","type":"string"},"router":{"description":"The router that decided: enso.","type":"string"}},"required":["router","chosen","candidates","inputs","reason"],"type":"object"}},"type":"object"}]}}},"description":"Success.","headers":{"X-Routed-Model":{"description":"The model that served a routed request, one that named auto or an id the router resolves. The body's model field names the same id.","schema":{"type":"string"}}}},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/chat/public":{"post":{"operationId":"post_chat_public","summary":"Serves one completion to a caller with no account.","description":"Serves one completion to a caller with no account.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/openai.ChatCompletionRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/openai.ChatCompletionResponse"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/ci/fleet":{"get":{"operationId":"get_ci_fleet","summary":"Compares what was written with what is running, one row per service along a single causal line: head, the commit on the branch; built, the image that commit produced; declared, the tag pinned in the universe repository; running, what the cluster serves.","description":"Compares what was written with what is running, one row per service\nalong a single causal line: head, the commit on the branch; built, the image\nthat commit produced; declared, the tag pinned in the universe repository;\nrunning, what the cluster serves. A service whose four values disagree names\nthe step that broke.","tags":["ci"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ci.Pipelines"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ci","x-public":true,"x-tool":true}},"/v1/ci/runs":{"get":{"operationId":"get_ci_runs","summary":"Lists recent builds: the repo, the branch, the commit and how each run ended, newest first.","description":"Lists recent builds: the repo, the branch, the commit and how each run\nended, newest first. A run names a repo, a branch and an actor, so the list is\nnever wider than the caller — a SuperAdmin sees the fleet, an org member sees\nonly its own org.","tags":["ci"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ci.Executions"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ci","x-public":true,"x-tool":true}},"/v1/cloudflare/d1/databases":{"get":{"operationId":"get_cloudflare_d1_databases","summary":"Lists the D1 databases on the org's Cloudflare account.","description":"Lists the D1 databases on the org's Cloudflare account. Any org\nmember may read.","tags":["cloudflare"],"parameters":[{"name":"page","in":"query","required":false,"description":"Page is the 1-based page of databases to return.","schema":{"type":"string"}},{"name":"per_page","in":"query","required":false,"description":"PerPage is how many databases one page holds.","schema":{"type":"string"}},{"name":"name","in":"query","required":false,"description":"Name filters to the database with this name.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true},"post":{"operationId":"post_cloudflare_d1_databases","summary":"Creates a D1 database on the org's Cloudflare account.","description":"Creates a D1 database on the org's Cloudflare account.\nRequires org admin.","tags":["cloudflare"],"requestBody":{"content":{"application/json":{"example":{"name":"orders"},"schema":{"$ref":"#/components/schemas/cloudflare.databaseCreateIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/d1/databases/{database}":{"delete":{"operationId":"delete_cloudflare_d1_databases_by_database","summary":"Deletes a D1 database and everything stored in it.","description":"Deletes a D1 database and everything stored in it. Requires\norg admin.","tags":["cloudflare"],"parameters":[{"name":"database","in":"path","required":true,"description":"Database is the Cloudflare D1 database id or name.","schema":{"type":"string"},"example":"orders"}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/d1/databases/{database}/query":{"post":{"operationId":"post_cloudflare_d1_databases_by_database_query","summary":"Runs one SQL statement against a D1 database.","description":"Runs one SQL statement against a D1 database. It executes on the org's\nOWN Cloudflare account and relays D1's result set. The body is checked for a\nnon-empty `sql` and then forwarded VERBATIM, so every field D1 accepts reaches D1\neven though only two are named here.\n\nRequires ORG ADMIN — a statement may INSERT, UPDATE or DROP, so a query takes the\nwrite gate rather than the read one — and a caller who is only an org member is\nrefused 403. A missing `sql` is 400; 503 if the org has never connected a\nCloudflare token.","tags":["cloudflare"],"parameters":[{"name":"database","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"params":[42],"sql":"SELECT * FROM orders WHERE id = ?"},"schema":{"$ref":"#/components/schemas/cloudflare.D1Query"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/kv/namespaces":{"get":{"operationId":"get_cloudflare_kv_namespaces","summary":"Lists the Workers KV namespaces on the org's Cloudflare account.","description":"Lists the Workers KV namespaces on the org's Cloudflare\naccount. Any org member may read.","tags":["cloudflare"],"parameters":[{"name":"page","in":"query","required":false,"description":"Page is the 1-based page of namespaces to return.","schema":{"type":"string"}},{"name":"per_page","in":"query","required":false,"description":"PerPage is how many namespaces one page holds.","schema":{"type":"string"}},{"name":"order","in":"query","required":false,"description":"Order names the field to sort by, and Direction sorts asc or desc.","schema":{"type":"string"}},{"name":"direction","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true},"post":{"operationId":"post_cloudflare_kv_namespaces","summary":"Creates a Workers KV namespace on the org's Cloudflare account.","description":"Creates a Workers KV namespace on the org's Cloudflare\naccount. Requires org admin. Cloudflare mints the namespace id the value routes\naddress.","tags":["cloudflare"],"requestBody":{"content":{"application/json":{"example":{"title":"sessions"},"schema":{"$ref":"#/components/schemas/cloudflare.namespaceCreateIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/kv/namespaces/{namespace}":{"delete":{"operationId":"delete_cloudflare_kv_namespaces_by_namespace","summary":"Deletes a Workers KV namespace and every key in it.","description":"Deletes a Workers KV namespace and every key in it. Requires\norg admin.","tags":["cloudflare"],"parameters":[{"name":"namespace","in":"path","required":true,"description":"Namespace is the Cloudflare KV namespace id.","schema":{"type":"string"},"example":"0123456789abcdef0123456789abcdef"}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/kv/namespaces/{namespace}/values/{key}":{"delete":{"operationId":"delete_cloudflare_kv_namespaces_by_namespace_values_by_key","summary":"Removes one key from a Workers KV namespace.","description":"Removes one key from a Workers KV namespace. Requires org admin.","tags":["cloudflare"],"parameters":[{"name":"namespace","in":"path","required":true,"description":"Namespace is the Cloudflare KV namespace id.","schema":{"type":"string"},"example":"0123456789abcdef0123456789abcdef"},{"name":"key","in":"path","required":true,"description":"Key is the key within that namespace. KV keys are broad (up to 512 bytes),\nso this one is escaped rather than charset-restricted.","schema":{"type":"string"},"example":"session/abc"}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true},"get":{"operationId":"get_cloudflare_kv_namespaces_by_namespace_values_by_key","summary":"Read a Workers KV value as its stored bytes","description":"Answers one KV key's value from the org's OWN Cloudflare account as RAW BYTES under the content type it was written with — not wrapped in a JSON envelope, which is why this is not a typed op. Any org member may read. A key that does not exist is Cloudflare's own 404; an invalid namespace, or a key that is empty, over 512 bytes, not valid UTF-8, or carries a control character, is 400; 503 if the org has never connected a Cloudflare token.","tags":["cloudflare"],"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"cloudflare","x-public":true},"put":{"operationId":"put_cloudflare_kv_namespaces_by_namespace_values_by_key","summary":"Write a Workers KV value from the request body","description":"Stores one KV key on the org's OWN Cloudflare account. The REQUEST BODY IS THE VALUE, forwarded verbatim under the caller's own Content-Type (`text/plain` when none is sent), so a value is never re-encoded on the way in — which is why this is not a typed op. `expiration` and `expiration_ttl` may ride the query string and are passed through to Cloudflare. Requires ORG ADMIN (403 otherwise); the same namespace and key validation as the read answers 400; 503 if the org has never connected a Cloudflare token.","tags":["cloudflare"],"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"cloudflare","x-public":true}},"/v1/cloudflare/pages/projects":{"get":{"operationId":"get_cloudflare_pages_projects","summary":"Lists the org's Cloudflare Pages projects.","description":"Lists the org's Cloudflare Pages projects. Any org member may read.","tags":["cloudflare"],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true},"post":{"operationId":"post_cloudflare_pages_projects","summary":"Creates a Cloudflare Pages project on the org's account.","description":"Creates a Cloudflare Pages project on the org's account. Requires\norg admin. Only the modeled fields reach Cloudflare, so an unmodeled key in the\nrequest is dropped rather than forwarded.","tags":["cloudflare"],"requestBody":{"content":{"application/json":{"example":{"name":"marketing-site","production_branch":"main"},"schema":{"$ref":"#/components/schemas/cloudflare.PagesProjectCreate"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/pages/projects/{project}":{"delete":{"operationId":"delete_cloudflare_pages_projects_by_project","summary":"Deletes a Cloudflare Pages project, and with it every deployment it has ever made.","description":"Deletes a Cloudflare Pages project, and with it every deployment it\nhas ever made. Requires org admin.","tags":["cloudflare"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the Pages project name.","schema":{"type":"string"},"example":"marketing-site"}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true},"get":{"operationId":"get_cloudflare_pages_projects_by_project","summary":"Reads one Cloudflare Pages project — its build config, deployment configs and latest deployment.","description":"Reads one Cloudflare Pages project — its build config, deployment\nconfigs and latest deployment. Any org member may read.","tags":["cloudflare"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the Pages project name.","schema":{"type":"string"},"example":"marketing-site"}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/pages/projects/{project}/deployments":{"post":{"operationId":"post_cloudflare_pages_projects_by_project_deployments","summary":"Trigger a new Pages deployment for a project","description":"Starts a build and deployment of one Cloudflare Pages project on the org's OWN Cloudflare account, and relays Cloudflare's deployment record back. `branch` picks what to build; OMITTING it builds the project's production branch.\n\nA body it cannot parse is IGNORED rather than refused — the deployment falls back to the production branch — which is the one rule to get right here and the reason this is not a typed op: a typed request would answer 400 where this deploys. Requires ORG ADMIN (403 otherwise), and 503 if the org has never connected a Cloudflare token.","tags":["cloudflare"],"parameters":[{"name":"project","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagesDeploy"}}}},"responses":{"2XX":{"content":{"application/json":{"schema":{}}},"description":"Success"}},"x-app":"cloudflare","x-public":true}},"/v1/cloudflare/pages/projects/{project}/domains":{"post":{"operationId":"post_cloudflare_pages_projects_by_project_domains","summary":"Attaches a custom domain to a Cloudflare Pages project.","description":"Attaches a custom domain to a Cloudflare Pages project. Requires\norg admin. Cloudflare owns validation and certificate issuance from here on.","tags":["cloudflare"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the Pages project name, from the path.","schema":{"type":"string"},"example":"marketing-site"}],"requestBody":{"content":{"application/json":{"example":{"name":"www.acme.com","project":"marketing-site"},"schema":{"$ref":"#/components/schemas/cloudflare.domainAddIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/pages/projects/{project}/domains/{domain}":{"delete":{"operationId":"delete_cloudflare_pages_projects_by_project_domains_by_domain","summary":"Detaches a custom domain from a Cloudflare Pages project.","description":"Detaches a custom domain from a Cloudflare Pages project.\nRequires org admin.","tags":["cloudflare"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the Pages project name.","schema":{"type":"string"},"example":"marketing-site"},{"name":"domain","in":"path","required":true,"description":"Domain is the attached custom domain to detach.","schema":{"type":"string"},"example":"www.acme.com"}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/r2/buckets":{"get":{"operationId":"get_cloudflare_r2_buckets","summary":"Lists the R2 buckets on the org's Cloudflare account.","description":"Lists the R2 buckets on the org's Cloudflare account. Any org\nmember may read.","tags":["cloudflare"],"parameters":[{"name":"per_page","in":"query","required":false,"description":"PerPage is how many buckets one page holds.","schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"description":"Cursor continues from the position a previous page returned.","schema":{"type":"string"}},{"name":"name_contains","in":"query","required":false,"description":"NameContains filters to buckets whose name contains this substring.","schema":{"type":"string"}},{"name":"order","in":"query","required":false,"description":"Order names the field to sort by, and Direction sorts asc or desc.","schema":{"type":"string"}},{"name":"direction","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true},"post":{"operationId":"post_cloudflare_r2_buckets","summary":"Creates an R2 bucket on the org's Cloudflare account.","description":"Creates an R2 bucket on the org's Cloudflare account. Requires\norg admin.","tags":["cloudflare"],"requestBody":{"content":{"application/json":{"example":{"name":"assets"},"schema":{"$ref":"#/components/schemas/cloudflare.bucketCreateIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/r2/buckets/{bucket}":{"delete":{"operationId":"delete_cloudflare_r2_buckets_by_bucket","summary":"Deletes an R2 bucket.","description":"Deletes an R2 bucket. Requires org admin. Cloudflare refuses a\nbucket that still holds objects, and that refusal is relayed.","tags":["cloudflare"],"parameters":[{"name":"bucket","in":"path","required":true,"description":"Bucket is the R2 bucket name.","schema":{"type":"string"},"example":"assets"}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/workers/scripts":{"get":{"operationId":"get_cloudflare_workers_scripts","summary":"Lists the Worker scripts on the org's Cloudflare account.","description":"Lists the Worker scripts on the org's Cloudflare account. Any\norg member may read.","tags":["cloudflare"],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/workers/scripts/{script}":{"delete":{"operationId":"delete_cloudflare_workers_scripts_by_script","summary":"Removes a Worker script from the org's Cloudflare account.","description":"Removes a Worker script from the org's Cloudflare account.\nRequires org admin. Routes bound to the script stop serving it.","tags":["cloudflare"],"parameters":[{"name":"script","in":"path","required":true,"description":"Script is the Worker script name.","schema":{"type":"string"},"example":"edge-router"}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true},"put":{"operationId":"put_cloudflare_workers_scripts_by_script","summary":"Uploads or replaces a module Worker script.","description":"Uploads or replaces a module Worker script. It publishes to the\norg's OWN Cloudflare account under the name in the path, replacing whatever was\nthere, and relays Cloudflare's result. The compatibility date, compatibility\nflags and bindings are packed into the multipart upload Cloudflare expects,\nbeside the module source.\n\nRequires ORG ADMIN — a Worker is arbitrary code on the org's own account and\ndomains — so a caller who is only an org member is refused 403. An empty source\nis 400, as is a `mainModule` that is not a plain file name; 503 if the org has\nnever connected a Cloudflare token.","tags":["cloudflare"],"parameters":[{"name":"script","in":"path","required":true,"description":"Script means two things on this route, and the document says so in both places\nit appears: the PATH segment names the Worker to publish, and the BODY field\ncarries that Worker's ES-module source — the code itself, never a name or a\nURL. A blank or absent source is refused; there is no empty Worker.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/cloudflare.WorkerScriptPut"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/workers/scripts/{script}/subdomain":{"post":{"operationId":"post_cloudflare_workers_scripts_by_script_subdomain","summary":"Publishes or withdraws one Worker script on the account's workers.dev subdomain.","description":"Publishes or withdraws one Worker script on the\naccount's workers.dev subdomain. Requires org admin.","tags":["cloudflare"],"parameters":[{"name":"script","in":"path","required":true,"description":"Script is the Worker script name, from the path.","schema":{"type":"string"},"example":"edge-router"}],"requestBody":{"content":{"application/json":{"example":{"enabled":true,"script":"edge-router"},"schema":{"$ref":"#/components/schemas/cloudflare.subdomainSetIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/workers/subdomain":{"get":{"operationId":"get_cloudflare_workers_subdomain","summary":"Reads the org account's workers.dev subdomain — the name under which every subdomain-enabled script is served.","description":"Reads the org account's workers.dev subdomain — the name\nunder which every subdomain-enabled script is served. Any org member may read.","tags":["cloudflare"],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/workers/zones/{zone}/routes":{"get":{"operationId":"get_cloudflare_workers_zones_by_zone_routes","summary":"Lists the Worker routes bound within one zone — the URL patterns that dispatch to a script.","description":"Lists the Worker routes bound within one zone — the URL\npatterns that dispatch to a script. Any org member may read. Routes are\nzone-scoped, so no account is resolved.","tags":["cloudflare"],"parameters":[{"name":"zone","in":"path","required":true,"description":"Zone is the 32-hex Cloudflare zone id.","schema":{"type":"string"},"example":"0123456789abcdef0123456789abcdef"}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true},"post":{"operationId":"post_cloudflare_workers_zones_by_zone_routes","summary":"Binds a URL pattern in a zone to a Worker script.","description":"Binds a URL pattern in a zone to a Worker script. Requires\norg admin — a route is what puts a script in front of live traffic.","tags":["cloudflare"],"parameters":[{"name":"zone","in":"path","required":true,"description":"Zone is the 32-hex Cloudflare zone id, from the path.","schema":{"type":"string"},"example":"0123456789abcdef0123456789abcdef"}],"requestBody":{"content":{"application/json":{"example":{"pattern":"acme.com/api/*","script":"edge-router","zone":"0123456789abcdef0123456789abcdef"},"schema":{"$ref":"#/components/schemas/cloudflare.routeCreateIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/workers/zones/{zone}/routes/{route}":{"delete":{"operationId":"delete_cloudflare_workers_zones_by_zone_routes_by_route","summary":"Unbinds a Worker route, so its pattern stops dispatching to a script.","description":"Unbinds a Worker route, so its pattern stops dispatching to a\nscript. Requires org admin.","tags":["cloudflare"],"parameters":[{"name":"zone","in":"path","required":true,"description":"Zone is the 32-hex Cloudflare zone id.","schema":{"type":"string"},"example":"0123456789abcdef0123456789abcdef"},{"name":"route","in":"path","required":true,"description":"Route is the 32-hex Cloudflare route id.","schema":{"type":"string"},"example":"fedcba9876543210fedcba9876543210"}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/zones":{"get":{"operationId":"get_cloudflare_zones","summary":"Lists the Cloudflare zones the org's connected API token can see, paged and filtered by the query parameters Cloudflare itself accepts.","description":"Lists the Cloudflare zones the org's connected API token can see,\npaged and filtered by the query parameters Cloudflare itself accepts. Zones are\ntoken-scoped by Cloudflare, so no account is resolved. Any org member may read.\n\nZone and DNS-record MANAGEMENT is not here: it stays on the Hanzo DNS plane\n(/v1/dns). This only surfaces the Cloudflare zone objects the asset plane needs\n— a zone id is what addresses a Worker route or an analytics read.","tags":["cloudflare"],"parameters":[{"name":"page","in":"query","required":false,"description":"Page is the 1-based page of zones to return.","schema":{"type":"string"}},{"name":"per_page","in":"query","required":false,"description":"PerPage is how many zones one page holds.","schema":{"type":"string"}},{"name":"name","in":"query","required":false,"description":"Name filters to the zone with this domain name.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Status filters by zone status (active, pending, initializing, …).","schema":{"type":"string"}},{"name":"order","in":"query","required":false,"description":"Order names the field to sort by, and Direction sorts asc or desc.","schema":{"type":"string"}},{"name":"direction","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/zones/{zone}":{"get":{"operationId":"get_cloudflare_zones_by_zone","summary":"Reads one Cloudflare zone the org's token can see.","description":"Reads one Cloudflare zone the org's token can see. Any org member may\nread. A zone id the token cannot see is Cloudflare's own not-found, relayed.","tags":["cloudflare"],"parameters":[{"name":"zone","in":"path","required":true,"description":"Zone is the 32-hex Cloudflare zone id.","schema":{"type":"string"},"example":"0123456789abcdef0123456789abcdef"}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/zones/{zone}/analytics":{"get":{"operationId":"get_cloudflare_zones_by_zone_analytics","summary":"Reads a zone's Cloudflare traffic dashboard — requests, bandwidth, threats and pageviews over the since/until window.","description":"Reads a zone's Cloudflare traffic dashboard — requests, bandwidth,\nthreats and pageviews over the since/until window. Any org member may read.\n\nA zone whose Cloudflare plan does not serve this endpoint yields Cloudflare's\nOWN error, never a fabricated success.","tags":["cloudflare"],"parameters":[{"name":"zone","in":"path","required":true,"description":"Zone is the 32-hex Cloudflare zone id.","schema":{"type":"string"},"example":"0123456789abcdef0123456789abcdef"},{"name":"since","in":"query","required":false,"description":"Since and Until bound the window, in the form Cloudflare accepts — an RFC 3339\ntime or a negative number of minutes from now (\"-1440\" is the last day).","schema":{"type":"string"},"example":"-1440"},{"name":"until","in":"query","required":false,"schema":{"type":"string"},"example":"0"},{"name":"continuous","in":"query","required":false,"description":"Continuous asks Cloudflare for only fully-aggregated buckets.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/cloudflare/zones/{zone}/purge":{"post":{"operationId":"post_cloudflare_zones_by_zone_purge","summary":"Drops a zone's Cloudflare edge cache — either the whole zone (purge_everything) or exactly the listed file URLs.","description":"Drops a zone's Cloudflare edge cache — either the whole zone\n(purge_everything) or exactly the listed file URLs. Requires org admin.\n\nPurging is the one zone-scoped WRITE this plane owns. It is not DNS — no record\nchanges — so it does not belong on /v1/dns, and it is not a connection, so it does\nnot belong on the integrations plane. It is a cache operation on a zone, which is\nwhat this asset plane is for. It takes the admin gate because dropping a zone's\ncache sends every subsequent request to the origin: on a site fronting a small\norigin that is a self-inflicted load spike, so it is a change, not a look.\n\nExactly one selector is required. Cloudflare treats a body with neither as a\nno-op and answers 200, which reads as \"purged\" to a caller that never purged\nanything — the failure we refuse to pass through.","tags":["cloudflare"],"parameters":[{"name":"zone","in":"path","required":true,"description":"Zone is the 32-hex Cloudflare zone id, from the path.","schema":{"type":"string"},"example":"0123456789abcdef0123456789abcdef"}],"requestBody":{"content":{"application/json":{"example":{"purge_everything":true,"zone":"0123456789abcdef0123456789abcdef"},"schema":{"$ref":"#/components/schemas/cloudflare.purgeIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"cloudflare","x-public":true,"x-tool":true}},"/v1/code/ask":{"get":{"operationId":"get_code_ask","summary":"Answers a question about the caller org's code with a CITED answer: retrieval packs grounding context, then the synthesizer writes the answer over exactly those spans, which come back alongside it.","description":"Answers a question about the caller org's code with a CITED answer:\nretrieval packs grounding context, then the synthesizer writes the answer over\nexactly those spans, which come back alongside it. It never answers without\ngrounding — with no matched code the answer is empty and says so, and with no\nsynthesizer available the citations still come back with \"degraded\": true so\nthe caller can reason over the spans itself.","tags":["code"],"parameters":[{"name":"q","in":"query","required":false,"description":"Q is the question to answer. Required, max 4000 bytes.","schema":{"type":"string"},"example":"where is the per-org SQLite file opened"},{"name":"repo","in":"query","required":false,"description":"Repo narrows retrieval to one repository. Empty searches every repo the org\nhas indexed.","schema":{"type":"string"},"example":"cloud"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/code.AskAnswer"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"code","x-public":true,"x-tool":true},"post":{"operationId":"post_code_ask","summary":"Answers a question about the caller org's code with a CITED answer, taking the question from the request BODY, for a question too long or too awkward to put in a URL.","description":"Answers a question about the caller org's code with a CITED answer,\ntaking the question from the request BODY, for a question too long or too\nawkward to put in a URL. `query` and `repo` in the body take precedence over\n`?q=` and `?repo=`; either source works alone.","tags":["code"],"requestBody":{"content":{"application/json":{"example":{"query":"where is the per-org SQLite file opened","repo":"cloud"},"schema":{"$ref":"#/components/schemas/code.askPostIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/code.AskAnswer"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"code","x-public":true,"x-tool":true}},"/v1/code/context":{"post":{"operationId":"post_code_context","summary":"Packs the most relevant code for a query into a token budget — THE primitive for a coding agent that has to decide what to put in a prompt.","description":"Packs the most relevant code for a query into a token budget — THE\nprimitive for a coding agent that has to decide what to put in a prompt. It\nretrieves seed spans, expands each with the definitions it calls and its key\ncallers, then greedily fills the budget, so the answer is a coherent slice of\nthe codebase rather than a list of disconnected matches. The top match is\nalways included, truncated if it alone overflows, so a matched query never\ncomes back empty. A retrieval outage answers 200 with an empty bundle rather\nthan a 5xx.","tags":["code"],"requestBody":{"content":{"application/json":{"example":{"budgetTokens":4000,"query":"how does the store open a per-org database","repo":"cloud"},"schema":{"$ref":"#/components/schemas/code.contextIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/code.ContextBundle"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"code","x-public":true,"x-tool":true}},"/v1/code/file":{"get":{"operationId":"get_code_file","summary":"Returns the INDEXED content of one file — read_file over the chunks the search tiers hold, for pulling up code an agent just found.","description":"Returns the INDEXED content of one file — read_file over the chunks the\nsearch tiers hold, for pulling up code an agent just found. It is NOT\nbyte-verbatim: the git object plane is the source of record for exact bytes,\nhistory and blame. A file absent from the index is a 404, so an agent can tell\n\"not indexed\" from \"empty file\".","tags":["code"],"parameters":[{"name":"path","in":"query","required":false,"description":"Path is the file's repo-relative path. Required.","schema":{"type":"string"},"example":"apps/code/store.go"},{"name":"repo","in":"query","required":false,"description":"Repo is the repository the file belongs to. REQUIRED.","schema":{"type":"string"},"example":"cloud"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/code.fileContent"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"code","x-public":true,"x-tool":true}},"/v1/code/index":{"post":{"operationId":"post_code_index","summary":"(re)indexes a repository for the caller's org, incrementally: files whose content hash is unchanged are skipped, so re-sending a whole tree is cheap.","description":"(re)indexes a repository for the caller's org, incrementally: files whose\ncontent hash is unchanged are skipped, so re-sending a whole tree is cheap.\nEach file is parsed for symbols, split at AST boundaries and — when the\nsemantic tier is available — embedded, which is what makes it searchable across\nall three retrieval tiers. Pass `prune` to also DELETE indexed files absent\nfrom the request, which turns the call into a full sync; without it the call is\nan upsert. The index is written to the caller org's own physically separate\ndatabase.","tags":["code"],"requestBody":{"content":{"application/json":{"example":{"files":[{"content":"package main\n","path":"main.go"}],"prune":true,"repo":"cloud"},"schema":{"$ref":"#/components/schemas/code.indexIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/code.indexResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"code","x-public":true,"x-tool":true}},"/v1/code/search":{"get":{"operationId":"get_code_search","summary":"Finds code in the caller org's index across three orthogonal retrieval tiers fused by reciprocal-rank fusion: lexical (FTS5 trigram over code-tokenized text), symbolic (real definition and reference edges), and semantic (embedding cosine over AST-boundary chunks).","description":"Finds code in the caller org's index across three orthogonal retrieval\ntiers fused by reciprocal-rank fusion: lexical (FTS5 trigram over\ncode-tokenized text), symbolic (real definition and reference edges), and\nsemantic (embedding cosine over AST-boundary chunks). Pick one tier with\n`type`, or leave it to run all three as hybrid, which is what a coding agent\nusually wants. It is FAIL-HONEST: a retrieval outage answers 200 with an empty\nresult set and \"degraded\": true rather than a 5xx, so an agent degrades instead\nof stalling. A malformed regex is a 400.","tags":["code"],"parameters":[{"name":"q","in":"query","required":false,"description":"Q is the search query. Required, max 4000 bytes. For type=regex it is a\nregular expression; for type=symbol it is a symbol name.","schema":{"type":"string"},"example":"func openStore"},{"name":"type","in":"query","required":false,"description":"Type selects the retrieval tier: \"text\" (FTS5 trigram), \"regex\",\n\"symbol\" (definitions), \"semantic\" (embeddings) or \"hybrid\". Anything\nelse — including empty — reads as hybrid.","schema":{"type":"string"},"example":"hybrid"},{"name":"repo","in":"query","required":false,"description":"Repo narrows to one repository. Empty searches every repo the org has indexed.","schema":{"type":"string"},"example":"cloud"},{"name":"limit","in":"query","required":false,"description":"Limit caps how many spans come back: default 20, maximum 100. A value that\nis not a positive integer reads as the default.","schema":{"format":"int64","type":"integer"},"example":20}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/code.searchResults"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"code","x-public":true,"x-tool":true}},"/v1/code/tree":{"get":{"operationId":"get_code_tree","summary":"Returns one repository's file structure with a per-file symbol count — get_repo_structure over the org's own index, with no git checkout involved.","description":"Returns one repository's file structure with a per-file symbol count —\nget_repo_structure over the org's own index, with no git checkout involved. A\nrepository that has not been indexed answers an empty tree rather than an\nerror, so an agent can tell \"nothing here\" without handling a failure.","tags":["code"],"parameters":[{"name":"repo","in":"query","required":false,"description":"Repo is the repository to walk. REQUIRED — a tree is repo-scoped.","schema":{"type":"string"},"example":"cloud"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/code.repoTree"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"code","x-public":true,"x-tool":true}},"/v1/commerce/cart":{"post":{"operationId":"openCart","summary":"Open a cart for a shopper to fill","description":"Opens an empty cart for a shopper to fill, and answers it with its new id.\n\nThis is the first step of a sale: hold the id, add items to it with\nsetCartItem, then hand it to checkout. Every field of the request is optional —\nan empty body opens a perfectly good anonymous cart — and the fields exist only\nto pre-fill what is already known about the shopper.\n\nThe STORE defaults to the org's own default storefront, so a merchant selling\nthrough one storefront never has to name it. The CURRENCY defaults to usd; note\nthat checkout overrides it with the store's own currency when the sale is\nauthorized, so a currency set here is a hint rather than a commitment.\n\nThe cart is created in the CALLER'S OWN org namespace, taken from the validated\nprincipal and never from the body, so a cart can never be opened on another\ntenant's books.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["commerce"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CartOpen"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Cart"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"commerce","x-public":true,"x-tool":true}},"/v1/commerce/cart/{id}":{"get":{"operationId":"getCart","summary":"Read one cart with its lines and totals","description":"Reads one cart: its lines, its status and what it comes to.\n\nThis is what a storefront calls to render the basket, and what a support agent\ncalls to see what a shopper is looking at. The totals are the cart's STORED\ntally — shipping and tax stay zero until checkout resolves a shipping option\nand a tax region, so a cart total before checkout is the merchandise total and\nis meant to be.\n\nThe org scopes the read by construction: the store is namespaced to it, so a\ncart id belonging to another tenant is simply not found rather than found and\nthen filtered, and answers 404 rather than 403 so the id space cannot be probed.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["commerce"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the cart's id, as the open call answered it.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Cart"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"commerce","x-public":true,"x-tool":true}},"/v1/commerce/cart/{id}/discard":{"post":{"operationId":"discardCart","summary":"Discard a cart the shopper abandoned","description":"Discards a cart the shopper abandoned, and answers it in its final state.\n\nA discarded cart is CLOSED, not deleted: the row stays, so abandoned-basket\nreporting and any follow-up that keys on it still have something to read. It\nstops being a cart anything will check out, which is the point — it is how a\nstorefront says \"this basket is over\" without destroying the evidence that it\nexisted.\n\nDiscarding is idempotent: a cart already discarded answers its stored state\nrather than failing, so a retry is safe.\n\nThe cart is resolved inside the caller's own org namespace, so another tenant's\nid answers 404.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["commerce"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the cart's id, as the open call answered it.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Cart"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"commerce","x-public":true,"x-tool":true}},"/v1/commerce/cart/{id}/item":{"post":{"operationId":"setCartItem","summary":"Set one item's quantity in a cart; zero removes it","description":"Sets how many of one item a cart holds, and answers the whole updated cart.\n\nThis is the ONE way a cart's contents change. The quantity is the RESULT, not a\ndelta: sending 3 leaves 3 however many were there before, so a retry is safe and\na double-submit cannot double an order. ZERO REMOVES the line — there is\ndeliberately no separate delete, because removal is the same act at the boundary\nvalue and a second spelling would be a second set of edge cases.\n\nName the item with EITHER product OR variant, never both. Prefer variant for\nanything sold in sizes, colours or tiers: the price and the stock belong to the\nvariant, so a product-level line on a varianted product prices the wrong thing.\nEither may be given as an id or as the human key — a product's URL slug, a\nvariant's SKU — which is what lets a storefront add to cart straight from a\nproduct page URL without a lookup first.\n\nThe item's price and name are CACHED onto the line as it is added, so the cart\nkeeps the price the shopper was shown even if the catalog moves underneath it.\n\nAn item that resolves to nothing in the catalog is refused 400 and the cart is\nleft exactly as it was; nothing is partially applied.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["commerce"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the cart to amend, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CartItemSet"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Cart"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"commerce","x-public":true,"x-tool":true}},"/v1/commerce/catalog":{"get":{"operationId":"get_commerce_catalog","summary":"The public product catalog projection for a brand","description":"Returns the brand's published catalog — the shared source docs, the console sidebar and the pricing pages all read — with the brand taken from the query and defaulting to hanzo. It is public and cacheable, and it is the projection that deliberately omits cost and margin; those live only on the platform-admin projection.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/catalog/models":{"post":{"operationId":"post_commerce_catalog_models","summary":"Land a syncer's view of the model catalog: upstream costs and machine facts","description":"Takes a batch of model rows and upserts each one's upstream COST and machine-observable facts, answering what was created and changed. It deliberately touches nothing a human owns — not the retail price, not the markup, not the entitlement tier — so a sync can never overwrite an administrator's pricing decision. The gate is a PLATFORM principal rather than a platform ADMIN, because the caller is normally a scheduled job — the platform's own application, an IAM identity under the admin org.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/catalog/models/refresh":{"post":{"operationId":"post_commerce_catalog_models_refresh","summary":"Refresh the model catalog by reading the upstream provider","description":"Pulls the upstream model list and lands it through the same upsert the push endpoint uses, so the rule that a sync owns cost and an administrator owns price holds no matter which endpoint a row came through. It takes no body — the upstream is READ rather than told. If that upstream cannot be read the call answers 502 and writes NOTHING: a sync that cannot see its source must never conclude the source is empty, because that conclusion would withdraw every model on sale. The gate is a PLATFORM principal so the scheduled job's application identity qualifies.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/collection":{"get":{"operationId":"get_commerce_collection","summary":"List your org's collections, as a page","description":"A collection is a merchandising group a storefront renders — a slug and name, copy and media, flat lists of the product and variant ids it holds, published, preorder and out-of-stock flags, and an availability window. Membership lives on the collection as those id lists rather than as a join, so putting a product into a collection is a write here and not on the product. Answers a pagination envelope — the page and display echoed back, the rows under models, a total count and a facets array — read from the caller org's own namespaced store, so one tenant can never list another's. Sorting defaults to the slug and is overridable with sort. display is the page size and page applies only alongside it; either one that is not a positive integer is refused with 500 rather than silently ignored, and the limit query overrides the reported COUNT only, never the rows returned. No search backend is wired, so the datastore is the one and only list path and facets is always empty. A request resolving no org namespace is served an EMPTY page rather than an unscoped scan: the namespace IS the tenant filter, so without one there is nothing safe to return. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The token must also carry Admin or the Collection list scope.","tags":["commerce"],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_collection","summary":"Create a collection","description":"A collection is a merchandising group a storefront renders — a slug and name, copy and media, flat lists of the product and variant ids it holds, published, preorder and out-of-stock flags, and an availability window. Membership lives on the collection as those id lists rather than as a join, so putting a product into a collection is a write here and not on the product. Decodes the body into a new row in the caller org's own namespaced store — isolated to that tenant from its first write — and answers the stored row at 201 with a Location header naming its id. The id is assigned by the store, not taken from the body. A body that fails to decode is 400 and a store that refuses the write is 500. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The token must also carry Admin or WriteCollection.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/collection/{collectionid}":{"delete":{"operationId":"delete_commerce_collection_by_collectionid","summary":"Delete a collection, keeping a recoverable copy","description":"A collection is a merchandising group a storefront renders — a slug and name, copy and media, flat lists of the product and variant ids it holds, published, preorder and out-of-stock flags, and an availability window. Membership lives on the collection as those id lists rather than as a join, so putting a product into a collection is a write here and not on the product. Removes the addressed row and answers 204 with no body. Before the live row goes it is written once more under a deleted tombstone kind, so a deletion leaves a recoverable copy rather than destroying the record outright — and a tombstone that cannot be written fails the call with 500 before anything is removed. The id is resolved inside the caller org's own namespace, so an absent or foreign id is 404. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The token must also carry Admin or WriteCollection.","tags":["commerce"],"parameters":[{"name":"collectionid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"get":{"operationId":"get_commerce_collection_by_collectionid","summary":"Fetch one collection","description":"A collection is a merchandising group a storefront renders — a slug and name, copy and media, flat lists of the product and variant ids it holds, published, preorder and out-of-stock flags, and an availability window. Membership lives on the collection as those id lists rather than as a join, so putting a product into a collection is a write here and not on the product. Reads the addressed row from the caller org's own namespaced store. An id that is not there is 404 — and another tenant's id is not there by construction, so it reads exactly like a typo instead of confirming the row exists somewhere else. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The token must also carry Admin or ReadCollection.","tags":["commerce"],"parameters":[{"name":"collectionid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"patch":{"operationId":"patch_commerce_collection_by_collectionid","summary":"Change part of a collection","description":"A collection is a merchandising group a storefront renders — a slug and name, copy and media, flat lists of the product and variant ids it holds, published, preorder and out-of-stock flags, and an availability window. Membership lives on the collection as those id lists rather than as a join, so putting a product into a collection is a write here and not on the product. Loads the stored row and decodes the body OVER it, so only the fields the body names change and everything else keeps its stored value — the difference from the full replace, which clears what it is not told. Answers the merged row. An id absent from the caller org's namespace is 404 and a body that fails to decode is 400. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The token must also carry Admin, or ReadCollection and WriteCollection together.","tags":["commerce"],"parameters":[{"name":"collectionid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_collection_by_collectionid","summary":"Method-override tunnel for a collection — for clients that cannot send PUT, PATCH or DELETE","description":"A collection is a merchandising group a storefront renders — a slug and name, copy and media, flat lists of the product and variant ids it holds, published, preorder and out-of-stock flags, and an availability window. Membership lives on the collection as those id lists rather than as a join, so putting a product into a collection is a write here and not on the product. Re-dispatches the request into the handler the intended verb would have reached, taking that verb from a _method form value or query parameter and then from the X-HTTP-Method-Override header. PUT replaces the row, PATCH changes part of it, DELETE removes it, and anything else is 405. The trap is the DEFAULT: naming no override at all leaves the method POST, which this tunnel maps to the PARTIAL UPDATE — it is never a create, and creating is the collection root's job. Behaviour and authorization are the underlying operation's, since the real handler runs. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through.","tags":["commerce"],"parameters":[{"name":"collectionid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"put":{"operationId":"put_commerce_collection_by_collectionid","summary":"Replace a collection outright","description":"A collection is a merchandising group a storefront renders — a slug and name, copy and media, flat lists of the product and variant ids it holds, published, preorder and out-of-stock flags, and an availability window. Membership lives on the collection as those id lists rather than as a join, so putting a product into a collection is a write here and not on the product. This is a true REPLACEMENT, not a merge: the stored row's key is preserved, but the body is decoded onto a FRESH entity, so every field the body omits is written back as its ZERO value. Patch is the verb for changing part of a row. The id is resolved inside the caller org's own namespace and an absent one is 404 before anything is written; a body that fails to decode is 400. Answers the stored result. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The token must also carry Admin, or ReadCollection and WriteCollection together.","tags":["commerce"],"parameters":[{"name":"collectionid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/currencies":{"get":{"operationId":"get_commerce_currencies","summary":"The reference currency list the price and settings pickers render","description":"Returns every reference currency as one global list, so a store settings form or a product price picker binds real rows instead of a hardcoded array. It is a default-namespace read shared by every tenant rather than per-org data, and it is public and cacheable.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/disclosure":{"get":{"operationId":"get_commerce_disclosure","summary":"List your org's disclosures, as a page","description":"A disclosure is a published-document record — a publication body, a content hash, a type and a named receiver. The hash LOOKS like a field you set and is in fact derived, but only on update: a freshly created disclosure keeps whatever hash the caller sent until the first replace or patch recomputes it, so a new row's hash attests to nothing. This kind lives in commerce's demo tree — a live writable resource in your tenant's real store that nothing else in commerce reads. Answers a pagination envelope — the page and display echoed back, the rows under models, a total count and a facets array — read from the caller org's own namespaced store, so one tenant can never list another's. Sorting defaults to the last-updated time and is overridable with sort. display is the page size and page applies only alongside it; either one that is not a positive integer is refused with 500 rather than silently ignored, and the limit query overrides the reported COUNT only, never the rows returned. No search backend is wired, so the datastore is the one and only list path and facets is always empty. A request resolving no org namespace is served an EMPTY page rather than an unscoped scan: the namespace IS the tenant filter, so without one there is nothing safe to return. Any valid access token reaches it. The per-kind permission table has no entry for disclosure, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_disclosure","summary":"Create a disclosure","description":"A disclosure is a published-document record — a publication body, a content hash, a type and a named receiver. The hash LOOKS like a field you set and is in fact derived, but only on update: a freshly created disclosure keeps whatever hash the caller sent until the first replace or patch recomputes it, so a new row's hash attests to nothing. This kind lives in commerce's demo tree — a live writable resource in your tenant's real store that nothing else in commerce reads. Decodes the body into a new row in the caller org's own namespaced store — isolated to that tenant from its first write — and answers the stored row at 201 with a Location header naming its id. The id is assigned by the store, not taken from the body. A body that fails to decode is 400 and a store that refuses the write is 500. Any valid access token reaches it. The per-kind permission table has no entry for disclosure, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/disclosure/{disclosureid}":{"delete":{"operationId":"delete_commerce_disclosure_by_disclosureid","summary":"Delete a disclosure, keeping a recoverable copy","description":"A disclosure is a published-document record — a publication body, a content hash, a type and a named receiver. The hash LOOKS like a field you set and is in fact derived, but only on update: a freshly created disclosure keeps whatever hash the caller sent until the first replace or patch recomputes it, so a new row's hash attests to nothing. This kind lives in commerce's demo tree — a live writable resource in your tenant's real store that nothing else in commerce reads. Removes the addressed row and answers 204 with no body. Before the live row goes it is written once more under a deleted tombstone kind, so a deletion leaves a recoverable copy rather than destroying the record outright — and a tombstone that cannot be written fails the call with 500 before anything is removed. The id is resolved inside the caller org's own namespace, so an absent or foreign id is 404. Any valid access token reaches it. The per-kind permission table has no entry for disclosure, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"disclosureid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"get":{"operationId":"get_commerce_disclosure_by_disclosureid","summary":"Fetch one disclosure","description":"A disclosure is a published-document record — a publication body, a content hash, a type and a named receiver. The hash LOOKS like a field you set and is in fact derived, but only on update: a freshly created disclosure keeps whatever hash the caller sent until the first replace or patch recomputes it, so a new row's hash attests to nothing. This kind lives in commerce's demo tree — a live writable resource in your tenant's real store that nothing else in commerce reads. Reads the addressed row from the caller org's own namespaced store. An id that is not there is 404 — and another tenant's id is not there by construction, so it reads exactly like a typo instead of confirming the row exists somewhere else. Any valid access token reaches it. The per-kind permission table has no entry for disclosure, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"disclosureid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"patch":{"operationId":"patch_commerce_disclosure_by_disclosureid","summary":"Change part of a disclosure","description":"A disclosure is a published-document record — a publication body, a content hash, a type and a named receiver. The hash LOOKS like a field you set and is in fact derived, but only on update: a freshly created disclosure keeps whatever hash the caller sent until the first replace or patch recomputes it, so a new row's hash attests to nothing. This kind lives in commerce's demo tree — a live writable resource in your tenant's real store that nothing else in commerce reads. Loads the stored row and decodes the body OVER it, so only the fields the body names change and everything else keeps its stored value — the difference from the full replace, which clears what it is not told. Answers the merged row. An id absent from the caller org's namespace is 404 and a body that fails to decode is 400. Any valid access token reaches it. The per-kind permission table has no entry for disclosure, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"disclosureid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_disclosure_by_disclosureid","summary":"Method-override tunnel for a disclosure — for clients that cannot send PUT, PATCH or DELETE","description":"A disclosure is a published-document record — a publication body, a content hash, a type and a named receiver. The hash LOOKS like a field you set and is in fact derived, but only on update: a freshly created disclosure keeps whatever hash the caller sent until the first replace or patch recomputes it, so a new row's hash attests to nothing. This kind lives in commerce's demo tree — a live writable resource in your tenant's real store that nothing else in commerce reads. Re-dispatches the request into the handler the intended verb would have reached, taking that verb from a _method form value or query parameter and then from the X-HTTP-Method-Override header. PUT replaces the row, PATCH changes part of it, DELETE removes it, and anything else is 405. The trap is the DEFAULT: naming no override at all leaves the method POST, which this tunnel maps to the PARTIAL UPDATE — it is never a create, and creating is the collection root's job. Behaviour and authorization are the underlying operation's, since the real handler runs. Any valid access token reaches it.","tags":["commerce"],"parameters":[{"name":"disclosureid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"put":{"operationId":"put_commerce_disclosure_by_disclosureid","summary":"Replace a disclosure outright","description":"A disclosure is a published-document record — a publication body, a content hash, a type and a named receiver. The hash LOOKS like a field you set and is in fact derived, but only on update: a freshly created disclosure keeps whatever hash the caller sent until the first replace or patch recomputes it, so a new row's hash attests to nothing. This kind lives in commerce's demo tree — a live writable resource in your tenant's real store that nothing else in commerce reads. This is a true REPLACEMENT, not a merge: the stored row's key is preserved, but the body is decoded onto a FRESH entity, so every field the body omits is written back as its ZERO value. Patch is the verb for changing part of a row. The id is resolved inside the caller org's own namespace and an absent one is 404 before anything is written; a body that fails to decode is 400. Answers the stored result. Any valid access token reaches it. The per-kind permission table has no entry for disclosure, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"disclosureid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/discount":{"get":{"operationId":"get_commerce_discount","summary":"List your org's discounts, as a page","description":"A discount is a price rule: a type (flat, percent, free-shipping, free-item or bulk), a window, a scope naming the store, collection, product or variant it applies to, a target, and rules pairing a trigger — a price or quantity threshold — with an action, an amount off or a percentage. It is ENABLED BY DEFAULT, so a bare create makes a live discount rather than a draft. The rule engine caches per replica for about thirty seconds, so a discount switched off here can keep applying briefly on other replicas. Answers a pagination envelope — the page and display echoed back, the rows under models, a total count and a facets array — read from the caller org's own namespaced store, so one tenant can never list another's. Sorting defaults to the last-updated time and is overridable with sort. display is the page size and page applies only alongside it; either one that is not a positive integer is refused with 500 rather than silently ignored, and the limit query overrides the reported COUNT only, never the rows returned. No search backend is wired, so the datastore is the one and only list path and facets is always empty. A request resolving no org namespace is served an EMPTY page rather than an unscoped scan: the namespace IS the tenant filter, so without one there is nothing safe to return. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The per-kind permission table has no entry for discount, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_discount","summary":"Create a discount","description":"A discount is a price rule: a type (flat, percent, free-shipping, free-item or bulk), a window, a scope naming the store, collection, product or variant it applies to, a target, and rules pairing a trigger — a price or quantity threshold — with an action, an amount off or a percentage. It is ENABLED BY DEFAULT, so a bare create makes a live discount rather than a draft. The rule engine caches per replica for about thirty seconds, so a discount switched off here can keep applying briefly on other replicas. Decodes the body into a new row in the caller org's own namespaced store — isolated to that tenant from its first write — and answers the stored row at 201 with a Location header naming its id. The id is assigned by the store, not taken from the body. A body that fails to decode is 400 and a store that refuses the write is 500. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The per-kind permission table has no entry for discount, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/discount/{discountid}":{"delete":{"operationId":"delete_commerce_discount_by_discountid","summary":"Delete a discount, keeping a recoverable copy","description":"A discount is a price rule: a type (flat, percent, free-shipping, free-item or bulk), a window, a scope naming the store, collection, product or variant it applies to, a target, and rules pairing a trigger — a price or quantity threshold — with an action, an amount off or a percentage. It is ENABLED BY DEFAULT, so a bare create makes a live discount rather than a draft. The rule engine caches per replica for about thirty seconds, so a discount switched off here can keep applying briefly on other replicas. Removes the addressed row and answers 204 with no body. Before the live row goes it is written once more under a deleted tombstone kind, so a deletion leaves a recoverable copy rather than destroying the record outright — and a tombstone that cannot be written fails the call with 500 before anything is removed. The id is resolved inside the caller org's own namespace, so an absent or foreign id is 404. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The per-kind permission table has no entry for discount, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"discountid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"get":{"operationId":"get_commerce_discount_by_discountid","summary":"Fetch one discount","description":"A discount is a price rule: a type (flat, percent, free-shipping, free-item or bulk), a window, a scope naming the store, collection, product or variant it applies to, a target, and rules pairing a trigger — a price or quantity threshold — with an action, an amount off or a percentage. It is ENABLED BY DEFAULT, so a bare create makes a live discount rather than a draft. The rule engine caches per replica for about thirty seconds, so a discount switched off here can keep applying briefly on other replicas. Reads the addressed row from the caller org's own namespaced store. An id that is not there is 404 — and another tenant's id is not there by construction, so it reads exactly like a typo instead of confirming the row exists somewhere else. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The per-kind permission table has no entry for discount, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"discountid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"patch":{"operationId":"patch_commerce_discount_by_discountid","summary":"Change part of a discount","description":"A discount is a price rule: a type (flat, percent, free-shipping, free-item or bulk), a window, a scope naming the store, collection, product or variant it applies to, a target, and rules pairing a trigger — a price or quantity threshold — with an action, an amount off or a percentage. It is ENABLED BY DEFAULT, so a bare create makes a live discount rather than a draft. The rule engine caches per replica for about thirty seconds, so a discount switched off here can keep applying briefly on other replicas. Loads the stored row and decodes the body OVER it, so only the fields the body names change and everything else keeps its stored value — the difference from the full replace, which clears what it is not told. Answers the merged row. An id absent from the caller org's namespace is 404 and a body that fails to decode is 400. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The per-kind permission table has no entry for discount, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"discountid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_discount_by_discountid","summary":"Method-override tunnel for a discount — for clients that cannot send PUT, PATCH or DELETE","description":"A discount is a price rule: a type (flat, percent, free-shipping, free-item or bulk), a window, a scope naming the store, collection, product or variant it applies to, a target, and rules pairing a trigger — a price or quantity threshold — with an action, an amount off or a percentage. It is ENABLED BY DEFAULT, so a bare create makes a live discount rather than a draft. The rule engine caches per replica for about thirty seconds, so a discount switched off here can keep applying briefly on other replicas. Re-dispatches the request into the handler the intended verb would have reached, taking that verb from a _method form value or query parameter and then from the X-HTTP-Method-Override header. PUT replaces the row, PATCH changes part of it, DELETE removes it, and anything else is 405. The trap is the DEFAULT: naming no override at all leaves the method POST, which this tunnel maps to the PARTIAL UPDATE — it is never a create, and creating is the collection root's job. Behaviour and authorization are the underlying operation's, since the real handler runs. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through.","tags":["commerce"],"parameters":[{"name":"discountid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"put":{"operationId":"put_commerce_discount_by_discountid","summary":"Replace a discount outright","description":"A discount is a price rule: a type (flat, percent, free-shipping, free-item or bulk), a window, a scope naming the store, collection, product or variant it applies to, a target, and rules pairing a trigger — a price or quantity threshold — with an action, an amount off or a percentage. It is ENABLED BY DEFAULT, so a bare create makes a live discount rather than a draft. The rule engine caches per replica for about thirty seconds, so a discount switched off here can keep applying briefly on other replicas. This is a true REPLACEMENT, not a merge: the stored row's key is preserved, but the body is decoded onto a FRESH entity, so every field the body omits is written back as its ZERO value. Patch is the verb for changing part of a row. The id is resolved inside the caller org's own namespace and an absent one is 404 before anything is written; a body that fails to decode is 400. Answers the stored result. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The per-kind permission table has no entry for discount, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"discountid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/health":{"get":{"operationId":"get_commerce_health","summary":"Answers ok whenever the commerce subsystem is mounted.","description":"Answers ok whenever the commerce subsystem is mounted. It is registered\nbefore the module embed boots, so it keeps answering even when the embed\nfailed and every business route serves the fail-closed 503 — which is the\npoint: it reports that the process is reachable, never that the money plane\nis healthy. Unauthenticated: a probe that needs a credential is a probe that\nreports the credential.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["commerce"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/liveness"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"commerce","x-public":true,"x-tool":true}},"/v1/commerce/movie":{"get":{"operationId":"get_commerce_movie","summary":"List your org's movies, as a page","description":"A movie is a film catalog record — a slug plus EIDR and IMDB ids, all three required, with title and synopsis copy, artwork, screenshots, trailers, cast and crew, and available and hidden flags. It carries NO price: the money for a film lives on the product that sells it. Answers a pagination envelope — the page and display echoed back, the rows under models, a total count and a facets array — read from the caller org's own namespaced store, so one tenant can never list another's. Sorting defaults to the slug and is overridable with sort. display is the page size and page applies only alongside it; either one that is not a positive integer is refused with 500 rather than silently ignored, and the limit query overrides the reported COUNT only, never the rows returned. No search backend is wired, so the datastore is the one and only list path and facets is always empty. A request resolving no org namespace is served an EMPTY page rather than an unscoped scan: the namespace IS the tenant filter, so without one there is nothing safe to return. Any valid access token reaches it. The per-kind permission table has no entry for movie, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_movie","summary":"Create a movie","description":"A movie is a film catalog record — a slug plus EIDR and IMDB ids, all three required, with title and synopsis copy, artwork, screenshots, trailers, cast and crew, and available and hidden flags. It carries NO price: the money for a film lives on the product that sells it. Decodes the body into a new row in the caller org's own namespaced store — isolated to that tenant from its first write — and answers the stored row at 201 with a Location header naming its id. The id is assigned by the store, not taken from the body. A body that fails to decode is 400 and a store that refuses the write is 500. Any valid access token reaches it. The per-kind permission table has no entry for movie, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/movie/{movieid}":{"delete":{"operationId":"delete_commerce_movie_by_movieid","summary":"Delete a movie, keeping a recoverable copy","description":"A movie is a film catalog record — a slug plus EIDR and IMDB ids, all three required, with title and synopsis copy, artwork, screenshots, trailers, cast and crew, and available and hidden flags. It carries NO price: the money for a film lives on the product that sells it. Removes the addressed row and answers 204 with no body. Before the live row goes it is written once more under a deleted tombstone kind, so a deletion leaves a recoverable copy rather than destroying the record outright — and a tombstone that cannot be written fails the call with 500 before anything is removed. The id is resolved inside the caller org's own namespace, so an absent or foreign id is 404. Any valid access token reaches it. The per-kind permission table has no entry for movie, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"movieid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"get":{"operationId":"get_commerce_movie_by_movieid","summary":"Fetch one movie","description":"A movie is a film catalog record — a slug plus EIDR and IMDB ids, all three required, with title and synopsis copy, artwork, screenshots, trailers, cast and crew, and available and hidden flags. It carries NO price: the money for a film lives on the product that sells it. Reads the addressed row from the caller org's own namespaced store. An id that is not there is 404 — and another tenant's id is not there by construction, so it reads exactly like a typo instead of confirming the row exists somewhere else. Any valid access token reaches it. The per-kind permission table has no entry for movie, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"movieid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"patch":{"operationId":"patch_commerce_movie_by_movieid","summary":"Change part of a movie","description":"A movie is a film catalog record — a slug plus EIDR and IMDB ids, all three required, with title and synopsis copy, artwork, screenshots, trailers, cast and crew, and available and hidden flags. It carries NO price: the money for a film lives on the product that sells it. Loads the stored row and decodes the body OVER it, so only the fields the body names change and everything else keeps its stored value — the difference from the full replace, which clears what it is not told. Answers the merged row. An id absent from the caller org's namespace is 404 and a body that fails to decode is 400. Any valid access token reaches it. The per-kind permission table has no entry for movie, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"movieid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_movie_by_movieid","summary":"Method-override tunnel for a movie — for clients that cannot send PUT, PATCH or DELETE","description":"A movie is a film catalog record — a slug plus EIDR and IMDB ids, all three required, with title and synopsis copy, artwork, screenshots, trailers, cast and crew, and available and hidden flags. It carries NO price: the money for a film lives on the product that sells it. Re-dispatches the request into the handler the intended verb would have reached, taking that verb from a _method form value or query parameter and then from the X-HTTP-Method-Override header. PUT replaces the row, PATCH changes part of it, DELETE removes it, and anything else is 405. The trap is the DEFAULT: naming no override at all leaves the method POST, which this tunnel maps to the PARTIAL UPDATE — it is never a create, and creating is the collection root's job. Behaviour and authorization are the underlying operation's, since the real handler runs. Any valid access token reaches it.","tags":["commerce"],"parameters":[{"name":"movieid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"put":{"operationId":"put_commerce_movie_by_movieid","summary":"Replace a movie outright","description":"A movie is a film catalog record — a slug plus EIDR and IMDB ids, all three required, with title and synopsis copy, artwork, screenshots, trailers, cast and crew, and available and hidden flags. It carries NO price: the money for a film lives on the product that sells it. This is a true REPLACEMENT, not a merge: the stored row's key is preserved, but the body is decoded onto a FRESH entity, so every field the body omits is written back as its ZERO value. Patch is the verb for changing part of a row. The id is resolved inside the caller org's own namespace and an absent one is 404 before anything is written; a body that fails to decode is 400. Answers the stored result. Any valid access token reaches it. The per-kind permission table has no entry for movie, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"movieid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/note":{"get":{"operationId":"get_commerce_note","summary":"List your org's notes, as a page","description":"A note is a timestamped free-text log line — a caller-supplied time, a source, a message and an enabled flag. That time is the caller's own field and is distinct from the row's creation stamp; the note search filters on it, so a note written without one is a zero-time note the ops log will never surface. Answers a pagination envelope — the page and display echoed back, the rows under models, a total count and a facets array — read from the caller org's own namespaced store, so one tenant can never list another's. Sorting defaults to the last-updated time and is overridable with sort. display is the page size and page applies only alongside it; either one that is not a positive integer is refused with 500 rather than silently ignored, and the limit query overrides the reported COUNT only, never the rows returned. No search backend is wired, so the datastore is the one and only list path and facets is always empty. A request resolving no org namespace is served an EMPTY page rather than an unscoped scan: the namespace IS the tenant filter, so without one there is nothing safe to return. Any valid access token reaches it. The per-kind permission table has no entry for note, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_note","summary":"Create a note","description":"A note is a timestamped free-text log line — a caller-supplied time, a source, a message and an enabled flag. That time is the caller's own field and is distinct from the row's creation stamp; the note search filters on it, so a note written without one is a zero-time note the ops log will never surface. Decodes the body into a new row in the caller org's own namespaced store — isolated to that tenant from its first write — and answers the stored row at 201 with a Location header naming its id. The id is assigned by the store, not taken from the body. A body that fails to decode is 400 and a store that refuses the write is 500. Any valid access token reaches it. The per-kind permission table has no entry for note, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/note/{noteid}":{"delete":{"operationId":"delete_commerce_note_by_noteid","summary":"Delete a note, keeping a recoverable copy","description":"A note is a timestamped free-text log line — a caller-supplied time, a source, a message and an enabled flag. That time is the caller's own field and is distinct from the row's creation stamp; the note search filters on it, so a note written without one is a zero-time note the ops log will never surface. Removes the addressed row and answers 204 with no body. Before the live row goes it is written once more under a deleted tombstone kind, so a deletion leaves a recoverable copy rather than destroying the record outright — and a tombstone that cannot be written fails the call with 500 before anything is removed. The id is resolved inside the caller org's own namespace, so an absent or foreign id is 404. Any valid access token reaches it. The per-kind permission table has no entry for note, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"noteid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"get":{"operationId":"get_commerce_note_by_noteid","summary":"Fetch one note","description":"A note is a timestamped free-text log line — a caller-supplied time, a source, a message and an enabled flag. That time is the caller's own field and is distinct from the row's creation stamp; the note search filters on it, so a note written without one is a zero-time note the ops log will never surface. Reads the addressed row from the caller org's own namespaced store. An id that is not there is 404 — and another tenant's id is not there by construction, so it reads exactly like a typo instead of confirming the row exists somewhere else. Any valid access token reaches it. The per-kind permission table has no entry for note, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"noteid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"patch":{"operationId":"patch_commerce_note_by_noteid","summary":"Change part of a note","description":"A note is a timestamped free-text log line — a caller-supplied time, a source, a message and an enabled flag. That time is the caller's own field and is distinct from the row's creation stamp; the note search filters on it, so a note written without one is a zero-time note the ops log will never surface. Loads the stored row and decodes the body OVER it, so only the fields the body names change and everything else keeps its stored value — the difference from the full replace, which clears what it is not told. Answers the merged row. An id absent from the caller org's namespace is 404 and a body that fails to decode is 400. Any valid access token reaches it. The per-kind permission table has no entry for note, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"noteid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_note_by_noteid","summary":"Method-override tunnel for a note — for clients that cannot send PUT, PATCH or DELETE","description":"A note is a timestamped free-text log line — a caller-supplied time, a source, a message and an enabled flag. That time is the caller's own field and is distinct from the row's creation stamp; the note search filters on it, so a note written without one is a zero-time note the ops log will never surface. Re-dispatches the request into the handler the intended verb would have reached, taking that verb from a _method form value or query parameter and then from the X-HTTP-Method-Override header. PUT replaces the row, PATCH changes part of it, DELETE removes it, and anything else is 405. The trap is the DEFAULT: naming no override at all leaves the method POST, which this tunnel maps to the PARTIAL UPDATE — it is never a create, and creating is the collection root's job. Behaviour and authorization are the underlying operation's, since the real handler runs. Any valid access token reaches it.","tags":["commerce"],"parameters":[{"name":"noteid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"put":{"operationId":"put_commerce_note_by_noteid","summary":"Replace a note outright","description":"A note is a timestamped free-text log line — a caller-supplied time, a source, a message and an enabled flag. That time is the caller's own field and is distinct from the row's creation stamp; the note search filters on it, so a note written without one is a zero-time note the ops log will never surface. This is a true REPLACEMENT, not a merge: the stored row's key is preserved, but the body is decoded onto a FRESH entity, so every field the body omits is written back as its ZERO value. Patch is the verb for changing part of a row. The id is resolved inside the caller org's own namespace and an absent one is 404 before anything is written; a body that fails to decode is 400. Answers the stored result. Any valid access token reaches it. The per-kind permission table has no entry for note, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"noteid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/org":{"get":{"operationId":"get_commerce_org","summary":"The public org configuration a checkout page boots from","description":"Answers the branding, identity issuer and client id, identity-verification config, enabled payment providers, return-URL allowlist and public payment application config for the org the request HOST resolves to. It is genuinely public and unauthenticated — a checkout page calls it before anyone has signed in — and it carries the same public payment config the authenticated config read does, so the card iframe can never initialize against a different application than the one that will be charged. Only ENABLED providers are listed and no credential path is ever projected. An unresolvable host answers a constant 404 that does not echo the host, so the endpoint cannot be used to enumerate orgs; a successful answer is cacheable for a minute.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/product":{"get":{"operationId":"get_commerce_product","summary":"List your org's products, as a page","description":"A product is a sellable catalog item: slug, SKU and UPC, name and copy, media, availability and preorder flags, a reservation block, and its money — currency, price, MSRP, list price and inventory cost in minor units, inventory count, taxability, and the subscription interval when it is subscribeable. Its variants and options are carried as a denormalized JSON snapshot inside the product, separate from the standalone variant rows, and nothing keeps the two in step for you. Answers a pagination envelope — the page and display echoed back, the rows under models, a total count and a facets array — read from the caller org's own namespaced store, so one tenant can never list another's. Sorting defaults to the slug and is overridable with sort. display is the page size and page applies only alongside it; either one that is not a positive integer is refused with 500 rather than silently ignored, and the limit query overrides the reported COUNT only, never the rows returned. No search backend is wired, so the datastore is the one and only list path and facets is always empty. A request resolving no org namespace is served an EMPTY page rather than an unscoped scan: the namespace IS the tenant filter, so without one there is nothing safe to return. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The token must also carry Admin or the Product list scope.","tags":["commerce"],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_product","summary":"Create a product","description":"A product is a sellable catalog item: slug, SKU and UPC, name and copy, media, availability and preorder flags, a reservation block, and its money — currency, price, MSRP, list price and inventory cost in minor units, inventory count, taxability, and the subscription interval when it is subscribeable. Its variants and options are carried as a denormalized JSON snapshot inside the product, separate from the standalone variant rows, and nothing keeps the two in step for you. Decodes the body into a new row in the caller org's own namespaced store — isolated to that tenant from its first write — and answers the stored row at 201 with a Location header naming its id. The id is assigned by the store, not taken from the body. A body that fails to decode is 400 and a store that refuses the write is 500. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The token must also carry Admin or WriteProduct.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/product/{productid}":{"delete":{"operationId":"delete_commerce_product_by_productid","summary":"Delete a product, keeping a recoverable copy","description":"A product is a sellable catalog item: slug, SKU and UPC, name and copy, media, availability and preorder flags, a reservation block, and its money — currency, price, MSRP, list price and inventory cost in minor units, inventory count, taxability, and the subscription interval when it is subscribeable. Its variants and options are carried as a denormalized JSON snapshot inside the product, separate from the standalone variant rows, and nothing keeps the two in step for you. Removes the addressed row and answers 204 with no body. Before the live row goes it is written once more under a deleted tombstone kind, so a deletion leaves a recoverable copy rather than destroying the record outright — and a tombstone that cannot be written fails the call with 500 before anything is removed. The id is resolved inside the caller org's own namespace, so an absent or foreign id is 404. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The token must also carry Admin or WriteProduct.","tags":["commerce"],"parameters":[{"name":"productid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"get":{"operationId":"get_commerce_product_by_productid","summary":"Fetch one product","description":"A product is a sellable catalog item: slug, SKU and UPC, name and copy, media, availability and preorder flags, a reservation block, and its money — currency, price, MSRP, list price and inventory cost in minor units, inventory count, taxability, and the subscription interval when it is subscribeable. Its variants and options are carried as a denormalized JSON snapshot inside the product, separate from the standalone variant rows, and nothing keeps the two in step for you. Reads the addressed row from the caller org's own namespaced store. An id that is not there is 404 — and another tenant's id is not there by construction, so it reads exactly like a typo instead of confirming the row exists somewhere else. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The token must also carry Admin or ReadProduct.","tags":["commerce"],"parameters":[{"name":"productid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"patch":{"operationId":"patch_commerce_product_by_productid","summary":"Change part of a product","description":"A product is a sellable catalog item: slug, SKU and UPC, name and copy, media, availability and preorder flags, a reservation block, and its money — currency, price, MSRP, list price and inventory cost in minor units, inventory count, taxability, and the subscription interval when it is subscribeable. Its variants and options are carried as a denormalized JSON snapshot inside the product, separate from the standalone variant rows, and nothing keeps the two in step for you. Loads the stored row and decodes the body OVER it, so only the fields the body names change and everything else keeps its stored value — the difference from the full replace, which clears what it is not told. Answers the merged row. An id absent from the caller org's namespace is 404 and a body that fails to decode is 400. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The token must also carry Admin, or ReadProduct and WriteProduct together.","tags":["commerce"],"parameters":[{"name":"productid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_product_by_productid","summary":"Method-override tunnel for a product — for clients that cannot send PUT, PATCH or DELETE","description":"A product is a sellable catalog item: slug, SKU and UPC, name and copy, media, availability and preorder flags, a reservation block, and its money — currency, price, MSRP, list price and inventory cost in minor units, inventory count, taxability, and the subscription interval when it is subscribeable. Its variants and options are carried as a denormalized JSON snapshot inside the product, separate from the standalone variant rows, and nothing keeps the two in step for you. Re-dispatches the request into the handler the intended verb would have reached, taking that verb from a _method form value or query parameter and then from the X-HTTP-Method-Override header. PUT replaces the row, PATCH changes part of it, DELETE removes it, and anything else is 405. The trap is the DEFAULT: naming no override at all leaves the method POST, which this tunnel maps to the PARTIAL UPDATE — it is never a create, and creating is the collection root's job. Behaviour and authorization are the underlying operation's, since the real handler runs. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through.","tags":["commerce"],"parameters":[{"name":"productid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"put":{"operationId":"put_commerce_product_by_productid","summary":"Replace a product outright","description":"A product is a sellable catalog item: slug, SKU and UPC, name and copy, media, availability and preorder flags, a reservation block, and its money — currency, price, MSRP, list price and inventory cost in minor units, inventory count, taxability, and the subscription interval when it is subscribeable. Its variants and options are carried as a denormalized JSON snapshot inside the product, separate from the standalone variant rows, and nothing keeps the two in step for you. This is a true REPLACEMENT, not a merge: the stored row's key is preserved, but the body is decoded onto a FRESH entity, so every field the body omits is written back as its ZERO value. Patch is the verb for changing part of a row. The id is resolved inside the caller org's own namespace and an absent one is 404 before anything is written; a body that fails to decode is 400. Answers the stored result. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The token must also carry Admin, or ReadProduct and WriteProduct together.","tags":["commerce"],"parameters":[{"name":"productid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/return":{"get":{"operationId":"get_commerce_return","summary":"List your org's returns, as a page","description":"A return is an RMA — the store, user and order it belongs to, the line items coming back, a fulfillment block carrying its own type, status and pricing, a summary, and eight lifecycle timestamps from submitted through delivered and processed. Its status is a FREE STRING with no enumeration behind it, and there is no refund amount on the return itself: the money sits inside the line items and the fulfillment pricing. Answers a pagination envelope — the page and display echoed back, the rows under models, a total count and a facets array — read from the caller org's own namespaced store, so one tenant can never list another's. Sorting defaults to the last-updated time and is overridable with sort. display is the page size and page applies only alongside it; either one that is not a positive integer is refused with 500 rather than silently ignored, and the limit query overrides the reported COUNT only, never the rows returned. No search backend is wired, so the datastore is the one and only list path and facets is always empty. A request resolving no org namespace is served an EMPTY page rather than an unscoped scan: the namespace IS the tenant filter, so without one there is nothing safe to return. Any valid access token reaches it. The token must also carry Admin or the Return list scope.","tags":["commerce"],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_return","summary":"Create a return","description":"A return is an RMA — the store, user and order it belongs to, the line items coming back, a fulfillment block carrying its own type, status and pricing, a summary, and eight lifecycle timestamps from submitted through delivered and processed. Its status is a FREE STRING with no enumeration behind it, and there is no refund amount on the return itself: the money sits inside the line items and the fulfillment pricing. Decodes the body into a new row in the caller org's own namespaced store — isolated to that tenant from its first write — and answers the stored row at 201 with a Location header naming its id. The id is assigned by the store, not taken from the body. A body that fails to decode is 400 and a store that refuses the write is 500. Any valid access token reaches it. The token must also carry Admin or WriteReturn.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/return/{returnid}":{"delete":{"operationId":"delete_commerce_return_by_returnid","summary":"Delete a return, keeping a recoverable copy","description":"A return is an RMA — the store, user and order it belongs to, the line items coming back, a fulfillment block carrying its own type, status and pricing, a summary, and eight lifecycle timestamps from submitted through delivered and processed. Its status is a FREE STRING with no enumeration behind it, and there is no refund amount on the return itself: the money sits inside the line items and the fulfillment pricing. Removes the addressed row and answers 204 with no body. Before the live row goes it is written once more under a deleted tombstone kind, so a deletion leaves a recoverable copy rather than destroying the record outright — and a tombstone that cannot be written fails the call with 500 before anything is removed. The id is resolved inside the caller org's own namespace, so an absent or foreign id is 404. Any valid access token reaches it. The token must also carry Admin or WriteReturn.","tags":["commerce"],"parameters":[{"name":"returnid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"get":{"operationId":"get_commerce_return_by_returnid","summary":"Fetch one return","description":"A return is an RMA — the store, user and order it belongs to, the line items coming back, a fulfillment block carrying its own type, status and pricing, a summary, and eight lifecycle timestamps from submitted through delivered and processed. Its status is a FREE STRING with no enumeration behind it, and there is no refund amount on the return itself: the money sits inside the line items and the fulfillment pricing. Reads the addressed row from the caller org's own namespaced store. An id that is not there is 404 — and another tenant's id is not there by construction, so it reads exactly like a typo instead of confirming the row exists somewhere else. Any valid access token reaches it. The token must also carry Admin or ReadReturn.","tags":["commerce"],"parameters":[{"name":"returnid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"patch":{"operationId":"patch_commerce_return_by_returnid","summary":"Change part of a return","description":"A return is an RMA — the store, user and order it belongs to, the line items coming back, a fulfillment block carrying its own type, status and pricing, a summary, and eight lifecycle timestamps from submitted through delivered and processed. Its status is a FREE STRING with no enumeration behind it, and there is no refund amount on the return itself: the money sits inside the line items and the fulfillment pricing. Loads the stored row and decodes the body OVER it, so only the fields the body names change and everything else keeps its stored value — the difference from the full replace, which clears what it is not told. Answers the merged row. An id absent from the caller org's namespace is 404 and a body that fails to decode is 400. Any valid access token reaches it. The token must also carry Admin, or ReadReturn and WriteReturn together.","tags":["commerce"],"parameters":[{"name":"returnid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_return_by_returnid","summary":"Method-override tunnel for a return — for clients that cannot send PUT, PATCH or DELETE","description":"A return is an RMA — the store, user and order it belongs to, the line items coming back, a fulfillment block carrying its own type, status and pricing, a summary, and eight lifecycle timestamps from submitted through delivered and processed. Its status is a FREE STRING with no enumeration behind it, and there is no refund amount on the return itself: the money sits inside the line items and the fulfillment pricing. Re-dispatches the request into the handler the intended verb would have reached, taking that verb from a _method form value or query parameter and then from the X-HTTP-Method-Override header. PUT replaces the row, PATCH changes part of it, DELETE removes it, and anything else is 405. The trap is the DEFAULT: naming no override at all leaves the method POST, which this tunnel maps to the PARTIAL UPDATE — it is never a create, and creating is the collection root's job. Behaviour and authorization are the underlying operation's, since the real handler runs. Any valid access token reaches it.","tags":["commerce"],"parameters":[{"name":"returnid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"put":{"operationId":"put_commerce_return_by_returnid","summary":"Replace a return outright","description":"A return is an RMA — the store, user and order it belongs to, the line items coming back, a fulfillment block carrying its own type, status and pricing, a summary, and eight lifecycle timestamps from submitted through delivered and processed. Its status is a FREE STRING with no enumeration behind it, and there is no refund amount on the return itself: the money sits inside the line items and the fulfillment pricing. This is a true REPLACEMENT, not a merge: the stored row's key is preserved, but the body is decoded onto a FRESH entity, so every field the body omits is written back as its ZERO value. Patch is the verb for changing part of a row. The id is resolved inside the caller org's own namespace and an absent one is 404 before anything is written; a body that fails to decode is 400. Answers the stored result. Any valid access token reaches it. The token must also carry Admin, or ReadReturn and WriteReturn together.","tags":["commerce"],"parameters":[{"name":"returnid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/saleschannel":{"get":{"operationId":"get_commerce_saleschannel","summary":"List your org's sales channels, as a page","description":"A sales channel is a named selling surface — a name, a description, a disabled flag and metadata. The flag is NEGATIVE, so a channel created from an empty body is enabled. Nothing on this row links products, prices or stock to the channel; here it is a label other surfaces scope themselves by. Answers a pagination envelope — the page and display echoed back, the rows under models, a total count and a facets array — read from the caller org's own namespaced store, so one tenant can never list another's. Sorting defaults to the last-updated time and is overridable with sort. display is the page size and page applies only alongside it; either one that is not a positive integer is refused with 500 rather than silently ignored, and the limit query overrides the reported COUNT only, never the rows returned. No search backend is wired, so the datastore is the one and only list path and facets is always empty. A request resolving no org namespace is served an EMPTY page rather than an unscoped scan: the namespace IS the tenant filter, so without one there is nothing safe to return. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The per-kind permission table has no entry for saleschannel, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_saleschannel","summary":"Create a sales channel","description":"A sales channel is a named selling surface — a name, a description, a disabled flag and metadata. The flag is NEGATIVE, so a channel created from an empty body is enabled. Nothing on this row links products, prices or stock to the channel; here it is a label other surfaces scope themselves by. Decodes the body into a new row in the caller org's own namespaced store — isolated to that tenant from its first write — and answers the stored row at 201 with a Location header naming its id. The id is assigned by the store, not taken from the body. A body that fails to decode is 400 and a store that refuses the write is 500. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The per-kind permission table has no entry for saleschannel, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/saleschannel/{saleschannelid}":{"delete":{"operationId":"delete_commerce_saleschannel_by_saleschannelid","summary":"Delete a sales channel, keeping a recoverable copy","description":"A sales channel is a named selling surface — a name, a description, a disabled flag and metadata. The flag is NEGATIVE, so a channel created from an empty body is enabled. Nothing on this row links products, prices or stock to the channel; here it is a label other surfaces scope themselves by. Removes the addressed row and answers 204 with no body. Before the live row goes it is written once more under a deleted tombstone kind, so a deletion leaves a recoverable copy rather than destroying the record outright — and a tombstone that cannot be written fails the call with 500 before anything is removed. The id is resolved inside the caller org's own namespace, so an absent or foreign id is 404. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The per-kind permission table has no entry for saleschannel, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"saleschannelid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"get":{"operationId":"get_commerce_saleschannel_by_saleschannelid","summary":"Fetch one sales channel","description":"A sales channel is a named selling surface — a name, a description, a disabled flag and metadata. The flag is NEGATIVE, so a channel created from an empty body is enabled. Nothing on this row links products, prices or stock to the channel; here it is a label other surfaces scope themselves by. Reads the addressed row from the caller org's own namespaced store. An id that is not there is 404 — and another tenant's id is not there by construction, so it reads exactly like a typo instead of confirming the row exists somewhere else. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The per-kind permission table has no entry for saleschannel, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"saleschannelid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"patch":{"operationId":"patch_commerce_saleschannel_by_saleschannelid","summary":"Change part of a sales channel","description":"A sales channel is a named selling surface — a name, a description, a disabled flag and metadata. The flag is NEGATIVE, so a channel created from an empty body is enabled. Nothing on this row links products, prices or stock to the channel; here it is a label other surfaces scope themselves by. Loads the stored row and decodes the body OVER it, so only the fields the body names change and everything else keeps its stored value — the difference from the full replace, which clears what it is not told. Answers the merged row. An id absent from the caller org's namespace is 404 and a body that fails to decode is 400. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The per-kind permission table has no entry for saleschannel, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"saleschannelid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_saleschannel_by_saleschannelid","summary":"Method-override tunnel for a sales channel — for clients that cannot send PUT, PATCH or DELETE","description":"A sales channel is a named selling surface — a name, a description, a disabled flag and metadata. The flag is NEGATIVE, so a channel created from an empty body is enabled. Nothing on this row links products, prices or stock to the channel; here it is a label other surfaces scope themselves by. Re-dispatches the request into the handler the intended verb would have reached, taking that verb from a _method form value or query parameter and then from the X-HTTP-Method-Override header. PUT replaces the row, PATCH changes part of it, DELETE removes it, and anything else is 405. The trap is the DEFAULT: naming no override at all leaves the method POST, which this tunnel maps to the PARTIAL UPDATE — it is never a create, and creating is the collection root's job. Behaviour and authorization are the underlying operation's, since the real handler runs. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through.","tags":["commerce"],"parameters":[{"name":"saleschannelid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"put":{"operationId":"put_commerce_saleschannel_by_saleschannelid","summary":"Replace a sales channel outright","description":"A sales channel is a named selling surface — a name, a description, a disabled flag and metadata. The flag is NEGATIVE, so a channel created from an empty body is enabled. Nothing on this row links products, prices or stock to the channel; here it is a label other surfaces scope themselves by. This is a true REPLACEMENT, not a merge: the stored row's key is preserved, but the body is decoded onto a FRESH entity, so every field the body omits is written back as its ZERO value. Patch is the verb for changing part of a row. The id is resolved inside the caller org's own namespace and an absent one is 404 before anything is written; a body that fails to decode is 400. Answers the stored result. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The per-kind permission table has no entry for saleschannel, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"saleschannelid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/stocklocation":{"get":{"operationId":"get_commerce_stocklocation","summary":"List your org's stock locations, as a page","description":"A stock location is a physical address inventory can be held at — a name, street lines, city, province, country, postal code and a phone. None of it is validated, there are no coordinates, and the row carries no enabled flag and no inventory link, so deleting it is the only way to retire one. Answers a pagination envelope — the page and display echoed back, the rows under models, a total count and a facets array — read from the caller org's own namespaced store, so one tenant can never list another's. Sorting defaults to the last-updated time and is overridable with sort. display is the page size and page applies only alongside it; either one that is not a positive integer is refused with 500 rather than silently ignored, and the limit query overrides the reported COUNT only, never the rows returned. No search backend is wired, so the datastore is the one and only list path and facets is always empty. A request resolving no org namespace is served an EMPTY page rather than an unscoped scan: the namespace IS the tenant filter, so without one there is nothing safe to return. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The per-kind permission table has no entry for stocklocation, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_stocklocation","summary":"Create a stock location","description":"A stock location is a physical address inventory can be held at — a name, street lines, city, province, country, postal code and a phone. None of it is validated, there are no coordinates, and the row carries no enabled flag and no inventory link, so deleting it is the only way to retire one. Decodes the body into a new row in the caller org's own namespaced store — isolated to that tenant from its first write — and answers the stored row at 201 with a Location header naming its id. The id is assigned by the store, not taken from the body. A body that fails to decode is 400 and a store that refuses the write is 500. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The per-kind permission table has no entry for stocklocation, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/stocklocation/{stocklocationid}":{"delete":{"operationId":"delete_commerce_stocklocation_by_stocklocationid","summary":"Delete a stock location, keeping a recoverable copy","description":"A stock location is a physical address inventory can be held at — a name, street lines, city, province, country, postal code and a phone. None of it is validated, there are no coordinates, and the row carries no enabled flag and no inventory link, so deleting it is the only way to retire one. Removes the addressed row and answers 204 with no body. Before the live row goes it is written once more under a deleted tombstone kind, so a deletion leaves a recoverable copy rather than destroying the record outright — and a tombstone that cannot be written fails the call with 500 before anything is removed. The id is resolved inside the caller org's own namespace, so an absent or foreign id is 404. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The per-kind permission table has no entry for stocklocation, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"stocklocationid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"get":{"operationId":"get_commerce_stocklocation_by_stocklocationid","summary":"Fetch one stock location","description":"A stock location is a physical address inventory can be held at — a name, street lines, city, province, country, postal code and a phone. None of it is validated, there are no coordinates, and the row carries no enabled flag and no inventory link, so deleting it is the only way to retire one. Reads the addressed row from the caller org's own namespaced store. An id that is not there is 404 — and another tenant's id is not there by construction, so it reads exactly like a typo instead of confirming the row exists somewhere else. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The per-kind permission table has no entry for stocklocation, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"stocklocationid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"patch":{"operationId":"patch_commerce_stocklocation_by_stocklocationid","summary":"Change part of a stock location","description":"A stock location is a physical address inventory can be held at — a name, street lines, city, province, country, postal code and a phone. None of it is validated, there are no coordinates, and the row carries no enabled flag and no inventory link, so deleting it is the only way to retire one. Loads the stored row and decodes the body OVER it, so only the fields the body names change and everything else keeps its stored value — the difference from the full replace, which clears what it is not told. Answers the merged row. An id absent from the caller org's namespace is 404 and a body that fails to decode is 400. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The per-kind permission table has no entry for stocklocation, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"stocklocationid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_stocklocation_by_stocklocationid","summary":"Method-override tunnel for a stock location — for clients that cannot send PUT, PATCH or DELETE","description":"A stock location is a physical address inventory can be held at — a name, street lines, city, province, country, postal code and a phone. None of it is validated, there are no coordinates, and the row carries no enabled flag and no inventory link, so deleting it is the only way to retire one. Re-dispatches the request into the handler the intended verb would have reached, taking that verb from a _method form value or query parameter and then from the X-HTTP-Method-Override header. PUT replaces the row, PATCH changes part of it, DELETE removes it, and anything else is 405. The trap is the DEFAULT: naming no override at all leaves the method POST, which this tunnel maps to the PARTIAL UPDATE — it is never a create, and creating is the collection root's job. Behaviour and authorization are the underlying operation's, since the real handler runs. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through.","tags":["commerce"],"parameters":[{"name":"stocklocationid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"put":{"operationId":"put_commerce_stocklocation_by_stocklocationid","summary":"Replace a stock location outright","description":"A stock location is a physical address inventory can be held at — a name, street lines, city, province, country, postal code and a phone. None of it is validated, there are no coordinates, and the row carries no enabled flag and no inventory link, so deleting it is the only way to retire one. This is a true REPLACEMENT, not a merge: the stored row's key is preserved, but the body is decoded onto a FRESH entity, so every field the body omits is written back as its ZERO value. Patch is the verb for changing part of a row. The id is resolved inside the caller org's own namespace and an absent one is 404 before anything is written; a body that fails to decode is 400. Answers the stored result. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The per-kind permission table has no entry for stocklocation, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"stocklocationid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store":{"get":{"operationId":"get_commerce_store","summary":"List your org's storefronts as a page","description":"Answers a pagination envelope — page, display, the rows, and a total count — read from the caller org's OWN namespaced database, so one tenant can never list another's stores. Sorting defaults to the store slug and is overridable with sort; display is the page size and page applies only alongside it, and either one that is not a positive integer is refused rather than silently ignored. The limit query overrides the reported COUNT only and never the rows returned. A request that resolves no org namespace is served an empty page, never an unscoped scan. Readable with an admin token, a store-scoped token, or the anonymous published storefront key.","tags":["commerce"],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_store","summary":"Create a storefront","description":"Creates a store from the body inside the caller org's own namespaced database, so the row is physically isolated to that tenant from its first write, and answers it at 201 with a Location header naming its id. Requires an admin or store-write token: the anonymous published storefront key may READ stores but never create one. A body that fails to decode is 400.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/store/access":{"get":{"operationId":"get_commerce_store_access","summary":"Whether a store is entitled to trade, and why","description":"Answers allowed, the store id, and a status of trial, active, payment_required, store_required or unavailable — the entitlement check a merchant surface gates on. The rule that surprises people is that entitlement is PER STORE, not per org: the store needs its own current subscription on the entry plan, either trialing with a trial end still ahead or active with a period end still ahead, so an org-wide balance or a sibling store's plan unlocks nothing here. The store comes from the X-Store-Id header and otherwise falls back to the org's first store; neither resolving is store_required with allowed false, and a backing-store failure is 503 with status unavailable — a retry signal, not a denial.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/store/current":{"get":{"operationId":"get_commerce_store_current","summary":"Resolve your org's active storefront without naming an id","description":"Returns the caller org's store resolved FROM THE AUTHENTICATED ORG rather than from a path id — which is how an admin dashboard or a storefront edge learns the store id it should then read and write against. An X-Store-Id header selects a specific store, resolved only inside the caller's own namespace, so a foreign id cannot cross the tenant boundary and answers 404 instead. With no header the org's first store is returned, and an org that has none yet has its canonical default provisioned lazily and idempotently, carrying no payment credentials. Only when there is no org in context, or provisioning fails, does it fall back to a placeholder store literally named default, which a storefront edge should treat as unconfigured.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/store/token":{"post":{"operationId":"post_commerce_store_token","summary":"Mint your org's least-privilege storefront read key","description":"Answers a freshly minted token carrying ONLY the published-read permission — enough for a logged-out shopper's storefront to read your published catalog and nothing more, with no write and no admin scope. It is org-bound, signed with the org's own secret and subject to the org id, so it can never act on another tenant. Minting ROTATES rather than accumulates: the previous storefront token is dropped first and is invalid immediately, so re-minting is how you revoke. Admin is enforced by the handler as well as the route, because the route's token gate does not apply on the identity path and a plain member must not be able to mint their org's key.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}":{"delete":{"operationId":"delete_commerce_store_by_storeid","summary":"Delete a storefront, keeping a recoverable copy","description":"Removes the addressed store and answers 204 with no body. Before the live row goes, the entity is written once more under a tombstone kind, so the deletion leaves a recoverable copy rather than destroying the record outright; the store's listing overrides live inside that row and go with it. The id is resolved inside the caller org's own namespace, so an unknown or foreign id is 404. Requires an admin or store-write token.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"get":{"operationId":"get_commerce_store_by_storeid","summary":"Fetch one storefront","description":"Reads the addressed store from the caller org's own namespaced database, so an id belonging to another tenant is simply absent there and answers 404 rather than leaking its existence. The body is the stored entity including its embedded listing override map. Readable with an admin or store-read token and also with the anonymous published storefront key, which is what lets a logged-out storefront resolve the store it is rendering.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"patch":{"operationId":"patch_commerce_store_by_storeid","summary":"Change part of a storefront","description":"Loads the stored store and decodes the body over it, so only the fields the body names change and everything else keeps its stored value — the difference from the full replace, which clears what it is not told. Answers the merged entity. The id is resolved inside the caller org's own namespace, so an unknown or foreign id is 404. Requires an admin token, or one holding both store read and store write.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_store_by_storeid","summary":"Method-override tunnel for clients that cannot send PUT, PATCH or DELETE","description":"Re-dispatches the request into the handler the intended verb would have reached, taking that verb from a _method form value or query parameter and then from the X-HTTP-Method-Override header, the header winning when both are present. Only PUT, PATCH and DELETE are accepted; anything else resolves to 405. The trap is the default: naming NO override at all is treated as a partial update, never as a create. Authorization is whatever the underlying operation requires, since the real handler runs.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"put":{"operationId":"put_commerce_store_by_storeid","summary":"Replace a storefront outright","description":"This is a true REPLACEMENT, not a merge: the stored key is preserved but the body is decoded onto a fresh entity, so every field the body omits is written back as its zero value. Use the partial update when you mean to change part of a store. The id is resolved inside the caller org's own namespace, so an unknown or foreign id is a 404 before anything is written. Requires an admin token, or one holding both store read and store write.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/authorize":{"post":{"operationId":"post_commerce_store_by_storeid_authorize","summary":"Authorize a new order against a storefront, holding the funds without settling them","description":"Tallies a new order for the addressed store from the user, payment and order body, reserves its items, runs the processor authorization and answers the saved order with a Location header pointing at it. The gate is a token carrying admin or published scope, so a published storefront key is enough; no token is 401 and a token with neither bit is 403. The store is loaded BEFORE any payment work and its currency OVERRIDES whatever the body asked for, so a store that will not load ends the call with 500 and nothing is charged. On any authorization failure the reservations are released and the order and payment are persisted as cancelled, so a failed attempt still leaves a durable record. Capture is a separate call.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/authorize/{orderid}":{"post":{"operationId":"post_commerce_store_by_storeid_authorize_by_orderid","summary":"Authorize an order that already exists, holding the funds without settling them","description":"Continues the order named in the path rather than minting a new one, holding funds for it. The order is loaded from the caller org's own store, so an id belonging to another tenant is a 404. The rule most callers get wrong is that the body's order object is MERGED onto the loaded order before the tally — this is not a read-only reference, and a field sent here overwrites what is stored. The gate, the store resolution and the currency override behave exactly as on the bodiless-id sibling, and settling is still the capture call's job.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}},{"name":"orderid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/bundle/{key}":{"get":{"operationId":"get_commerce_store_by_storeid_bundle_by_key","summary":"Fetch a bundle as this storefront sells it","description":"Returns the stored bundle with the store's listing for it laid over the top — every non-empty listing field wins, and the currency is forced to the store's own — so the caller reads what this storefront actually sells rather than the catalog-wide record. The overlay is keyed by the item's ID: a listing filed only under a slug or SKU does not reach it, unlike the listing reads, which do fall back to those. An unknown store or key is 404. Readable with an admin token or the anonymous published storefront key.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/capture/{orderid}":{"post":{"operationId":"post_commerce_store_by_storeid_capture_by_orderid","summary":"Capture a previously authorized order and settle the payment","description":"Settles the order named in the path — the second half of the two-step flow — and answers the updated order with a Location header. Dispatch follows the order's STORED payment type, and a successful capture is the moment the rest of the system learns about the sale: order and payment rows are updated, coupon redemptions, referral, cart and stats are written, the confirmation email goes out, and the paid and completed events are emitted. A capture failure releases the order's inventory reservations and answers 400, so a failed settlement never leaves items held.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}},{"name":"orderid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/charge":{"post":{"operationId":"post_commerce_store_by_storeid_charge","summary":"Authorize and capture a new order in one call","description":"Runs authorization and capture back to back against a freshly created order — the one-step flow for callers with no reason to hold funds. It takes the authorize body and inherits every authorize rule: the store's currency wins over the body, the items are reserved before the processor is called, and the amount bounds the processor enforces still apply. There is no order id on this address, so it can never continue an existing order. Either half failing answers 400, and the capture side effects — confirmation email, redemptions, stats, the paid and completed events — run only when both halves succeed.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/checkout/authorize":{"post":{"operationId":"post_commerce_store_by_storeid_checkout_authorize","summary":"Authorize a new order against a storefront, holding the funds — the checkout spelling","description":"Authorizes a new order for the addressed store and holds the funds, answering the saved order with a Location header. It binds the identical handler as the shorter authorize address, so the two are ONE operation at two spellings and not two behaviours; the checkout prefix is the newer one. Every rule carries over: admin or published scope on the token, the store loaded first with its currency overriding the body, items reserved before the processor call, and reservations released with the order persisted cancelled on failure. Nothing is settled here.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/checkout/authorize/{orderid}":{"post":{"operationId":"post_commerce_store_by_storeid_checkout_authorize_by_orderid","summary":"Authorize an existing order, holding the funds — the checkout spelling","description":"Continues the order named in the path rather than minting one, and shares its handler byte for byte with the unprefixed authorize-by-id address. The order is loaded from the caller org's own store, so another tenant's id is a 404, and the body's order object is merged onto the loaded row before the tally — a field sent here overwrites what is stored. Store resolution, the token gate and the currency override behave as on every other authorize address; settle with the capture address and the same order id.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}},{"name":"orderid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/checkout/capture/{orderid}":{"post":{"operationId":"post_commerce_store_by_storeid_checkout_capture_by_orderid","summary":"Capture a previously authorized order and settle it — the checkout spelling","description":"Settles the authorized order named in the path and answers the updated order with a Location header, running the same handler as the unprefixed capture address. Dispatch follows the order's stored payment type. Success is what triggers the downstream work — order and payment updates, redemptions, referral, cart and stats, the confirmation email, and the paid and completed events — while a failure releases the order's inventory reservations and answers 400.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}},{"name":"orderid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/checkout/charge":{"post":{"operationId":"post_commerce_store_by_storeid_checkout_charge","summary":"Authorize and capture a new order in one call — the checkout spelling","description":"Performs authorization and capture back to back against a newly created order for the addressed store, on the same handler as the unprefixed charge address. It takes the authorize body and inherits every authorize rule, including the store's currency winning over the body and the items being reserved before the processor is called. There is no order id on this address, so it can never continue an existing order. Either half failing answers 400, and the capture side effects run only when both succeed.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/checkout/paypal/cancel/{payKey}":{"post":{"operationId":"post_commerce_store_by_storeid_checkout_paypal_cancel_by_paykey","summary":"PayPal cancel by pay key — refuses, exactly as the unprefixed address does","description":"Meant to void the payments carrying the given pay key, stamp them cancelled and cancel the order, but the shared checkout handler resolves its order from an ORDER ID path parameter this route does not carry. The result is an untyped order and a cancel dispatch that refuses with 400 before the pay key lookup ever runs. Token gate, namespacing and store resolution happen first, so a missing token is still 401 and an unloadable store still 500. It is the same handler as the unprefixed cancel address, with the same outcome.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}},{"name":"payKey","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/checkout/paypal/confirm/{payKey}":{"post":{"operationId":"post_commerce_store_by_storeid_checkout_paypal_confirm_by_paykey","summary":"PayPal confirm by pay key — refuses, exactly as the unprefixed address does","description":"Meant to mark the payments carrying the given pay key as paid and set the order to paid, it cannot reach that work from this address: the shared checkout handler takes its order from an ORDER ID path parameter this route does not carry, so the order is always fresh and untyped and the confirm dispatch refuses with 400 before the pay key is queried. The token gate, the namespace middleware and the store lookup all run ahead of that, so authentication and store failures surface first. Behaviour is identical to the unprefixed confirm address; the checkout prefix changes nothing here.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}},{"name":"payKey","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/checkout/paypal/pay":{"post":{"operationId":"post_commerce_store_by_storeid_checkout_paypal_pay","summary":"Start a PayPal authorization for a new order — the checkout spelling","description":"Begins a PayPal authorization by running the ordinary store authorize flow, since the route binds that exact handler — body, store resolution, tally, reservations and failure behaviour are the authorize address's, unchanged. The processor is chosen from the body's payment type, so this path reaches PayPal only when that type says so. A successful PayPal authorization stamps a pay key onto the payment, which is the key the confirm and cancel addresses filter on. Build against the plain authorize address instead.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/listing":{"get":{"operationId":"get_commerce_store_by_storeid_listing","summary":"The storefront's whole listing override map","description":"Returns every override this store applies to catalog items — name, price, list price, media, availability and the hidden flag — keyed by product or variant id, in one read. A listing is an OVERRIDE, not a product: the catalog item exists independently and this map only says how this storefront presents it. Read from the caller org's own namespaced database, so a store id belonging to another tenant is 404. Readable with an admin token or the anonymous published storefront key.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/listing/{key}":{"delete":{"operationId":"delete_commerce_store_by_storeid_listing_by_key","summary":"Remove a listing override","description":"Drops the key from the store's listing map and re-saves the store, answering 204 with no body. It UN-OVERRIDES rather than deletes: the product, variant or bundle itself is untouched and simply reverts to its catalog values on this storefront. A key that is not present is 404, and so is a store id outside the caller org's namespace. Admin-gated.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"get":{"operationId":"get_commerce_store_by_storeid_listing_by_key","summary":"Fetch one listing override, by item id or by its slug or SKU","description":"Looks the key up in the store's listing map first and, failing that, matches it against each listing's slug and then its SKU — so a storefront holding only a product's URL slug can still resolve the override. That fallback is unique to the listing reads; the item overlay routes match by id alone. A key matching none of the three is 404, as is a store id outside the caller org's namespace. Readable with an admin token or the anonymous published storefront key.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"patch":{"operationId":"patch_commerce_store_by_storeid_listing_by_key","summary":"Confirm a listing override exists and re-save the store","description":"Requires the key to already be present — an absent one is 404 — and answers the store's listing map at 200. Read the behaviour before relying on it: the decoded body is applied to a COPY taken out of the map and is never assigned back, so the stored listing is unchanged and the map returned is exactly the map that was already there. An actual edit to an existing listing has to go through the upsert, which does write its result back into the store. A body that fails to decode is still 400. Admin-gated and namespaced to the caller's org.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_store_by_storeid_listing_by_key","summary":"Add a listing override under a new key","description":"Creates the override and answers the store's ENTIRE listing map at 201 with a Location header — not just the entry that was added. A key already present is refused 400: creation never silently overwrites, so changing an existing listing has to be an explicit replace. The stored listing has its currency stamped from the store's own, which the replace path does not do. The key is matched exactly here, with none of the slug or SKU fallback the read allows. Admin-gated and resolved inside the caller org's namespace.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"put":{"operationId":"put_commerce_store_by_storeid_listing_by_key","summary":"Upsert a listing override","description":"Decodes the body over the existing listing when the key is present, so fields it omits keep their stored values, and builds the listing from the body alone when the key is new. Answers 200 when it replaced something and 201 with a Location header when it created it; either way the body is the store's entire listing map, not the single entry. Unlike creation, this path does NOT restamp the listing's currency from the store. Admin-gated, with the store resolved inside the caller org's namespace.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/paypal/cancel/{payKey}":{"post":{"operationId":"post_commerce_store_by_storeid_paypal_cancel_by_paykey","summary":"PayPal cancel by pay key — refuses, because a pay key alone does not identify the order","description":"Intended to void the payments carrying the given pay key, stamp them cancelled and cancel the order, it never reaches that work: the shared checkout handler reads its order from an ORDER ID path parameter this route does not carry, leaving an untyped order that the cancel dispatch refuses with 400 before the pay key lookup runs. Authentication, namespacing and store resolution happen ahead of the refusal, so a missing token is 401 and an unloadable store 500. Cancelling a real PayPal authorization needs an address that carries the order id.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}},{"name":"payKey","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/paypal/confirm/{payKey}":{"post":{"operationId":"post_commerce_store_by_storeid_paypal_confirm_by_paykey","summary":"PayPal confirm by pay key — refuses, because a pay key alone does not identify the order","description":"Intended to mark every payment carrying the given pay key as paid and flip the order to paid, it cannot do that from this address and does not pretend to: the shared checkout handler resolves its order from an ORDER ID path parameter that this route does not carry, so it always works against a fresh untyped order and the confirm dispatch refuses it with 400 before the pay key is ever queried. The token gate, the namespace and the store lookup all run ahead of that, so a missing token is still 401 and an unloadable store still 500. Drive a PayPal return through an address that carries the order id.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}},{"name":"payKey","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/paypal/pay":{"post":{"operationId":"post_commerce_store_by_storeid_paypal_pay","summary":"Start a PayPal authorization for a new order","description":"Runs the ordinary store authorize flow — the route binds that very handler, so the body, the store resolution, the tally, the reservations and the failure behaviour are the authorize address's, unchanged. It reaches PayPal only when the body's payment type says so; nothing about this path forces the processor, so a card-typed payment posted here authorizes on the card processor instead. A successful PayPal authorization stamps a pay key onto the payment, which is the key the confirm and cancel addresses filter on. It is the older entry point; the plain authorize address is the one to build against.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/product/{key}":{"get":{"operationId":"get_commerce_store_by_storeid_product_by_key","summary":"Fetch a product as this storefront sells it","description":"Returns the stored product with the store's listing for it laid over the top — non-empty listing fields replace the catalog values and the currency is forced to the store's own — which is what lets two storefronts sell the same catalog product at their own price, name and media. The overlay is keyed by the product's ID, so a listing filed only under a slug or SKU does not apply here. An unknown store or key is 404. Readable with an admin token or the anonymous published storefront key.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/trial":{"post":{"operationId":"post_commerce_store_by_storeid_trial","summary":"Start this store's no-card trial on the entry plan","description":"Creates a trialing subscription for the addressed store on the entry plan and grants that plan's trial credit, answering 201 when this call actually started one and 200 with a reason otherwise — not_new when the store already has billing history, trial_not_configured when no entry plan is wired. The window is always the SEVEN-DAY no-card trial, because this address never presents a card; the longer card-present window is reached only by adding a card afterwards. Entitlement is per store while the billing subject is the org, so every store an org owns takes its own trial. Admin-gated and namespaced to the caller's org: no resolvable store is 404 with store_required, and a backing-store failure is 503.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/store/{storeid}/variant/{key}":{"get":{"operationId":"get_commerce_store_by_storeid_variant_by_key","summary":"Fetch a variant as this storefront sells it","description":"Returns the stored variant with the store's listing for it overlaid — non-empty listing fields replace the catalog values and the currency is forced to the store's own — which is what makes per-storefront pricing of a shared variant possible. The overlay is keyed by the variant's ID, never by its slug or SKU. An unknown store or key is 404. Readable with an admin token or the anonymous published storefront key.","tags":["commerce"],"parameters":[{"name":"storeid","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/submission":{"get":{"operationId":"get_commerce_submission","summary":"List your org's submissions, as a page","description":"A submission is one filled-in form from a site visitor — an email, an optional user id, the client details the server observed (user agent, referer, geography) and the form's own fields as free metadata. It carries no form id, so the link back to the form that produced it is not stored on the row. Answers a pagination envelope — the page and display echoed back, the rows under models, a total count and a facets array — read from the caller org's own namespaced store, so one tenant can never list another's. Sorting defaults to the last-updated time and is overridable with sort. display is the page size and page applies only alongside it; either one that is not a positive integer is refused with 500 rather than silently ignored, and the limit query overrides the reported COUNT only, never the rows returned. No search backend is wired, so the datastore is the one and only list path and facets is always empty. A request resolving no org namespace is served an EMPTY page rather than an unscoped scan: the namespace IS the tenant filter, so without one there is nothing safe to return. Any valid access token reaches it. The per-kind permission table has no entry for submission, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_submission","summary":"Create a submission","description":"A submission is one filled-in form from a site visitor — an email, an optional user id, the client details the server observed (user agent, referer, geography) and the form's own fields as free metadata. It carries no form id, so the link back to the form that produced it is not stored on the row. Decodes the body into a new row in the caller org's own namespaced store — isolated to that tenant from its first write — and answers the stored row at 201 with a Location header naming its id. The id is assigned by the store, not taken from the body. A body that fails to decode is 400 and a store that refuses the write is 500. Any valid access token reaches it. The per-kind permission table has no entry for submission, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/submission/{submissionid}":{"delete":{"operationId":"delete_commerce_submission_by_submissionid","summary":"Delete a submission, keeping a recoverable copy","description":"A submission is one filled-in form from a site visitor — an email, an optional user id, the client details the server observed (user agent, referer, geography) and the form's own fields as free metadata. It carries no form id, so the link back to the form that produced it is not stored on the row. Removes the addressed row and answers 204 with no body. Before the live row goes it is written once more under a deleted tombstone kind, so a deletion leaves a recoverable copy rather than destroying the record outright — and a tombstone that cannot be written fails the call with 500 before anything is removed. The id is resolved inside the caller org's own namespace, so an absent or foreign id is 404. Any valid access token reaches it. The per-kind permission table has no entry for submission, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"submissionid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"get":{"operationId":"get_commerce_submission_by_submissionid","summary":"Fetch one submission","description":"A submission is one filled-in form from a site visitor — an email, an optional user id, the client details the server observed (user agent, referer, geography) and the form's own fields as free metadata. It carries no form id, so the link back to the form that produced it is not stored on the row. Reads the addressed row from the caller org's own namespaced store. An id that is not there is 404 — and another tenant's id is not there by construction, so it reads exactly like a typo instead of confirming the row exists somewhere else. Any valid access token reaches it. The per-kind permission table has no entry for submission, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"submissionid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"patch":{"operationId":"patch_commerce_submission_by_submissionid","summary":"Change part of a submission","description":"A submission is one filled-in form from a site visitor — an email, an optional user id, the client details the server observed (user agent, referer, geography) and the form's own fields as free metadata. It carries no form id, so the link back to the form that produced it is not stored on the row. Loads the stored row and decodes the body OVER it, so only the fields the body names change and everything else keeps its stored value — the difference from the full replace, which clears what it is not told. Answers the merged row. An id absent from the caller org's namespace is 404 and a body that fails to decode is 400. Any valid access token reaches it. The per-kind permission table has no entry for submission, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"submissionid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_submission_by_submissionid","summary":"Method-override tunnel for a submission — for clients that cannot send PUT, PATCH or DELETE","description":"A submission is one filled-in form from a site visitor — an email, an optional user id, the client details the server observed (user agent, referer, geography) and the form's own fields as free metadata. It carries no form id, so the link back to the form that produced it is not stored on the row. Re-dispatches the request into the handler the intended verb would have reached, taking that verb from a _method form value or query parameter and then from the X-HTTP-Method-Override header. PUT replaces the row, PATCH changes part of it, DELETE removes it, and anything else is 405. The trap is the DEFAULT: naming no override at all leaves the method POST, which this tunnel maps to the PARTIAL UPDATE — it is never a create, and creating is the collection root's job. Behaviour and authorization are the underlying operation's, since the real handler runs. Any valid access token reaches it.","tags":["commerce"],"parameters":[{"name":"submissionid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"put":{"operationId":"put_commerce_submission_by_submissionid","summary":"Replace a submission outright","description":"A submission is one filled-in form from a site visitor — an email, an optional user id, the client details the server observed (user agent, referer, geography) and the form's own fields as free metadata. It carries no form id, so the link back to the form that produced it is not stored on the row. This is a true REPLACEMENT, not a merge: the stored row's key is preserved, but the body is decoded onto a FRESH entity, so every field the body omits is written back as its ZERO value. Patch is the verb for changing part of a row. The id is resolved inside the caller org's own namespace and an absent one is 404 before anything is written; a body that fails to decode is 400. Answers the stored result. Any valid access token reaches it. The per-kind permission table has no entry for submission, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"submissionid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/subscriber":{"get":{"operationId":"get_commerce_subscriber","summary":"List your org's subscribers, as a page","description":"A subscriber is a mailing-list member — name, email, the form id that captured them, unsubscribed state and date, client details, tags and metadata. Writing one FIRES A WEBHOOK: subscriber.created on create and subscriber.updated on replace or patch, emitted BEFORE the write is known to have succeeded and carrying the row as sent, so the payload holds the raw email rather than the normalized one that gets stored. Answers a pagination envelope — the page and display echoed back, the rows under models, a total count and a facets array — read from the caller org's own namespaced store, so one tenant can never list another's. Sorting defaults to the last-updated time and is overridable with sort. display is the page size and page applies only alongside it; either one that is not a positive integer is refused with 500 rather than silently ignored, and the limit query overrides the reported COUNT only, never the rows returned. No search backend is wired, so the datastore is the one and only list path and facets is always empty. A request resolving no org namespace is served an EMPTY page rather than an unscoped scan: the namespace IS the tenant filter, so without one there is nothing safe to return. Any valid access token reaches it. The token must also carry Admin or the Subscriber list scope.","tags":["commerce"],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_subscriber","summary":"Create a subscriber","description":"A subscriber is a mailing-list member — name, email, the form id that captured them, unsubscribed state and date, client details, tags and metadata. Writing one FIRES A WEBHOOK: subscriber.created on create and subscriber.updated on replace or patch, emitted BEFORE the write is known to have succeeded and carrying the row as sent, so the payload holds the raw email rather than the normalized one that gets stored. Decodes the body into a new row in the caller org's own namespaced store — isolated to that tenant from its first write — and answers the stored row at 201 with a Location header naming its id. The id is assigned by the store, not taken from the body. A body that fails to decode is 400 and a store that refuses the write is 500. Any valid access token reaches it. The token must also carry Admin or WriteSubscriber.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/subscriber/{subscriberid}":{"delete":{"operationId":"delete_commerce_subscriber_by_subscriberid","summary":"Delete a subscriber, keeping a recoverable copy","description":"A subscriber is a mailing-list member — name, email, the form id that captured them, unsubscribed state and date, client details, tags and metadata. Writing one FIRES A WEBHOOK: subscriber.created on create and subscriber.updated on replace or patch, emitted BEFORE the write is known to have succeeded and carrying the row as sent, so the payload holds the raw email rather than the normalized one that gets stored. Removes the addressed row and answers 204 with no body. Before the live row goes it is written once more under a deleted tombstone kind, so a deletion leaves a recoverable copy rather than destroying the record outright — and a tombstone that cannot be written fails the call with 500 before anything is removed. The id is resolved inside the caller org's own namespace, so an absent or foreign id is 404. Any valid access token reaches it. The token must also carry Admin or WriteSubscriber.","tags":["commerce"],"parameters":[{"name":"subscriberid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"get":{"operationId":"get_commerce_subscriber_by_subscriberid","summary":"Fetch one subscriber","description":"A subscriber is a mailing-list member — name, email, the form id that captured them, unsubscribed state and date, client details, tags and metadata. Writing one FIRES A WEBHOOK: subscriber.created on create and subscriber.updated on replace or patch, emitted BEFORE the write is known to have succeeded and carrying the row as sent, so the payload holds the raw email rather than the normalized one that gets stored. Reads the addressed row from the caller org's own namespaced store. An id that is not there is 404 — and another tenant's id is not there by construction, so it reads exactly like a typo instead of confirming the row exists somewhere else. Any valid access token reaches it. The token must also carry Admin or ReadSubscriber.","tags":["commerce"],"parameters":[{"name":"subscriberid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"patch":{"operationId":"patch_commerce_subscriber_by_subscriberid","summary":"Change part of a subscriber","description":"A subscriber is a mailing-list member — name, email, the form id that captured them, unsubscribed state and date, client details, tags and metadata. Writing one FIRES A WEBHOOK: subscriber.created on create and subscriber.updated on replace or patch, emitted BEFORE the write is known to have succeeded and carrying the row as sent, so the payload holds the raw email rather than the normalized one that gets stored. Loads the stored row and decodes the body OVER it, so only the fields the body names change and everything else keeps its stored value — the difference from the full replace, which clears what it is not told. Answers the merged row. An id absent from the caller org's namespace is 404 and a body that fails to decode is 400. Any valid access token reaches it. The token must also carry Admin, or ReadSubscriber and WriteSubscriber together.","tags":["commerce"],"parameters":[{"name":"subscriberid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_subscriber_by_subscriberid","summary":"Method-override tunnel for a subscriber — for clients that cannot send PUT, PATCH or DELETE","description":"A subscriber is a mailing-list member — name, email, the form id that captured them, unsubscribed state and date, client details, tags and metadata. Writing one FIRES A WEBHOOK: subscriber.created on create and subscriber.updated on replace or patch, emitted BEFORE the write is known to have succeeded and carrying the row as sent, so the payload holds the raw email rather than the normalized one that gets stored. Re-dispatches the request into the handler the intended verb would have reached, taking that verb from a _method form value or query parameter and then from the X-HTTP-Method-Override header. PUT replaces the row, PATCH changes part of it, DELETE removes it, and anything else is 405. The trap is the DEFAULT: naming no override at all leaves the method POST, which this tunnel maps to the PARTIAL UPDATE — it is never a create, and creating is the collection root's job. Behaviour and authorization are the underlying operation's, since the real handler runs. Any valid access token reaches it.","tags":["commerce"],"parameters":[{"name":"subscriberid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"put":{"operationId":"put_commerce_subscriber_by_subscriberid","summary":"Replace a subscriber outright","description":"A subscriber is a mailing-list member — name, email, the form id that captured them, unsubscribed state and date, client details, tags and metadata. Writing one FIRES A WEBHOOK: subscriber.created on create and subscriber.updated on replace or patch, emitted BEFORE the write is known to have succeeded and carrying the row as sent, so the payload holds the raw email rather than the normalized one that gets stored. This is a true REPLACEMENT, not a merge: the stored row's key is preserved, but the body is decoded onto a FRESH entity, so every field the body omits is written back as its ZERO value. Patch is the verb for changing part of a row. The id is resolved inside the caller org's own namespace and an absent one is 404 before anything is written; a body that fails to decode is 400. Answers the stored result. Any valid access token reaches it. The token must also carry Admin, or ReadSubscriber and WriteSubscriber together.","tags":["commerce"],"parameters":[{"name":"subscriberid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/tokentransaction":{"get":{"operationId":"get_commerce_tokentransaction","summary":"List your org's token transactions, as a page","description":"A token transaction records a transfer between two identified parties — amount and fees, a timestamp, sending and receiving addresses, names, user ids, states and countries, a flag per side, a protocol name and a transaction hash. Nothing here touches a chain: the hash is an unvalidated string and the flags are plain writable booleans with no screening behind them. Amounts are floating-point rather than the exact minor units every real money field in commerce uses, and there is no currency field at all — this kind lives in commerce's demo tree, so it is a live writable resource in your tenant's store that nothing else in commerce reads, and it must never carry real money. Answers a pagination envelope — the page and display echoed back, the rows under models, a total count and a facets array — read from the caller org's own namespaced store, so one tenant can never list another's. Sorting defaults to the last-updated time and is overridable with sort. display is the page size and page applies only alongside it; either one that is not a positive integer is refused with 500 rather than silently ignored, and the limit query overrides the reported COUNT only, never the rows returned. No search backend is wired, so the datastore is the one and only list path and facets is always empty. A request resolving no org namespace is served an EMPTY page rather than an unscoped scan: the namespace IS the tenant filter, so without one there is nothing safe to return. Any valid access token reaches it. The per-kind permission table has no entry for tokentransaction, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_tokentransaction","summary":"Create a token transaction","description":"A token transaction records a transfer between two identified parties — amount and fees, a timestamp, sending and receiving addresses, names, user ids, states and countries, a flag per side, a protocol name and a transaction hash. Nothing here touches a chain: the hash is an unvalidated string and the flags are plain writable booleans with no screening behind them. Amounts are floating-point rather than the exact minor units every real money field in commerce uses, and there is no currency field at all — this kind lives in commerce's demo tree, so it is a live writable resource in your tenant's store that nothing else in commerce reads, and it must never carry real money. Decodes the body into a new row in the caller org's own namespaced store — isolated to that tenant from its first write — and answers the stored row at 201 with a Location header naming its id. The id is assigned by the store, not taken from the body. A body that fails to decode is 400 and a store that refuses the write is 500. Any valid access token reaches it. The per-kind permission table has no entry for tokentransaction, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/tokentransaction/{tokentransactionid}":{"delete":{"operationId":"delete_commerce_tokentransaction_by_tokentransactionid","summary":"Delete a token transaction, keeping a recoverable copy","description":"A token transaction records a transfer between two identified parties — amount and fees, a timestamp, sending and receiving addresses, names, user ids, states and countries, a flag per side, a protocol name and a transaction hash. Nothing here touches a chain: the hash is an unvalidated string and the flags are plain writable booleans with no screening behind them. Amounts are floating-point rather than the exact minor units every real money field in commerce uses, and there is no currency field at all — this kind lives in commerce's demo tree, so it is a live writable resource in your tenant's store that nothing else in commerce reads, and it must never carry real money. Removes the addressed row and answers 204 with no body. Before the live row goes it is written once more under a deleted tombstone kind, so a deletion leaves a recoverable copy rather than destroying the record outright — and a tombstone that cannot be written fails the call with 500 before anything is removed. The id is resolved inside the caller org's own namespace, so an absent or foreign id is 404. Any valid access token reaches it. The per-kind permission table has no entry for tokentransaction, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"tokentransactionid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"get":{"operationId":"get_commerce_tokentransaction_by_tokentransactionid","summary":"Fetch one token transaction","description":"A token transaction records a transfer between two identified parties — amount and fees, a timestamp, sending and receiving addresses, names, user ids, states and countries, a flag per side, a protocol name and a transaction hash. Nothing here touches a chain: the hash is an unvalidated string and the flags are plain writable booleans with no screening behind them. Amounts are floating-point rather than the exact minor units every real money field in commerce uses, and there is no currency field at all — this kind lives in commerce's demo tree, so it is a live writable resource in your tenant's store that nothing else in commerce reads, and it must never carry real money. Reads the addressed row from the caller org's own namespaced store. An id that is not there is 404 — and another tenant's id is not there by construction, so it reads exactly like a typo instead of confirming the row exists somewhere else. Any valid access token reaches it. The per-kind permission table has no entry for tokentransaction, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"tokentransactionid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"patch":{"operationId":"patch_commerce_tokentransaction_by_tokentransactionid","summary":"Change part of a token transaction","description":"A token transaction records a transfer between two identified parties — amount and fees, a timestamp, sending and receiving addresses, names, user ids, states and countries, a flag per side, a protocol name and a transaction hash. Nothing here touches a chain: the hash is an unvalidated string and the flags are plain writable booleans with no screening behind them. Amounts are floating-point rather than the exact minor units every real money field in commerce uses, and there is no currency field at all — this kind lives in commerce's demo tree, so it is a live writable resource in your tenant's store that nothing else in commerce reads, and it must never carry real money. Loads the stored row and decodes the body OVER it, so only the fields the body names change and everything else keeps its stored value — the difference from the full replace, which clears what it is not told. Answers the merged row. An id absent from the caller org's namespace is 404 and a body that fails to decode is 400. Any valid access token reaches it. The per-kind permission table has no entry for tokentransaction, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"tokentransactionid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_tokentransaction_by_tokentransactionid","summary":"Method-override tunnel for a token transaction — for clients that cannot send PUT, PATCH or DELETE","description":"A token transaction records a transfer between two identified parties — amount and fees, a timestamp, sending and receiving addresses, names, user ids, states and countries, a flag per side, a protocol name and a transaction hash. Nothing here touches a chain: the hash is an unvalidated string and the flags are plain writable booleans with no screening behind them. Amounts are floating-point rather than the exact minor units every real money field in commerce uses, and there is no currency field at all — this kind lives in commerce's demo tree, so it is a live writable resource in your tenant's store that nothing else in commerce reads, and it must never carry real money. Re-dispatches the request into the handler the intended verb would have reached, taking that verb from a _method form value or query parameter and then from the X-HTTP-Method-Override header. PUT replaces the row, PATCH changes part of it, DELETE removes it, and anything else is 405. The trap is the DEFAULT: naming no override at all leaves the method POST, which this tunnel maps to the PARTIAL UPDATE — it is never a create, and creating is the collection root's job. Behaviour and authorization are the underlying operation's, since the real handler runs. Any valid access token reaches it.","tags":["commerce"],"parameters":[{"name":"tokentransactionid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"put":{"operationId":"put_commerce_tokentransaction_by_tokentransactionid","summary":"Replace a token transaction outright","description":"A token transaction records a transfer between two identified parties — amount and fees, a timestamp, sending and receiving addresses, names, user ids, states and countries, a flag per side, a protocol name and a transaction hash. Nothing here touches a chain: the hash is an unvalidated string and the flags are plain writable booleans with no screening behind them. Amounts are floating-point rather than the exact minor units every real money field in commerce uses, and there is no currency field at all — this kind lives in commerce's demo tree, so it is a live writable resource in your tenant's store that nothing else in commerce reads, and it must never carry real money. This is a true REPLACEMENT, not a merge: the stored row's key is preserved, but the body is decoded onto a FRESH entity, so every field the body omits is written back as its ZERO value. Patch is the verb for changing part of a row. The id is resolved inside the caller org's own namespace and an absent one is 404 before anything is written; a body that fails to decode is 400. Answers the stored result. Any valid access token reaches it. The per-kind permission table has no entry for tokentransaction, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"tokentransactionid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/transfer":{"get":{"operationId":"get_commerce_transfer","summary":"List your org's transfers, as a page","description":"A transfer records that a payable WAS PAID — the annotation a human writes after paying out of band. Commerce executes no payout: creating one moves no money, and it marks the referenced payable settled. It carries the payable and payee ids, the amount it settles and the amount actually sent (which may be a different asset), a type of eth, wire or other, the transaction hash or wire reference, when it was paid and who recorded it; amounts are exact decimal strings with an asset, not cents. It is admin-gated because writing one settles money we owe, and nothing enforces uniqueness on the reference — so posting the same transfer twice settles the payable twice. Answers a pagination envelope — the page and display echoed back, the rows under models, a total count and a facets array — read from the caller org's own namespaced store, so one tenant can never list another's. Sorting defaults to the last-updated time and is overridable with sort. display is the page size and page applies only alongside it; either one that is not a positive integer is refused with 500 rather than silently ignored, and the limit query overrides the reported COUNT only, never the rows returned. No search backend is wired, so the datastore is the one and only list path and facets is always empty. A request resolving no org namespace is served an EMPTY page rather than an unscoped scan: the namespace IS the tenant filter, so without one there is nothing safe to return. The token must carry the ADMIN permission; an ordinary access token is refused. The per-kind permission table has no entry for transfer, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_transfer","summary":"Create a transfer","description":"A transfer records that a payable WAS PAID — the annotation a human writes after paying out of band. Commerce executes no payout: creating one moves no money, and it marks the referenced payable settled. It carries the payable and payee ids, the amount it settles and the amount actually sent (which may be a different asset), a type of eth, wire or other, the transaction hash or wire reference, when it was paid and who recorded it; amounts are exact decimal strings with an asset, not cents. It is admin-gated because writing one settles money we owe, and nothing enforces uniqueness on the reference — so posting the same transfer twice settles the payable twice. Decodes the body into a new row in the caller org's own namespaced store — isolated to that tenant from its first write — and answers the stored row at 201 with a Location header naming its id. The id is assigned by the store, not taken from the body. A body that fails to decode is 400 and a store that refuses the write is 500. The token must carry the ADMIN permission; an ordinary access token is refused. The per-kind permission table has no entry for transfer, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/transfer/{transferid}":{"delete":{"operationId":"delete_commerce_transfer_by_transferid","summary":"Delete a transfer, keeping a recoverable copy","description":"A transfer records that a payable WAS PAID — the annotation a human writes after paying out of band. Commerce executes no payout: creating one moves no money, and it marks the referenced payable settled. It carries the payable and payee ids, the amount it settles and the amount actually sent (which may be a different asset), a type of eth, wire or other, the transaction hash or wire reference, when it was paid and who recorded it; amounts are exact decimal strings with an asset, not cents. It is admin-gated because writing one settles money we owe, and nothing enforces uniqueness on the reference — so posting the same transfer twice settles the payable twice. Removes the addressed row and answers 204 with no body. Before the live row goes it is written once more under a deleted tombstone kind, so a deletion leaves a recoverable copy rather than destroying the record outright — and a tombstone that cannot be written fails the call with 500 before anything is removed. The id is resolved inside the caller org's own namespace, so an absent or foreign id is 404. The token must carry the ADMIN permission; an ordinary access token is refused. The per-kind permission table has no entry for transfer, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"transferid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"get":{"operationId":"get_commerce_transfer_by_transferid","summary":"Fetch one transfer","description":"A transfer records that a payable WAS PAID — the annotation a human writes after paying out of band. Commerce executes no payout: creating one moves no money, and it marks the referenced payable settled. It carries the payable and payee ids, the amount it settles and the amount actually sent (which may be a different asset), a type of eth, wire or other, the transaction hash or wire reference, when it was paid and who recorded it; amounts are exact decimal strings with an asset, not cents. It is admin-gated because writing one settles money we owe, and nothing enforces uniqueness on the reference — so posting the same transfer twice settles the payable twice. Reads the addressed row from the caller org's own namespaced store. An id that is not there is 404 — and another tenant's id is not there by construction, so it reads exactly like a typo instead of confirming the row exists somewhere else. The token must carry the ADMIN permission; an ordinary access token is refused. The per-kind permission table has no entry for transfer, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"transferid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"patch":{"operationId":"patch_commerce_transfer_by_transferid","summary":"Change part of a transfer","description":"A transfer records that a payable WAS PAID — the annotation a human writes after paying out of band. Commerce executes no payout: creating one moves no money, and it marks the referenced payable settled. It carries the payable and payee ids, the amount it settles and the amount actually sent (which may be a different asset), a type of eth, wire or other, the transaction hash or wire reference, when it was paid and who recorded it; amounts are exact decimal strings with an asset, not cents. It is admin-gated because writing one settles money we owe, and nothing enforces uniqueness on the reference — so posting the same transfer twice settles the payable twice. Loads the stored row and decodes the body OVER it, so only the fields the body names change and everything else keeps its stored value — the difference from the full replace, which clears what it is not told. Answers the merged row. An id absent from the caller org's namespace is 404 and a body that fails to decode is 400. The token must carry the ADMIN permission; an ordinary access token is refused. The per-kind permission table has no entry for transfer, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"transferid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_transfer_by_transferid","summary":"Method-override tunnel for a transfer — for clients that cannot send PUT, PATCH or DELETE","description":"A transfer records that a payable WAS PAID — the annotation a human writes after paying out of band. Commerce executes no payout: creating one moves no money, and it marks the referenced payable settled. It carries the payable and payee ids, the amount it settles and the amount actually sent (which may be a different asset), a type of eth, wire or other, the transaction hash or wire reference, when it was paid and who recorded it; amounts are exact decimal strings with an asset, not cents. It is admin-gated because writing one settles money we owe, and nothing enforces uniqueness on the reference — so posting the same transfer twice settles the payable twice. Re-dispatches the request into the handler the intended verb would have reached, taking that verb from a _method form value or query parameter and then from the X-HTTP-Method-Override header. PUT replaces the row, PATCH changes part of it, DELETE removes it, and anything else is 405. The trap is the DEFAULT: naming no override at all leaves the method POST, which this tunnel maps to the PARTIAL UPDATE — it is never a create, and creating is the collection root's job. Behaviour and authorization are the underlying operation's, since the real handler runs. The token must carry the ADMIN permission; an ordinary access token is refused.","tags":["commerce"],"parameters":[{"name":"transferid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"put":{"operationId":"put_commerce_transfer_by_transferid","summary":"Replace a transfer outright","description":"A transfer records that a payable WAS PAID — the annotation a human writes after paying out of band. Commerce executes no payout: creating one moves no money, and it marks the referenced payable settled. It carries the payable and payee ids, the amount it settles and the amount actually sent (which may be a different asset), a type of eth, wire or other, the transaction hash or wire reference, when it was paid and who recorded it; amounts are exact decimal strings with an asset, not cents. It is admin-gated because writing one settles money we owe, and nothing enforces uniqueness on the reference — so posting the same transfer twice settles the payable twice. This is a true REPLACEMENT, not a merge: the stored row's key is preserved, but the body is decoded onto a FRESH entity, so every field the body omits is written back as its ZERO value. Patch is the verb for changing part of a row. The id is resolved inside the caller org's own namespace and an absent one is 404 before anything is written; a body that fails to decode is 400. Answers the stored result. The token must carry the ADMIN permission; an ordinary access token is refused. The per-kind permission table has no entry for transfer, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"transferid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/variant":{"get":{"operationId":"get_commerce_variant","summary":"List your org's variants, as a page","description":"A variant is one purchasable SKU of a product — its product id, SKU and UPC, name, media, availability, the option name and value pairs that distinguish it, a sold counter, and its own money and stock: currency, price, MSRP, inventory cost, inventory count and taxability. Inventory and sold are plain writable numbers with no decrement logic behind them here. The same variant also exists as a JSON copy inside its product, and writing one does not update the other. Answers a pagination envelope — the page and display echoed back, the rows under models, a total count and a facets array — read from the caller org's own namespaced store, so one tenant can never list another's. Sorting defaults to the SKU and is overridable with sort. display is the page size and page applies only alongside it; either one that is not a positive integer is refused with 500 rather than silently ignored, and the limit query overrides the reported COUNT only, never the rows returned. No search backend is wired, so the datastore is the one and only list path and facets is always empty. A request resolving no org namespace is served an EMPTY page rather than an unscoped scan: the namespace IS the tenant filter, so without one there is nothing safe to return. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The token must also carry Admin or the Variant list scope.","tags":["commerce"],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_variant","summary":"Create a variant","description":"A variant is one purchasable SKU of a product — its product id, SKU and UPC, name, media, availability, the option name and value pairs that distinguish it, a sold counter, and its own money and stock: currency, price, MSRP, inventory cost, inventory count and taxability. Inventory and sold are plain writable numbers with no decrement logic behind them here. The same variant also exists as a JSON copy inside its product, and writing one does not update the other. Decodes the body into a new row in the caller org's own namespaced store — isolated to that tenant from its first write — and answers the stored row at 201 with a Location header naming its id. The id is assigned by the store, not taken from the body. A body that fails to decode is 400 and a store that refuses the write is 500. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The token must also carry Admin or WriteVariant.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/variant/{variantid}":{"delete":{"operationId":"delete_commerce_variant_by_variantid","summary":"Delete a variant, keeping a recoverable copy","description":"A variant is one purchasable SKU of a product — its product id, SKU and UPC, name, media, availability, the option name and value pairs that distinguish it, a sold counter, and its own money and stock: currency, price, MSRP, inventory cost, inventory count and taxability. Inventory and sold are plain writable numbers with no decrement logic behind them here. The same variant also exists as a JSON copy inside its product, and writing one does not update the other. Removes the addressed row and answers 204 with no body. Before the live row goes it is written once more under a deleted tombstone kind, so a deletion leaves a recoverable copy rather than destroying the record outright — and a tombstone that cannot be written fails the call with 500 before anything is removed. The id is resolved inside the caller org's own namespace, so an absent or foreign id is 404. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The token must also carry Admin or WriteVariant.","tags":["commerce"],"parameters":[{"name":"variantid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"get":{"operationId":"get_commerce_variant_by_variantid","summary":"Fetch one variant","description":"A variant is one purchasable SKU of a product — its product id, SKU and UPC, name, media, availability, the option name and value pairs that distinguish it, a sold counter, and its own money and stock: currency, price, MSRP, inventory cost, inventory count and taxability. Inventory and sold are plain writable numbers with no decrement logic behind them here. The same variant also exists as a JSON copy inside its product, and writing one does not update the other. Reads the addressed row from the caller org's own namespaced store. An id that is not there is 404 — and another tenant's id is not there by construction, so it reads exactly like a typo instead of confirming the row exists somewhere else. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The token must also carry Admin or ReadVariant.","tags":["commerce"],"parameters":[{"name":"variantid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"patch":{"operationId":"patch_commerce_variant_by_variantid","summary":"Change part of a variant","description":"A variant is one purchasable SKU of a product — its product id, SKU and UPC, name, media, availability, the option name and value pairs that distinguish it, a sold counter, and its own money and stock: currency, price, MSRP, inventory cost, inventory count and taxability. Inventory and sold are plain writable numbers with no decrement logic behind them here. The same variant also exists as a JSON copy inside its product, and writing one does not update the other. Loads the stored row and decodes the body OVER it, so only the fields the body names change and everything else keeps its stored value — the difference from the full replace, which clears what it is not told. Answers the merged row. An id absent from the caller org's namespace is 404 and a body that fails to decode is 400. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The token must also carry Admin, or ReadVariant and WriteVariant together.","tags":["commerce"],"parameters":[{"name":"variantid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_variant_by_variantid","summary":"Method-override tunnel for a variant — for clients that cannot send PUT, PATCH or DELETE","description":"A variant is one purchasable SKU of a product — its product id, SKU and UPC, name, media, availability, the option name and value pairs that distinguish it, a sold counter, and its own money and stock: currency, price, MSRP, inventory cost, inventory count and taxability. Inventory and sold are plain writable numbers with no decrement logic behind them here. The same variant also exists as a JSON copy inside its product, and writing one does not update the other. Re-dispatches the request into the handler the intended verb would have reached, taking that verb from a _method form value or query parameter and then from the X-HTTP-Method-Override header. PUT replaces the row, PATCH changes part of it, DELETE removes it, and anything else is 405. The trap is the DEFAULT: naming no override at all leaves the method POST, which this tunnel maps to the PARTIAL UPDATE — it is never a create, and creating is the collection root's job. Behaviour and authorization are the underlying operation's, since the real handler runs. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through.","tags":["commerce"],"parameters":[{"name":"variantid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"put":{"operationId":"put_commerce_variant_by_variantid","summary":"Replace a variant outright","description":"A variant is one purchasable SKU of a product — its product id, SKU and UPC, name, media, availability, the option name and value pairs that distinguish it, a sold counter, and its own money and stock: currency, price, MSRP, inventory cost, inventory count and taxability. Inventory and sold are plain writable numbers with no decrement logic behind them here. The same variant also exists as a JSON copy inside its product, and writing one does not update the other. This is a true REPLACEMENT, not a merge: the stored row's key is preserved, but the body is decoded onto a FRESH entity, so every field the body omits is written back as its ZERO value. Patch is the verb for changing part of a row. The id is resolved inside the caller org's own namespace and an absent one is 404 before anything is written; a body that fails to decode is 400. Answers the stored result. Any valid access token reaches it. The org must also be entitled to the commerce admin: the paywall answers 402 subscription_required unless the org holds an active or trialing pro subscription, a live trial credit or a redeemed invite, and 503 when that entitlement cannot be read rather than admitting on an unknown. A platform superadmin passes straight through. The token must also carry Admin, or ReadVariant and WriteVariant together.","tags":["commerce"],"parameters":[{"name":"variantid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/wallet":{"get":{"operationId":"get_commerce_wallet","summary":"List your org's wallets, as a page","description":"A wallet is a container of custodial blockchain accounts, and its only field is that account list — each account carrying a name, an address, a chain type, and the ENCRYPTED private key with its salt. Creating a wallet through this table generates NO KEYS: key generation lives on the account routes, so a wallet made here is an empty shell and an account posted into one is stored exactly as sent, with no key generation and no validation behind it. Know what a read renders: the plaintext private key is never marshalled and never stored, but the encrypted blob and its salt ARE returned, so whoever can read a wallet can attack it offline down to the strength of the owner's passphrase. That is why this kind is admin-gated. Answers a pagination envelope — the page and display echoed back, the rows under models, a total count and a facets array — read from the caller org's own namespaced store, so one tenant can never list another's. Sorting defaults to the last-updated time and is overridable with sort. display is the page size and page applies only alongside it; either one that is not a positive integer is refused with 500 rather than silently ignored, and the limit query overrides the reported COUNT only, never the rows returned. No search backend is wired, so the datastore is the one and only list path and facets is always empty. A request resolving no org namespace is served an EMPTY page rather than an unscoped scan: the namespace IS the tenant filter, so without one there is nothing safe to return. The token must carry the ADMIN permission; an ordinary access token is refused. The per-kind permission table has no entry for wallet, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_wallet","summary":"Create a wallet","description":"A wallet is a container of custodial blockchain accounts, and its only field is that account list — each account carrying a name, an address, a chain type, and the ENCRYPTED private key with its salt. Creating a wallet through this table generates NO KEYS: key generation lives on the account routes, so a wallet made here is an empty shell and an account posted into one is stored exactly as sent, with no key generation and no validation behind it. Know what a read renders: the plaintext private key is never marshalled and never stored, but the encrypted blob and its salt ARE returned, so whoever can read a wallet can attack it offline down to the strength of the owner's passphrase. That is why this kind is admin-gated. Decodes the body into a new row in the caller org's own namespaced store — isolated to that tenant from its first write — and answers the stored row at 201 with a Location header naming its id. The id is assigned by the store, not taken from the body. A body that fails to decode is 400 and a store that refuses the write is 500. The token must carry the ADMIN permission; an ordinary access token is refused. The per-kind permission table has no entry for wallet, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/wallet/{walletid}":{"delete":{"operationId":"delete_commerce_wallet_by_walletid","summary":"Delete a wallet, keeping a recoverable copy","description":"A wallet is a container of custodial blockchain accounts, and its only field is that account list — each account carrying a name, an address, a chain type, and the ENCRYPTED private key with its salt. Creating a wallet through this table generates NO KEYS: key generation lives on the account routes, so a wallet made here is an empty shell and an account posted into one is stored exactly as sent, with no key generation and no validation behind it. Know what a read renders: the plaintext private key is never marshalled and never stored, but the encrypted blob and its salt ARE returned, so whoever can read a wallet can attack it offline down to the strength of the owner's passphrase. That is why this kind is admin-gated. Removes the addressed row and answers 204 with no body. Before the live row goes it is written once more under a deleted tombstone kind, so a deletion leaves a recoverable copy rather than destroying the record outright — and a tombstone that cannot be written fails the call with 500 before anything is removed. The id is resolved inside the caller org's own namespace, so an absent or foreign id is 404. The token must carry the ADMIN permission; an ordinary access token is refused. The per-kind permission table has no entry for wallet, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"walletid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"get":{"operationId":"get_commerce_wallet_by_walletid","summary":"Fetch one wallet","description":"A wallet is a container of custodial blockchain accounts, and its only field is that account list — each account carrying a name, an address, a chain type, and the ENCRYPTED private key with its salt. Creating a wallet through this table generates NO KEYS: key generation lives on the account routes, so a wallet made here is an empty shell and an account posted into one is stored exactly as sent, with no key generation and no validation behind it. Know what a read renders: the plaintext private key is never marshalled and never stored, but the encrypted blob and its salt ARE returned, so whoever can read a wallet can attack it offline down to the strength of the owner's passphrase. That is why this kind is admin-gated. Reads the addressed row from the caller org's own namespaced store. An id that is not there is 404 — and another tenant's id is not there by construction, so it reads exactly like a typo instead of confirming the row exists somewhere else. The token must carry the ADMIN permission; an ordinary access token is refused. The per-kind permission table has no entry for wallet, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"walletid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"patch":{"operationId":"patch_commerce_wallet_by_walletid","summary":"Change part of a wallet","description":"A wallet is a container of custodial blockchain accounts, and its only field is that account list — each account carrying a name, an address, a chain type, and the ENCRYPTED private key with its salt. Creating a wallet through this table generates NO KEYS: key generation lives on the account routes, so a wallet made here is an empty shell and an account posted into one is stored exactly as sent, with no key generation and no validation behind it. Know what a read renders: the plaintext private key is never marshalled and never stored, but the encrypted blob and its salt ARE returned, so whoever can read a wallet can attack it offline down to the strength of the owner's passphrase. That is why this kind is admin-gated. Loads the stored row and decodes the body OVER it, so only the fields the body names change and everything else keeps its stored value — the difference from the full replace, which clears what it is not told. Answers the merged row. An id absent from the caller org's namespace is 404 and a body that fails to decode is 400. The token must carry the ADMIN permission; an ordinary access token is refused. The per-kind permission table has no entry for wallet, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"walletid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_wallet_by_walletid","summary":"Method-override tunnel for a wallet — for clients that cannot send PUT, PATCH or DELETE","description":"A wallet is a container of custodial blockchain accounts, and its only field is that account list — each account carrying a name, an address, a chain type, and the ENCRYPTED private key with its salt. Creating a wallet through this table generates NO KEYS: key generation lives on the account routes, so a wallet made here is an empty shell and an account posted into one is stored exactly as sent, with no key generation and no validation behind it. Know what a read renders: the plaintext private key is never marshalled and never stored, but the encrypted blob and its salt ARE returned, so whoever can read a wallet can attack it offline down to the strength of the owner's passphrase. That is why this kind is admin-gated. Re-dispatches the request into the handler the intended verb would have reached, taking that verb from a _method form value or query parameter and then from the X-HTTP-Method-Override header. PUT replaces the row, PATCH changes part of it, DELETE removes it, and anything else is 405. The trap is the DEFAULT: naming no override at all leaves the method POST, which this tunnel maps to the PARTIAL UPDATE — it is never a create, and creating is the collection root's job. Behaviour and authorization are the underlying operation's, since the real handler runs. The token must carry the ADMIN permission; an ordinary access token is refused.","tags":["commerce"],"parameters":[{"name":"walletid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"put":{"operationId":"put_commerce_wallet_by_walletid","summary":"Replace a wallet outright","description":"A wallet is a container of custodial blockchain accounts, and its only field is that account list — each account carrying a name, an address, a chain type, and the ENCRYPTED private key with its salt. Creating a wallet through this table generates NO KEYS: key generation lives on the account routes, so a wallet made here is an empty shell and an account posted into one is stored exactly as sent, with no key generation and no validation behind it. Know what a read renders: the plaintext private key is never marshalled and never stored, but the encrypted blob and its salt ARE returned, so whoever can read a wallet can attack it offline down to the strength of the owner's passphrase. That is why this kind is admin-gated. This is a true REPLACEMENT, not a merge: the stored row's key is preserved, but the body is decoded onto a FRESH entity, so every field the body omits is written back as its ZERO value. Patch is the verb for changing part of a row. The id is resolved inside the caller org's own namespace and an absent one is 404 before anything is written; a body that fails to decode is 400. Answers the stored result. The token must carry the ADMIN permission; an ordinary access token is refused. The per-kind permission table has no entry for wallet, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"walletid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/watchlist":{"get":{"operationId":"get_commerce_watchlist","summary":"List your org's watchlists, as a page","description":"A watchlist is a viewer's saved list of movies — a user id, an email, and the movies themselves. It stores WHOLE MOVIE SNAPSHOTS rather than movie ids, so a list goes stale the moment a film record changes and grows without bound as it fills. Answers a pagination envelope — the page and display echoed back, the rows under models, a total count and a facets array — read from the caller org's own namespaced store, so one tenant can never list another's. Sorting defaults to the last-updated time and is overridable with sort. display is the page size and page applies only alongside it; either one that is not a positive integer is refused with 500 rather than silently ignored, and the limit query overrides the reported COUNT only, never the rows returned. No search backend is wired, so the datastore is the one and only list path and facets is always empty. A request resolving no org namespace is served an EMPTY page rather than an unscoped scan: the namespace IS the tenant filter, so without one there is nothing safe to return. Any valid access token reaches it. The per-kind permission table has no entry for watchlist, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_watchlist","summary":"Create a watchlist","description":"A watchlist is a viewer's saved list of movies — a user id, an email, and the movies themselves. It stores WHOLE MOVIE SNAPSHOTS rather than movie ids, so a list goes stale the moment a film record changes and grows without bound as it fills. Decodes the body into a new row in the caller org's own namespaced store — isolated to that tenant from its first write — and answers the stored row at 201 with a Location header naming its id. The id is assigned by the store, not taken from the body. A body that fails to decode is 400 and a store that refuses the write is 500. Any valid access token reaches it. The per-kind permission table has no entry for watchlist, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"x-app":"commerce","x-public":true}},"/v1/commerce/watchlist/{watchlistid}":{"delete":{"operationId":"delete_commerce_watchlist_by_watchlistid","summary":"Delete a watchlist, keeping a recoverable copy","description":"A watchlist is a viewer's saved list of movies — a user id, an email, and the movies themselves. It stores WHOLE MOVIE SNAPSHOTS rather than movie ids, so a list goes stale the moment a film record changes and grows without bound as it fills. Removes the addressed row and answers 204 with no body. Before the live row goes it is written once more under a deleted tombstone kind, so a deletion leaves a recoverable copy rather than destroying the record outright — and a tombstone that cannot be written fails the call with 500 before anything is removed. The id is resolved inside the caller org's own namespace, so an absent or foreign id is 404. Any valid access token reaches it. The per-kind permission table has no entry for watchlist, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"watchlistid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"get":{"operationId":"get_commerce_watchlist_by_watchlistid","summary":"Fetch one watchlist","description":"A watchlist is a viewer's saved list of movies — a user id, an email, and the movies themselves. It stores WHOLE MOVIE SNAPSHOTS rather than movie ids, so a list goes stale the moment a film record changes and grows without bound as it fills. Reads the addressed row from the caller org's own namespaced store. An id that is not there is 404 — and another tenant's id is not there by construction, so it reads exactly like a typo instead of confirming the row exists somewhere else. Any valid access token reaches it. The per-kind permission table has no entry for watchlist, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"watchlistid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"patch":{"operationId":"patch_commerce_watchlist_by_watchlistid","summary":"Change part of a watchlist","description":"A watchlist is a viewer's saved list of movies — a user id, an email, and the movies themselves. It stores WHOLE MOVIE SNAPSHOTS rather than movie ids, so a list goes stale the moment a film record changes and grows without bound as it fills. Loads the stored row and decodes the body OVER it, so only the fields the body names change and everything else keeps its stored value — the difference from the full replace, which clears what it is not told. Answers the merged row. An id absent from the caller org's namespace is 404 and a body that fails to decode is 400. Any valid access token reaches it. The per-kind permission table has no entry for watchlist, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"watchlistid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"post":{"operationId":"post_commerce_watchlist_by_watchlistid","summary":"Method-override tunnel for a watchlist — for clients that cannot send PUT, PATCH or DELETE","description":"A watchlist is a viewer's saved list of movies — a user id, an email, and the movies themselves. It stores WHOLE MOVIE SNAPSHOTS rather than movie ids, so a list goes stale the moment a film record changes and grows without bound as it fills. Re-dispatches the request into the handler the intended verb would have reached, taking that verb from a _method form value or query parameter and then from the X-HTTP-Method-Override header. PUT replaces the row, PATCH changes part of it, DELETE removes it, and anything else is 405. The trap is the DEFAULT: naming no override at all leaves the method POST, which this tunnel maps to the PARTIAL UPDATE — it is never a create, and creating is the collection root's job. Behaviour and authorization are the underlying operation's, since the real handler runs. Any valid access token reaches it.","tags":["commerce"],"parameters":[{"name":"watchlistid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true},"put":{"operationId":"put_commerce_watchlist_by_watchlistid","summary":"Replace a watchlist outright","description":"A watchlist is a viewer's saved list of movies — a user id, an email, and the movies themselves. It stores WHOLE MOVIE SNAPSHOTS rather than movie ids, so a list goes stale the moment a film record changes and grows without bound as it fills. This is a true REPLACEMENT, not a merge: the stored row's key is preserved, but the body is decoded onto a FRESH entity, so every field the body omits is written back as its ZERO value. Patch is the verb for changing part of a row. The id is resolved inside the caller org's own namespace and an absent one is 404 before anything is written; a body that fails to decode is 400. Answers the stored result. Any valid access token reaches it. The per-kind permission table has no entry for watchlist, so the scaffold skips that second check with a warning and the gate above is the whole authorization story.","tags":["commerce"],"parameters":[{"name":"watchlistid","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/commerce/webhooks/{provider}":{"post":{"operationId":"post_commerce_webhooks_by_provider","summary":"Payment-provider webhook intake for settlement and subscription lifecycle events","description":"Accepts a payment provider's event, verifies it, applies its settlement, refund, dispute and subscription effects, and records it for audit. There is no bearer here and there cannot be: the provider's SIGNATURE over the body IS the authentication, so a request with no recognized signature header is 400 and one whose signature does not verify is 401. The path names the one processor that verifies, and only a processor holding its webhook secret may; any other name is 401. Each event is applied once for the whole deployment: a redelivery of an applied event is acknowledged as a duplicate, one still being applied is 409, and an event whose effect could not land is 503 so the provider redelivers it.","tags":["commerce"],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"commerce","x-public":true}},"/v1/company":{"get":{"operationId":"get_company","summary":"Returns the caller org's formation and the stages reachable from it, or 404 when the org has not begun one.","description":"Returns the caller org's formation and the stages reachable from it, or 404\nwhen the org has not begun one.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["company"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.formationView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true},"post":{"operationId":"post_company","summary":"Starts the org's one formation and returns it with the stages reachable from it.","description":"Starts the org's one formation and returns it with the stages reachable\nfrom it. It is idempotent: an org that already has a formation gets that one\nback with 200, while a first call creates it and answers 201.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["company"],"requestBody":{"content":{"application/json":{"example":{"jurisdiction":"DE","name":"AgentCo, LLC","structure":"c-corp"},"schema":{"$ref":"#/components/schemas/company.beginIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.formationView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/advance":{"post":{"operationId":"post_company_advance","summary":"Runs the ONE guarded transition of the formation machine.","description":"Runs the ONE guarded transition of the formation machine. It is the\nonly endpoint between stages: the actions populate data, this decides ordering.\n\nAn edge the machine does not define answers 409; an edge whose guard is not yet\nsatisfied answers 422 naming what is missing. Reaching the terminal `company`\nstage also records the incorporation on the canonical cap table, and that must\nsucceed before the transition is persisted.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["company"],"requestBody":{"content":{"application/json":{"example":{"to":"founders"},"schema":{"$ref":"#/components/schemas/company.advanceIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.formationView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/documents":{"post":{"operationId":"post_company_documents","summary":"Renders the formation documents for the chosen structure and jurisdiction, ingests each into the org's data room, and submits the state filing through the filing client.","description":"Renders the formation documents for the chosen structure and\njurisdiction, ingests each into the org's data room, and submits the state\nfiling through the filing client.\n\nWith no filing partner wired the filing is recorded honestly as \"manual\" — no\nfiling id is fabricated. Available only at the documents stage.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["company"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.formationView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/ein":{"post":{"operationId":"post_company_ein","summary":"Opens the EIN application and answers what it owes.","description":"Opens the EIN application and answers what it owes.\n\nThe answer states whether it can be filed ONLINE, because that is the fact\ndeciding whether the customer waits a sitting or several weeks — and it names\neach form with what that form is for, so nobody has to already know what an\nSS-4 is to understand why they are signing one.","tags":["company"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.einIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.EIN"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/esign":{"post":{"operationId":"post_company_esign","summary":"Sends the generated formation documents for signature by every founder and records the provider's reference on the formation.","description":"Sends the generated formation documents for signature by every\nfounder and records the provider's reference on the formation. Available only\nat the esign stage.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["company"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.esignOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/esign/complete":{"post":{"operationId":"post_company_esign_complete","summary":"Records whether the formation documents have been signed.","description":"Records whether the formation documents have been signed. It\nconsults the e-signature provider, which a real provider's webhook drives; the\nsignal is idempotent.\n\nAn explicit `signed` in the request overrides the provider's answer, which is\nthe manual path for the stub provider that never self-completes.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["company"],"requestBody":{"content":{"application/json":{"example":{"signed":true},"schema":{"$ref":"#/components/schemas/company.esignCompleteIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.formationView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/founders":{"post":{"operationId":"post_company_founders","summary":"Replaces the formation's founders.","description":"Replaces the formation's founders. Each founder needs a name, an\nemail and an equity share in basis points; every founder is (re)set to pending\nKYC, so a previously settled decision does not survive a change of the list.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["company"],"requestBody":{"content":{"application/json":{"example":{"founders":[{"email":"ada@acme.com","equityBps":10000,"name":"Ada"}]},"schema":{"$ref":"#/components/schemas/company.foundersIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.formationView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/fundraise/deck":{"post":{"operationId":"post_company_fundraise_deck","summary":"Share a pitch deck in the org's data room","description":"Stores the request body as a document in the caller org's data room and answers with the data room id to reference it by. The deck is RAW BYTES of whatever content type is sent — a PDF, a slide export — not a JSON document: the Content-Type header is carried through to the data room as given, and `?name=` names the document, defaulting to `pitch-deck`.\n\nScoped to the caller's validated org, for a SuperAdmin or an admin of that org (a member who is neither is refused 403), and only after incorporation: a formation still short of stage `company` is refused 409 and an org that never began one is 404. The route is registered AHEAD of the surface's JSON body cap deliberately, so a deck's size ceiling is the edge's rather than the cap meant for small structured records. An empty body is 400; a data room that will not take the bytes is 502.","tags":["company"],"requestBody":{"content":{"application/octet-stream":{"schema":{"format":"binary","type":"string"}}}},"responses":{"2XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/deckOut"}}},"description":"Success"}},"x-app":"company","x-public":true}},"/v1/company/fundraise/round":{"post":{"operationId":"post_company_fundraise_round","summary":"Records a fundraising round on the org's canonical cap table.","description":"Records a fundraising round on the org's canonical cap table.\nAvailable only after incorporation (stage company); roundType defaults to\nPRICED.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["company"],"requestBody":{"content":{"application/json":{"example":{"name":"Seed","roundType":"PRICED","targetAmount":2000000},"schema":{"$ref":"#/components/schemas/company.RoundInput"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.roundOut"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/fundraise/safe":{"post":{"operationId":"post_company_fundraise_safe","summary":"Raises an e-signature request over documents already in the org's data room — a SAFE, a convertible note, or any other fundraising paper.","description":"Raises an e-signature request over documents already in the org's\ndata room — a SAFE, a convertible note, or any other fundraising paper.\nAvailable only after incorporation (stage company).\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["company"],"requestBody":{"content":{"application/json":{"example":{"documentIds":["doc_safe"],"signers":[{"email":"ada@acme.com","name":"Ada"}]},"schema":{"$ref":"#/components/schemas/company.safeIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.safeOut"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/genesis":{"post":{"operationId":"post_company_genesis","summary":"Seeds the canonical cap table with the founding allocation (stakeholders, a common share class, issued shares) and anchors the deterministic equity-genesis root on-chain.","description":"Seeds the canonical cap table with the founding allocation\n(stakeholders, a common share class, issued shares) and anchors the\ndeterministic equity-genesis root on-chain.\n\nIt is idempotent: once a root is recorded the cap table is NOT re-seeded, which\nwould double-issue founder share certificates. The root is persisted even when\nthe on-chain submit fails, because the root is the tamper-evident witness and\nmust not be recomputed on retry. Available only at the genesis stage.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["company"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.formationView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/import/captable":{"post":{"operationId":"post_company_import_captable","summary":"Reads an existing company's cap table from a Google Sheet and adds its stakeholders to the canonical cap table.","description":"Reads an existing company's cap table from a Google Sheet and\nadds its stakeholders to the canonical cap table.\n\nThe first row is a header and columns are matched by name (case-insensitive):\nname and email are required, type/relationship/institution optional. A sheet\nwithout name and email columns, or with no usable data rows, is refused with\n400. Available only at the import stage.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["company"],"requestBody":{"content":{"application/json":{"example":{"range":"Cap Table!A1:E100","spreadsheetId":"1AbCdEfGhIjKlMnOpQrStUvWxYz"},"schema":{"$ref":"#/components/schemas/company.importCapTableIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.importCapTableOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/import/documents":{"post":{"operationId":"post_company_import_documents","summary":"Ingests an existing company's corporate documents from a Google Drive folder into the org's data room.","description":"Ingests an existing company's corporate documents from a Google\nDrive folder into the org's data room. The import is shallow — sub-folders are\nskipped, not walked — and available only at the import stage.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["company"],"requestBody":{"content":{"application/json":{"example":{"folderId":"1AbCdEfGhIjKlMnOpQrStUvWxYz"},"schema":{"$ref":"#/components/schemas/company.importDocumentsIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.importDocumentsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/kyc":{"post":{"operationId":"post_company_kyc","summary":"Opens an identity-verification session for every founder with the wired provider and records each session's reference on the formation.","description":"Opens an identity-verification session for every founder with the\nwired provider and records each session's reference on the formation.\n\nA start is never a decision: any terminal status the provider reports at\ninquiry time is clamped back to pending, so the payment gate can never open\nhere. A terminal status arrives only from POST /v1/company/kyc/refresh (the\nprovider) or POST /v1/company/kyc/decision (a Hanzo platform reviewer).\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["company"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.kycStartOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/kyc/refresh":{"post":{"operationId":"post_company_kyc_refresh","summary":"RefreshKYC reconciles each pending founder's KYC with the WIRED provider — the PULL path to a provider-reported terminal status.","description":"RefreshKYC reconciles each pending founder's KYC with the WIRED provider — the\nPULL path to a provider-reported terminal status. For the manual provider the\ncheck stays pending; for a real provider it reflects the settled decision,\nATTRIBUTED to the provider.\n\nIt NEVER trusts a client-asserted status — the status comes from the PROVIDER —\nso a client cannot force a pass here, and an already-passing founder (e.g. a\nreviewer confirmation) is left untouched.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["company"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.kycRefreshOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/payment":{"post":{"operationId":"post_company_payment","summary":"Charges the caller's own org the one-time Hanzo Company formation fee.","description":"Charges the caller's own org the one-time Hanzo Company formation fee.\n\nIt is $999 unless the deployment sets another, and the answer is the formation\nrecord carrying its paid flag and the charge reference. It takes no body: the org is the validated tenant and the amount is the\nplatform's, never the caller's to assert.\n\nIDEMPOTENT on the formation rather than on the request: an already-paid\nformation answers 200 with the same record and is not charged again, so a\nretry or a double-clicked button costs nothing. Available only at the\n`payment` stage (409 anywhere else) and only for an org that has begun a\nformation (404 otherwise).\n\nA denial answers the fleet-wide billing contract — 402 insufficient_balance,\n402 spend_cap_exceeded, 503 balance_unavailable — carried by cloud.Denied,\nwhich is the money wire's own {\"error\":{\"code\",\"message\"}} body rather than a\nsecond vocabulary invented for this surface.\n\nThe gate is the LAST thing it does, after the stage check and the paid\nshort-circuit, so a caller the machine is about to refuse is never charged.\nThat ordering is why the gate cannot lift into middleware, where it would run\nfirst. Both facts are pinned: TestPaymentDenialWire, TestPaymentChargesLast.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["company"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.formationView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/register":{"get":{"operationId":"get_company_register","summary":"Returns the platform's whole formation register, newest activity first — every org's formation, not the caller's.","description":"Returns the platform's whole formation register, newest activity\nfirst — every org's formation, not the caller's. It is a Hanzo platform\noperation: a caller who is not a platform reviewer gets 403.\n\nFilter by stage and structure, page with limit and offset. An unknown stage is\nrefused with 400 rather than returning a silently empty page.","tags":["company"],"parameters":[{"name":"stage","in":"query","required":false,"description":"Stage keeps only formations at that stage. Empty means any.","schema":{"type":"string"},"example":"founders"},{"name":"structure","in":"query","required":false,"description":"Structure keeps only formations of that entity kind. Empty means any.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit bounds the page; 0 or less means the default of 200.","schema":{"format":"int64","type":"integer"},"example":50},{"name":"offset","in":"query","required":false,"description":"Offset skips that many rows.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.registerPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/register/summary":{"get":{"operationId":"get_company_register_summary","summary":"Counts the platform's formations by stage — the register's shape in one read, so a queue that is growing is visible as a number rather than inferred by paging the list.","description":"Counts the platform's formations by stage — the register's\nshape in one read, so a queue that is growing is visible as a number rather\nthan inferred by paging the list. A Hanzo platform operation: a caller who is\nnot a platform reviewer gets 403.","tags":["company"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.registerCounts"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/review":{"get":{"operationId":"get_company_review","summary":"Reports the founders whose KYC is not yet settled, oldest formation first, so the queue drains in the order founders have been waiting.","description":"Reports the founders whose KYC is not yet settled, oldest formation\nfirst, so the queue drains in the order founders have been waiting. A Hanzo\nplatform operation: a caller who is not a platform reviewer gets 403.\n\nIt only says who is waiting; the decision itself is POST\n/v1/company/kyc/decision.","tags":["company"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit bounds how many formations are scanned; 0 or less means the default of 200.","schema":{"format":"int64","type":"integer"},"example":50}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.reviewQueue"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/skip":{"post":{"operationId":"post_company_skip","summary":"Marks the org as already incorporated and moves it onto the import path, so an existing company brings its documents and cap table in instead of forming a new entity.","description":"Marks the org as already incorporated and moves it onto the import path,\nso an existing company brings its documents and cap table in instead of forming\na new entity. Available only at the structure stage.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["company"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.formationView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/structure":{"put":{"operationId":"put_company_structure","summary":"Records the entity kind, the state of formation and the proposed name.","description":"Records the entity kind, the state of formation and the proposed\nname. Available only at the structure stage; an unknown structure or\njurisdiction, or an empty name, is refused with 400.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["company"],"requestBody":{"content":{"application/json":{"example":{"jurisdiction":"DE","name":"AgentCo, LLC","structure":"c-corp"},"schema":{"$ref":"#/components/schemas/company.structureIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.formationView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/company/tariff":{"post":{"operationId":"post_company_tariff","summary":"Itemises what a formation costs before anyone commits to it.","description":"Itemises what a formation costs before anyone commits to it.\n\nIt answers what is due now and what recurs, as separate figures, and marks the\nstate's filing fee as money we collect and remit rather than keep. A caller can\ntherefore show a payer the whole bill — which is the point of quoting at all,\nand was impossible while the fee was one number in an error string.\n\nA jurisdiction whose filing fee this deployment has not been told REFUSES,\nnaming the setting that fixes it. Quoting our half as though it were the total\nis the one answer that would be worse than no answer.","tags":["company"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.tariffIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/company.Tariff"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"company","x-public":true,"x-tool":true}},"/v1/completions":{"post":{"operationId":"post_completions","summary":"Implements the OpenAI-compatible chat completions API","description":"Implements the OpenAI-compatible chat completions API","tags":["ai"],"parameters":[{"name":"X-Max-Cost","in":"header","required":false,"description":"The most this request may cost, in USD per 1,000 tokens. Routing picks only models under it; an org's own ceiling fills it when it is absent, and the lower of the two holds.","schema":{"minimum":0,"type":"number"}},{"name":"X-Max-Latency-Ms","in":"header","required":false,"description":"The slowest model this request accepts, in milliseconds.","schema":{"minimum":0,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/openai.ChatCompletionRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/openai.ChatCompletionResponse"},{"properties":{"routing":{"description":"What the router decided for this request and why, present when one routed it (a model Enso routes by reasoning depth). Every field is one the router read or wrote; it reports no score, expected cost or latency because it weighs none.","properties":{"candidates":{"description":"Each model the router's table names, with the reasoning depths that read it, shallow to deep.","items":{"properties":{"depths":{"items":{"type":"string"},"type":"array"},"model":{"type":"string"}},"required":["model","depths"],"type":"object"},"type":"array"},"chosen":{"description":"The model the request is served at.","type":"string"},"inputs":{"properties":{"depth":{"description":"The reasoning depth the request states; default when it states none.","type":"string"},"key":{"description":"The table row that depth was read at.","type":"string"},"policy":{"description":"Whether the caller's plan or credit pays for the paid model at that depth.","enum":["funded","unfunded","n/a"],"type":"string"}},"required":["depth","key","policy"],"type":"object"},"reason":{"description":"How the inputs led to chosen, in a sentence.","type":"string"},"router":{"description":"The router that decided: enso.","type":"string"}},"required":["router","chosen","candidates","inputs","reason"],"type":"object"}},"type":"object"}]}}},"description":"Success.","headers":{"X-Routed-Model":{"description":"The model that served a routed request, one that named auto or an id the router resolves. The body's model field names the same id.","schema":{"type":"string"}}}},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/compliance/accreditation":{"get":{"operationId":"get_compliance_accreditation","summary":"Returns the org's tracked accreditation-state records, newest first — evidence entries the org keeps, never a platform certification.","description":"Returns the org's tracked accreditation-state records, newest\nfirst — evidence entries the org keeps, never a platform certification.","tags":["compliance"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned; non-positive means the server default.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/compliance.accList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compliance","x-public":true,"x-tool":true},"post":{"operationId":"post_compliance_accreditation","summary":"Records an ASSERTED accreditation state for a subject — the subject's own assertion, with no verifier.","description":"Records an ASSERTED accreditation state for a subject — the\nsubject's own assertion, with no verifier. Every CONFIRMED state\n(provider_verified, reviewer_confirmed) and every rejected/expired state is a\nDECISION recorded via the decision endpoint, attributed to the reviewer — a\ncreate can never stamp a confirmation. The underlying figures (income, net\nworth) are never stored; only the method, category, and state.","tags":["compliance"],"requestBody":{"content":{"application/json":{"example":{"basis":"income","method":"self_attested","subjectId":"sub_1"},"schema":{"$ref":"#/components/schemas/compliance.accreditationReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/compliance.accView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compliance","x-public":true,"x-tool":true}},"/v1/compliance/accreditation/{id}":{"get":{"operationId":"get_compliance_accreditation_by_id","summary":"Returns one tracked accreditation record.","description":"Returns one tracked accreditation record.","tags":["compliance"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the accreditation record to read, from the path.","schema":{"type":"string"},"example":"acc_1"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/compliance.accView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compliance","x-public":true,"x-tool":true}},"/v1/compliance/accreditation/{id}/decision":{"post":{"operationId":"post_compliance_accreditation_by_id_decision","summary":"Records an org reviewer's decision on an accreditation record — a reviewer confirmation, a provider verification the reviewer has evidence of (a CPA/attorney letter, a verifier report), a rejection, or an expiry.","description":"Records an org reviewer's decision on an accreditation\nrecord — a reviewer confirmation, a provider verification the reviewer has\nevidence of (a CPA/attorney letter, a verifier report), a rejection, or an\nexpiry. ROLE-GATED (an org admin or platform reviewer) and ATTRIBUTED: the\nreviewer's identity is recorded as ReviewerSub and audited. Human-in-the-loop:\nthe platform never confirms on its own, and even a provider_verified state\ncarries the reviewer who recorded it.","tags":["compliance"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the accreditation record to decide, from the path.","schema":{"type":"string"},"example":"acc_1"}],"requestBody":{"content":{"application/json":{"example":{"id":"acc_1","status":"reviewer_confirmed"},"schema":{"$ref":"#/components/schemas/compliance.accreditationDecision"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/compliance.accView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compliance","x-public":true,"x-tool":true}},"/v1/compliance/audit":{"get":{"operationId":"get_compliance_audit","summary":"AuditRead is the compliance read of the SHARED tamper-evident audit plane — the SOC 2 posture surface (privileged actions: who started/decided what, when).","description":"AuditRead is the compliance read of the SHARED tamper-evident audit plane —\nthe SOC 2 posture surface (privileged actions: who started/decided what, when). The\norg is PINNED to the caller's validated org and the rows are narrowed to\ncompliance.* actions. Fail-closed: no principal is a 401, no configured audit\nstore a 501.","tags":["compliance"],"parameters":[{"name":"result","in":"query","required":false,"description":"Result filters rows by outcome result: success, deny, or error; empty means all.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/compliance.auditList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compliance","x-public":true,"x-tool":true}},"/v1/compliance/health":{"get":{"operationId":"get_compliance_health","summary":"Reports subsystem liveness and the wired verification provider.","description":"Reports subsystem liveness and the wired verification provider. Fail-open\non purpose: it never probes the external provider, so a provider outage cannot\nfail liveness.","tags":["compliance"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/compliance.healthView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compliance","x-public":true,"x-tool":true}},"/v1/compliance/records":{"get":{"operationId":"get_compliance_records","summary":"ListRecords is the unified compliance-record view for the org: its verifications and accreditation records together, each provider-reported or tracked, never platform-asserted.","description":"ListRecords is the unified compliance-record view for the org: its verifications\nand accreditation records together, each provider-reported or tracked, never\nplatform-asserted. PII stays in the subject store; records carry only opaque ids\nand statuses.","tags":["compliance"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned; non-positive means the server default.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/compliance.recordList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compliance","x-public":true,"x-tool":true}},"/v1/compliance/status":{"get":{"operationId":"get_compliance_status","summary":"Status is the org's honest posture read: the wired provider and the per-status tally of its verifications.","description":"Status is the org's honest posture read: the wired provider and the per-status\ntally of its verifications. It is deliberately NOT a boolean \"compliant\" — it\nreports counts of provider-reported states and carries the boundary disclaimer.","tags":["compliance"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/compliance.statusView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compliance","x-public":true,"x-tool":true}},"/v1/compliance/subjects":{"get":{"operationId":"get_compliance_subjects","summary":"Returns the org's subjects as PII-MINIMIZED summaries — no name or email, only whether an email is on file.","description":"Returns the org's subjects as PII-MINIMIZED summaries — no name or\nemail, only whether an email is on file. The full record is returned only by the\nexplicit single-subject read.","tags":["compliance"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned; non-positive means the server default.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/compliance.subjectList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compliance","x-public":true,"x-tool":true},"post":{"operationId":"post_compliance_subjects","summary":"Records a party the org is verifying as part of its own onboarding/compliance — a team member, vendor, customer, or counterparty.","description":"Records a party the org is verifying as part of its own\nonboarding/compliance — a team member, vendor, customer, or counterparty. The\nsubject's contact PII (name/email) is sealed at rest and returned only to the\nowning org; downstream records reference the subject by opaque id.","tags":["compliance"],"requestBody":{"content":{"application/json":{"example":{"email":"founder@example.com","kind":"individual","name":"Ada"},"schema":{"$ref":"#/components/schemas/compliance.subjectReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/compliance.Subject"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compliance","x-public":true,"x-tool":true}},"/v1/compliance/subjects/{id}":{"get":{"operationId":"get_compliance_subjects_by_id","summary":"Returns one subject WITH its contact PII — the only surface that returns it, and only to the owning org.","description":"Returns one subject WITH its contact PII — the only surface that\nreturns it, and only to the owning org. The response is never cached by any\nintermediary.","tags":["compliance"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the subject to read, from the path.","schema":{"type":"string"},"example":"sub_1"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/compliance.Subject"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compliance","x-public":true,"x-tool":true}},"/v1/compliance/verifications":{"get":{"operationId":"get_compliance_verifications","summary":"Returns the org's KYC/KYB verifications, newest first — opaque subject references and provider-reported statuses only, no subject PII.","description":"Returns the org's KYC/KYB verifications, newest first — opaque\nsubject references and provider-reported statuses only, no subject PII.","tags":["compliance"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned; non-positive means the server default.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/compliance.checkList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compliance","x-public":true,"x-tool":true},"post":{"operationId":"post_compliance_verifications","summary":"Begins a KYC/KYB verification of a subject through the wired provider — an existing subject by id, or one created inline from the request.","description":"Begins a KYC/KYB verification of a subject through the wired\nprovider — an existing subject by id, or one created inline from the request.\nThe returned status is provider-reported and never terminal on a fresh start:\nstarting a verification can never yield a verified record, and a provider error\nis a 502, never a verification.","tags":["compliance"],"requestBody":{"content":{"application/json":{"example":{"subjectId":"sub_1"},"schema":{"$ref":"#/components/schemas/compliance.verificationReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/compliance.checkView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compliance","x-public":true,"x-tool":true}},"/v1/compliance/verifications/webhook":{"post":{"operationId":"post_compliance_verifications_webhook","summary":"Provider push that settles a verification, authenticated by HMAC signature","description":"The external PUSH reconcile: a verification provider (or a Hanzo relay) signals that a check settled, and the reconciled check comes back. It authenticates by an HMAC SIGNATURE over the RAW body bytes rather than by a principal — an external caller has no validated org — and the org is then resolved FROM the record the signed provider reference matches, so a call can only ever touch the one tenant that owns that reference.\n\nThe body carries NO trusted decision. A valid signature cannot force a status: the reference only says WHICH check to re-read, and the status is then pulled from the wired provider, which stays the source of truth. With no real provider configured a check stays pending, and the only route to a passing status is the role-gated, attributed reviewer decision.\n\nAn unknown reference is a benign 200 `{\"ignored\": ...}` no-op, not an error, so a provider replaying stale events neither retry-storms nor learns whether a reference exists in some other tenant. Fails closed otherwise: 501 unless a webhook secret is configured, 401 on a signature that does not verify, 400 with no provider reference, 413 over 1 MiB, and 502 if the secret or the provider is unreachable.","tags":["compliance"],"x-app":"compliance","x-public":true}},"/v1/compliance/verifications/{id}":{"get":{"operationId":"get_compliance_verifications_by_id","summary":"Returns one verification — its opaque subject reference and provider-reported status, no subject PII.","description":"Returns one verification — its opaque subject reference and\nprovider-reported status, no subject PII.","tags":["compliance"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the verification to act on, from the path.","schema":{"type":"string"},"example":"chk_1"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/compliance.checkView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compliance","x-public":true,"x-tool":true}},"/v1/compliance/verifications/{id}/decision":{"post":{"operationId":"post_compliance_verifications_by_id_decision","summary":"Records a privileged reviewer's MANUAL decision on a verification — the human-in-the-loop path, and the ONLY route to a passing status when no real provider is wired.","description":"Records a privileged reviewer's MANUAL decision on a\nverification — the human-in-the-loop path, and the ONLY route to a passing status\nwhen no real provider is wired. It produces a DISTINCT reviewer_confirmed, never\na provider_verified (a provider decision is the provider's to report, via the\nwebhook or a reconcile), and it is ROLE-GATED (an org admin or platform reviewer)\nAND ATTRIBUTED (the reviewer's user id is DecidedBy), so a manual pass is always\naccountable.","tags":["compliance"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the verification to decide, from the path.","schema":{"type":"string"},"example":"chk_1"}],"requestBody":{"content":{"application/json":{"example":{"id":"chk_1","status":"reviewer_confirmed"},"schema":{"$ref":"#/components/schemas/compliance.verificationDecision"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/compliance.checkView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compliance","x-public":true,"x-tool":true}},"/v1/compliance/verifications/{id}/refresh":{"post":{"operationId":"post_compliance_verifications_by_id_refresh","summary":"Polls the wired provider for its current decision and records it, ATTRIBUTED to the provider — the internal PULL reconcile.","description":"Polls the wired provider for its current decision and\nrecords it, ATTRIBUTED to the provider — the internal PULL reconcile. For the\nManual provider the check stays pending; for a hosted provider it reflects the\nprovider's settled status. A poll error is a 502, never a verification.","tags":["compliance"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the verification to act on, from the path.","schema":{"type":"string"},"example":"chk_1"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/compliance.checkView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compliance","x-public":true,"x-tool":true}},"/v1/compute/clusters":{"get":{"operationId":"listClusters","summary":"Returns the caller org's clusters from both sources: the managed clusters projected from Visor's node pools, and the BYO clusters attached to the caller's project.","description":"Returns the caller org's clusters from both sources: the managed\nclusters projected from Visor's node pools, and the BYO clusters attached to the\ncaller's project. A Visor outage costs the managed half only — the BYO half\nstill lists, because a page that 502s on an optional provider is worse than a\npage that shows what it can.","tags":["compute"],"responses":{"200":{"content":{"application/json":{"example":{"clusters":[{"doksClusterId":"cl-1","kind":"managed","name":"prod","nodeCount":2,"nodePools":[{"count":2,"name":"gpu","poolId":"p-1","size":"gpu-h100x8-640gb"}],"nodeSize":"gpu-h100x8-640gb","status":"running"}]},"schema":{"$ref":"#/components/schemas/compute.clusterList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true},"post":{"operationId":"attachCluster","summary":"Attaches a BYO cluster to the caller's org — the kubeconfig is validated, KMS-sealed and added to the fleet — and answers 201 with the cluster as it now appears on GET /v1/compute/clusters.","description":"Attaches a BYO cluster to the caller's org — the kubeconfig is\nvalidated, KMS-sealed and added to the fleet — and answers 201 with the cluster\nas it now appears on GET /v1/compute/clusters. Billed the nominal management fee: the\ncustomer brings the compute, Hanzo meters the management plane.","tags":["compute"],"requestBody":{"content":{"application/json":{"example":{"default":false,"kubeconfig":"apiVersion: v1\nkind: Config\n...","name":"lab","provider":"on-prem"},"schema":{"$ref":"#/components/schemas/compute.clusterAttach"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"kind":"byo","name":"lab","nodeCount":3,"nodePools":[],"nvidiaGpu":2,"region":"on-prem","status":"attached"},"schema":{"$ref":"#/components/schemas/compute.clusterView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/compute/clusters/{clusterId}/pools":{"post":{"operationId":"createNodePool","summary":"Adds a node pool to one of the caller org's clusters and answers 201 with the created pool.","description":"Adds a node pool to one of the caller org's clusters and answers 201\nwith the created pool. Only the CreateNodePoolSpec fields are forwarded;\nowner/provider/clusterId ride in the query exactly as Visor expects them.","tags":["compute"],"parameters":[{"name":"clusterId","in":"path","required":true,"description":"ClusterID is the cluster to add the pool to, from the URL path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"autoScale":false,"count":2,"name":"gpu","provider":"digitalocean","size":"gpu-h100x8-640gb"},"schema":{"$ref":"#/components/schemas/compute.poolCreate"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"count":2,"name":"gpu","poolId":"p-1","size":"gpu-h100x8-640gb"},"schema":{"$ref":"#/components/schemas/compute.nodePoolView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/compute/clusters/{clusterId}/pools/{poolId}":{"delete":{"operationId":"deleteNodePool","summary":"Removes a node pool from one of the caller org's clusters.","description":"Removes a node pool from one of the caller org's clusters. The owner\nscopes the delete to the caller's tenant; provider+clusterId drive the\nprovider-side removal. Answers 204.","tags":["compute"],"parameters":[{"name":"clusterId","in":"path","required":true,"description":"ClusterID and PoolID address the pool, from the URL path.","schema":{"type":"string"}},{"name":"poolId","in":"path","required":true,"schema":{"type":"string"}},{"name":"provider","in":"query","required":false,"description":"Provider is the cloud the cluster lives on, from ?provider=. Required.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/compute/clusters/{clusterId}/pools/{poolId}/scale":{"post":{"operationId":"scaleNodePool","summary":"Resizes a node pool to an absolute node count and returns the pool as Visor reports it after the change.","description":"Resizes a node pool to an absolute node count and returns the pool as\nVisor reports it after the change.","tags":["compute"],"parameters":[{"name":"clusterId","in":"path","required":true,"description":"ClusterID is the cluster holding the pool, from the URL path.","schema":{"type":"string"}},{"name":"poolId","in":"path","required":true,"description":"PoolID is the pool to resize, from the URL path — the `poolId` a cluster read\nreports for it. Required.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"count":4,"provider":"digitalocean"},"schema":{"$ref":"#/components/schemas/compute.poolScale"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"count":4,"name":"gpu","poolId":"p-1","size":"gpu-h100x8-640gb"},"schema":{"$ref":"#/components/schemas/compute.nodePoolView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/compute/clusters/{id}":{"delete":{"operationId":"detachCluster","summary":"Removes a BYO cluster from the caller org's fleet.","description":"Removes a BYO cluster from the caller org's fleet. It only ever\ntouches BYO clusters — a managed cluster's nodes are removed through the node-pool\nroutes — and answers 404 when the name is not in this org's fleet.","tags":["compute"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the cluster's fleet name (the `name` it was attached under), matched\nlower-cased.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"detached":"lab"},"schema":{"$ref":"#/components/schemas/compute.clusterDetached"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/compute/fleet":{"get":{"operationId":"listFleet","summary":"Returns every compute unit the caller's org has, from every source, each carrying its latest utilization: agent run-targets, the BYO machines that dialed in, attached BYO clusters and Visor-provisioned machines.","description":"Returns every compute unit the caller's org has, from every source, each\ncarrying its latest utilization: agent run-targets, the BYO machines that dialed\nin, attached BYO clusters and Visor-provisioned machines.\n\nA unit with a live snapshot of its own keeps it; the rest are overlaid from the\nutilization series, and only when the sample agrees about the SOURCE — two planes\ncould mint the same unit id, and a board must never show one machine's load on\nanother's row. BYO GPU units also carry their gpu-jobs queue depth. Every source\nis folded in independently: a broken one costs its own rows and nothing else.","tags":["compute"],"responses":{"200":{"content":{"application/json":{"example":{"units":[{"host":"spark","kind":"worker","label":"spark","metrics":{"at":"2026-07-27T09:00:00Z","gpuUtil":0.42},"queued":2,"running":1,"sessions":0,"source":"byo","spec":{"arch":"arm64","cpus":20,"gpuModel":"NVIDIA GB10","gpus":1,"os":"linux"},"status":"online","unit":"spark"}]},"schema":{"$ref":"#/components/schemas/compute.fleetBoard"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/compute/fleet/jobs":{"get":{"operationId":"listFleetJobs","summary":"Returns the caller org's gpu-jobs render queue, each row tagged with the GPU it targets (empty = the shared any-GPU lane) and the node claiming it, optionally narrowed to one GPU's queue and/or one status.","description":"Returns the caller org's gpu-jobs render queue, each row tagged with\nthe GPU it targets (empty = the shared any-GPU lane) and the node claiming it,\noptionally narrowed to one GPU's queue and/or one status.\n\nA job whose worker died — STARTED with an elapsed lease and not yet reclaimed —\nreads \"stalled\", not \"running\". Fail-soft: an unavailable tasks engine yields an\nempty queue rather than an error.","tags":["compute"],"parameters":[{"name":"gpu","in":"query","required":false,"description":"GPU selects one node's lane: jobs TARGETED at it (gpu:\u003cnode\u003e) or CLAIMED by\nit. The literal \"shared\" selects the any-GPU lane — no target, no claimant.\nMatched case-insensitively.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Status selects one lifecycle state: queued, running, stalled, completed,\nfailed or canceled.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"jobs":[{"attempt":1,"gpu":"spark","id":"job-1","label":"hero","runId":"job-1","status":"running","type":"studio.render","worker":"spark"}]},"schema":{"$ref":"#/components/schemas/compute.jobList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/compute/fleet/jobs/{id}/cancel":{"post":{"operationId":"cancelFleetJob","summary":"Cancels a queued or running render in the caller's org.","description":"Cancels a queued or running render in the caller's org. The engine\ncancel is org-scoped, so a tenant can only ever cancel its OWN job: a job in\nanother tenant's shard is 404, exactly like one that never existed. An\nalready-finished job is 409.","tags":["compute"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the job (activity) id, from the URL path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"reason":"superseded"},"schema":{"$ref":"#/components/schemas/compute.jobCancel"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"canceled":"job-1","run":"job-1"},"schema":{"$ref":"#/components/schemas/compute.jobCanceled"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/compute/fleet/samples":{"get":{"operationId":"listFleetSamples","summary":"Returns the caller org's utilization series, oldest first.","description":"Returns the caller org's utilization series, oldest first.\n\nA rejected narrower is a 400 carrying its own reason (the vocabulary is ours and\nsafe to echo); a warehouse failure is logged and answered 503 \"unavailable\",\nbecause a chart that silently reads \"no load\" when the truth is \"we cannot tell\"\nis worse than one that says so. An ABSENT warehouse is different again: it returns\nan empty series, which renders honestly as \"no samples yet\".","tags":["compute"],"parameters":[{"name":"unit","in":"query","required":false,"description":"Unit selects one compute unit's series by its source-local id.","schema":{"type":"string"}},{"name":"source","in":"query","required":false,"description":"Source selects one plane: \"agent\", \"byo\" or \"visor\".","schema":{"type":"string"}},{"name":"range","in":"query","required":false,"description":"Range is the lookback window (e.g. \"1h\", \"24h\", \"7d\"); empty takes the\nwarehouse default.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"samples":[{"at":"2026-07-27T09:00:00Z","gpuModel":"GB10","gpuUtil":0.42,"gpus":1,"host":"spark","kind":"worker","source":"byo","unit":"spark"}]},"schema":{"$ref":"#/components/schemas/compute.sampleList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true},"post":{"operationId":"recordFleetSample","summary":"Records a BYO worker's live GPU utilization into the SAME series the fleet board overlays.","description":"Records a BYO worker's live GPU utilization into the SAME series the\nfleet board overlays. The org is the validated principal and source/kind are fixed\nserver-side, so a worker names only its own metrics — never another tenant or\nanother source. Answers 202: the warehouse write is DETACHED (its own bounded\ncontext, never in the response path), so a slow or absent warehouse cannot stall a\nheartbeat.","tags":["compute"],"requestBody":{"content":{"application/json":{"example":{"gpuModel":"GB10","gpuUtil":0.42,"gpus":1,"host":"spark","memFree":200,"memUsed":100,"unit":"spark"},"schema":{"$ref":"#/components/schemas/compute.sampleIngest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"recorded":true},"schema":{"$ref":"#/components/schemas/compute.sampleAccepted"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/compute/fleet/workers":{"get":{"operationId":"listFleetWorkers","summary":"Returns the caller org's BYO machines — the ones that dialed in via `hanzo link` — with everything each host reported about itself.","description":"Returns the caller org's BYO machines — the ones that dialed in\nvia `hanzo link` — with everything each host reported about itself. The Machines\nand GPUs pages fold the same data into their normalized shapes; this is the\ncanonical raw list a fleet view (or the CLI's `status`) reads.","tags":["compute"],"responses":{"200":{"content":{"application/json":{"example":{"workers":[{"arch":"arm64","cpus":20,"gpus":[{"memoryTotal":"122880 MiB","name":"NVIDIA GB10"}],"hostname":"spark","id":"spark","location":"on-prem","provider":"byo","status":"online"}]},"schema":{"$ref":"#/components/schemas/compute.workerList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/compute/gpus":{"get":{"operationId":"listGpus","summary":"Returns one row per physical accelerator the caller's org has, derived from its real GPU machines (the size slug says how many cards a node holds) and from the accelerators BYO workers report through nvidia-smi.","description":"Returns one row per physical accelerator the caller's org has, derived\nfrom its real GPU machines (the size slug says how many cards a node holds) and\nfrom the accelerators BYO workers report through nvidia-smi.\n\nLive telemetry is absent on Visor rows because Visor's machine object carries\nnone — an honest omission the console renders as \"—\", never a fabricated 0.","tags":["compute"],"responses":{"200":{"content":{"application/json":{"example":{"gpus":[{"id":"gpu-1#0","machine":"gpu-1","model":"H100","name":"gpu-1","provider":"digitalocean","region":"nyc2","status":"running"}]},"schema":{"$ref":"#/components/schemas/compute.gpuList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/compute/gpus/alerts":{"get":{"operationId":"listGpuAlerts","summary":"Is an HONEST empty surface: Visor exposes no GPU alert inventory, so this returns [] rather than fabricating alerts.","description":"Is an HONEST empty surface: Visor exposes no GPU alert inventory, so\nthis returns [] rather than fabricating alerts. It stays a real, tenant-gated\nroute so the console's alerts fetch resolves (200 [], not a 404) — an honest\n\"no alerts\", the same discipline the rest of the surface follows.","tags":["compute"],"responses":{"200":{"content":{"application/json":{"example":{"alerts":[]},"schema":{"$ref":"#/components/schemas/compute.gpuAlertList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/compute/k8s/clusters":{"get":{"operationId":"listKubernetesClusters","summary":"Lists the org's DOKS clusters (Visor, house account) folded with the org's BYO clusters — ONE fleet cluster view under the unified k8s noun.","description":"Lists the org's DOKS clusters (Visor, house account) folded with\nthe org's BYO clusters — ONE fleet cluster view under the unified k8s noun. A Visor\noutage is logged and skipped so a down optional provider never hides the BYO list.","tags":["compute"],"responses":{"200":{"content":{"application/json":{"example":{"clusters":[{"doClusterId":"cl-1","doksClusterId":"cl-1","kind":"managed","name":"prod","nodeCount":0,"nodePools":[],"region":"nyc3","status":"running"}]},"schema":{"$ref":"#/components/schemas/compute.clusterList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true},"post":{"operationId":"createKubernetesCluster","summary":"Provisions a DOKS cluster for the caller's org and answers 201.","description":"Provisions a DOKS cluster for the caller's org and answers 201.\nADMIN-GATED — a SuperAdmin, or an OrgAdmin of the caller's own org — because\nprovisioning spends real infrastructure on the house account. The request is\nvalidated at this boundary, then Visor owns provisioning and the hanzo-org\nownership tag.","tags":["compute"],"requestBody":{"content":{"application/json":{"example":{"name":"prod","nodePool":{"count":2,"name":"gpu","size":"gpu-h100x8-640gb"},"region":"nyc3"},"schema":{"$ref":"#/components/schemas/compute.createClusterReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"doClusterId":"cl-1","doksClusterId":"cl-1","kind":"managed","name":"prod","nodeCount":0,"nodePools":[],"region":"nyc3","status":"provisioning"},"schema":{"$ref":"#/components/schemas/compute.clusterView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/compute/k8s/clusters/{id}":{"delete":{"operationId":"deleteKubernetesCluster","summary":"Destroys a DOKS cluster by id and answers 204.","description":"Destroys a DOKS cluster by id and answers 204. ADMIN-GATED, like\ncreate. Visor scopes the delete to the org (refuses a foreign id), so this can\nonly ever remove the caller org's own cluster.","tags":["compute"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the provider's DOKS cluster id. Visor scopes the lookup to the caller's\norg, so another tenant's id resolves to not-found rather than their cluster.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true},"get":{"operationId":"getKubernetesCluster","summary":"Returns one cluster's detail: node pools + worker nodes.","description":"Returns one cluster's detail: node pools + worker nodes. Visor scopes\nthe lookup to the org (a foreign or missing id resolves to not-found), so a tenant\ncan never read another tenant's cluster by guessing an id.","tags":["compute"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the provider's DOKS cluster id. Visor scopes the lookup to the caller's\norg, so another tenant's id resolves to not-found rather than their cluster.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"doksClusterId":"cl-1","kind":"managed","name":"prod","nodeCount":1,"nodePools":[{"count":1,"name":"gpu","poolId":"p-1","size":"gpu-h100x8-640gb"}],"nodeSize":"gpu-h100x8-640gb","nodes":[{"id":"node-1","name":"node-1","status":"active"}],"region":"nyc3","status":"running"},"schema":{"$ref":"#/components/schemas/compute.clusterDetailView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/compute/k8s/nodes":{"get":{"operationId":"listKubernetesNodes","summary":"Returns every DOKS worker node in the org's clusters as a machine — the SAME set the fleet folds in (managedMachines), exposed directly under the k8s noun.","description":"Returns every DOKS worker node in the org's clusters as a machine —\nthe SAME set the fleet folds in (managedMachines), exposed directly under the k8s\nnoun. House account (hanzo-org cluster tag) + BYOC, deduped by Visor.","tags":["compute"],"responses":{"200":{"content":{"application/json":{"example":{"nodes":[{"id":"node-1","name":"node-1","region":"nyc3","status":"active","type":"s-4vcpu-8gb","vcpu":4}]},"schema":{"$ref":"#/components/schemas/compute.nodeList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/compute/machines":{"get":{"operationId":"listMachines","summary":"Returns every machine the caller's org has — Visor's registry, the live DigitalOcean droplets and the DOKS worker nodes (deduped into one union), plus the BYO machines that dialed in via `hanzo link` (provider \"byo\").","description":"Returns every machine the caller's org has — Visor's registry, the\nlive DigitalOcean droplets and the DOKS worker nodes (deduped into one union),\nplus the BYO machines that dialed in via `hanzo link` (provider \"byo\").\n\nA source Visor cannot answer for is logged and skipped, never an error: one\nwedged upstream must not hide the machines the other sources can see.","tags":["compute"],"parameters":[{"name":"kind","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"machines":[{"id":"web-1","mem":"4 GB","name":"Web 1","provider":"digitalocean","publicIp":"1.2.3.4","region":"sfo3","status":"running","type":"s-2vcpu-4gb","vcpu":2}]},"schema":{"$ref":"#/components/schemas/compute.machineList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true},"post":{"operationId":"post_compute_machines","summary":"Launch a metered machine for your org, or price one first with dryRun","description":"Provisions a machine owned by the caller's org and answers 201 with the machine. Send `dryRun: true` to get a PRICE QUOTE instead: 200 with the upstream quote passed through verbatim, nothing launched and nothing spent. Two response shapes on one address is the rule to know, and it is why this is not a typed op.\n\nMetering is not this plane's: the launch fronts the compute provider's resell endpoint, which owns the balance gate and the per-hour meter, and cloud only forwards the tenant. Ownership is the validated principal's org and is never read from the body, so a launch always lands in the caller's OWN tenant and the machine it creates is only ever visible to that tenant. Fails closed: a validated principal is required (401 without one) and `size` (or its `instanceType` alias) is required (400).","tags":["compute"],"x-app":"compute","x-public":true}},"/v1/compute/machines/agents":{"get":{"operationId":"listMachineAgents","summary":"Returns every agent↔machine binding in the caller's org — which machines are running which cloud Agent, with vm's own reconciled status.","description":"Returns every agent↔machine binding in the caller's org — which\nmachines are running which cloud Agent, with vm's own reconciled status.","tags":["compute"],"responses":{"200":{"content":{"application/json":{"example":{"agentBindings":[{"agentName":"bot-a","machineId":"drop-a","publicIp":"1.2.3.4","status":"running"}]},"schema":{"$ref":"#/components/schemas/compute.bindingList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/compute/machines/{id}":{"delete":{"operationId":"deleteMachine","summary":"Terminates one of the caller org's machines.","description":"Terminates one of the caller org's machines. Visor takes the\nmachine identity as owner+name, and the owner is the validated principal, so a\ncaller can only ever terminate its own tenant's machine. Answers 204.","tags":["compute"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the machine's org-scoped NAME — the stable key Visor addresses a\nmachine by (owner/name), not the ephemeral provider id.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true},"get":{"operationId":"getMachine","summary":"Returns one of the caller org's machines by its org-scoped name.","description":"Returns one of the caller org's machines by its org-scoped name.\nVisor keys the lookup by owner/name, so an id belonging to another tenant\nresolves to not-found rather than another org's machine.","tags":["compute"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the machine's org-scoped NAME — the stable key Visor addresses a\nmachine by (owner/name), not the ephemeral provider id.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"id":"web-1","name":"Web 1","publicIp":"1.2.3.4","region":"sfo3","status":"running","type":"s-2vcpu-4gb","vcpu":2},"schema":{"$ref":"#/components/schemas/compute.machineView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/compute/machines/{id}/agent":{"delete":{"operationId":"unbindMachineAgent","summary":"Detaches the agent runtime from one of the caller org's machines.","description":"Detaches the agent runtime from one of the caller org's\nmachines. The machine stays — this halts the bot, it does not terminate the\ncompute. Answers 204.","tags":["compute"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the machine's org-scoped NAME — the stable key Visor addresses a\nmachine by (owner/name), not the ephemeral provider id.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true},"get":{"operationId":"getMachineAgent","summary":"Returns the agent binding of one of the caller org's machines, or 404 when the machine runs no bot runtime.","description":"Returns the agent binding of one of the caller org's\nmachines, or 404 when the machine runs no bot runtime.","tags":["compute"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the machine's org-scoped NAME — the stable key Visor addresses a\nmachine by (owner/name), not the ephemeral provider id.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"agentName":"bot-a","botVersion":"1.4.0","machineId":"drop-a","status":"running"},"schema":{"$ref":"#/components/schemas/compute.agentBinding"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true},"put":{"operationId":"bindMachineAgent","summary":"Binds a cloud Agent to one of the caller org's machines: the machine is recorded as running that Agent's @hanzo/bot runtime.","description":"Binds a cloud Agent to one of the caller org's machines: the\nmachine is recorded as running that Agent's @hanzo/bot runtime. The owning org is\nthe validated tenant, never a client field.","tags":["compute"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the machine to bind, from the URL path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"agentName":"bot-a","botVersion":"1.4.0"},"schema":{"$ref":"#/components/schemas/compute.bindAgentReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"agentName":"bot-a","machineId":"drop-a","status":"binding"},"schema":{"$ref":"#/components/schemas/compute.agentBinding"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/compute/machines/{id}/{action}":{"post":{"operationId":"post_compute_machines_by_id_by_action","summary":"Message a bot, or stop it, by naming the action in the path","description":"Dispatches one verb against a bot the caller's org owns. `message` runs the bot's bound agent with the request body as the message and streams the agent's answer back VERBATIM — the upstream body, its content type and its status — so a message is a real agent run, recorded, billed and traced exactly like any other, under the caller's own identity rather than a fabricated one. `stop` and `pause` are the same single honest capability: they halt the runtime by unbinding the agent while LEAVING THE MACHINE UP, so the bot stops answering but keeps costing — rebind to resume, or delete the bot to tear it down. Stopping is idempotent; a bot with no binding still reports stopped.\n\nOrg-scoped and fails closed: a validated principal is required (401 without one) and the bot is addressed under the caller's OWN org, so another tenant's id is not reachable. An unknown action is a clean 400 naming the three it accepts, never a silent no-op, and messaging a bot with no bound agent is a 400.","tags":["compute"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"action","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"compute","x-public":true}},"/v1/compute/regions":{"get":{"operationId":"get_compute_regions","summary":"Lists the regions a machine can be launched in.","description":"Lists the regions a machine can be launched in.\n\nThe catalog is GLOBAL — identical for every tenant — so no owner is forwarded\nupstream. It is still org-gated, because a catalog is a map of what this\ndeployment can spend money in and an anonymous caller has no business reading it.","tags":["compute"],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/compute/sizes":{"get":{"operationId":"get_compute_sizes","summary":"Lists the machine sizes available to launch, with their specifications.","description":"Lists the machine sizes available to launch, with their specifications.\n\nGlobal and org-gated, exactly as the region catalog is, and for the same reasons.","tags":["compute"],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"compute","x-public":true,"x-tool":true}},"/v1/connection":{"get":{"operationId":"get_connection","summary":"Lists the caller's OWN connectors across every provider — the set `hanzo connector ls` prints.","description":"Lists the caller's OWN connectors across every provider — the set\n`hanzo connector ls` prints. Rows are keyed (org,user), so this can never\nsurface another user's connector, and no secret is in the view.","tags":["provider"],"responses":{"200":{"content":{"application/json":{"example":{"connectors":[{"account":"me@acme.com","connectedAt":"2026-07-01T10:00:00Z","expiresAt":"2026-07-01T11:00:00Z","externalId":"u-42","id":"openai:default","label":"default","provider":"openai","scopes":["api"]}]},"schema":{"$ref":"#/components/schemas/provider.connectionsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/connection/providers":{"get":{"operationId":"get_connection_providers","summary":"Lists the USER-plane provider cards.","description":"Lists the USER-plane provider cards. It is not the org\ncatalog at /v1/provider and the two are not a duplicate of one another: a\nprovider declares its custody plane, and the planes are disjoint, so a\nuser-scoped provider 404s on the org surface and vice versa. Hence the\ncatalog of what a\nuser can connect, and how. Modes derive from capabilities (Device/Adopt/Verify\n— Mount asserts at least one), never from a parallel kind enum.","tags":["provider"],"responses":{"200":{"content":{"application/json":{"example":{"providers":[{"category":"AI","description":"Use your own OpenAI account.","id":"openai","methods":["device","token"],"name":"OpenAI","scopes":["api"]}]},"schema":{"$ref":"#/components/schemas/provider.userCatalogOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/connection/{id}":{"delete":{"operationId":"delete_connection_by_id","summary":"Forgets a connector: every custodied secret, then the row.","description":"Forgets a connector: every custodied secret, then the row.\nIdempotent — dropping a never-connected id still answers {disconnected:true}\n(disconnect() parity). No provider Revoke: none of the user-plane providers\nexposes a revoke endpoint.","tags":["provider"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the connector id, provider + \":\" + label (\"openai:default\") — the\nauth-profile-id shape. Another user's id is simply no row, so 404.","schema":{"type":"string"},"example":"openai:work"}],"responses":{"200":{"content":{"application/json":{"example":{"disconnected":true},"schema":{"$ref":"#/components/schemas/provider.disconnectOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/connection/{id}/refresh":{"post":{"operationId":"post_connection_by_id_refresh","summary":"Forces a token rotation for a connected connector, ahead of the automatic rotation a token read would do inside the expiry window.","description":"Forces a token rotation for a connected connector, ahead of the\nautomatic rotation a token read would do inside the expiry window. Only\nproviders that declare a Refresh support it.","tags":["provider"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the connector id, provider + \":\" + label (\"openai:default\") — the\nauth-profile-id shape. Another user's id is simply no row, so 404.","schema":{"type":"string"},"example":"openai:work"}],"responses":{"200":{"content":{"application/json":{"example":{"connector":{"account":"me@acme.com","connectedAt":"2026-07-01T10:00:00Z","expiresAt":"2026-07-01T12:00:00Z","externalId":"u-42","id":"openai:work","label":"work","provider":"openai","scopes":["api"]},"refreshed":true},"schema":{"$ref":"#/components/schemas/provider.refreshOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/connection/{id}/token":{"get":{"operationId":"get_connection_by_id_token","summary":"Hands the custodied access token to its owner — the ONE place custody exits.","description":"Hands the custodied access token to its owner — the ONE place\ncustody exits. The (org,user)-keyed row IS the same-user gate: another user's\nid is simply \"no row\" → 404. fresh() auto-rotates within the refreshSkew\nwindow; static providers degenerate to a plain kmsGet of Secrets[0]. Refresh\ntokens are NEVER returned — custody keeps the sink. The token is never logged.","tags":["provider"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the connector id, provider + \":\" + label (\"openai:default\") — the\nauth-profile-id shape. Another user's id is simply no row, so 404.","schema":{"type":"string"},"example":"openai:work"}],"responses":{"200":{"content":{"application/json":{"example":{"expiresAt":"2026-07-01T11:00:00Z","label":"work","provider":"openai","token":"\u003cthe access token\u003e"},"schema":{"$ref":"#/components/schemas/provider.tokenOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/connection/{provider}/credential":{"post":{"operationId":"post_connection_by_provider_credential","summary":"Is the direct intake path: a customer-held token/setup-token (Verify) or an externally obtained OAuth bundle from the CLI's local PKCE (Adopt).","description":"Is the direct intake path: a customer-held token/setup-token\n(Verify) or an externally obtained OAuth bundle from the CLI's local PKCE\n(Adopt). ALWAYS verify-before-store: a bad credential is refused and NOTHING\nis persisted (connectByCredential's fail-closed order).","tags":["provider"],"parameters":[{"name":"provider","in":"path","required":true,"description":"Provider is the user-scoped provider's registry id, from the path.","schema":{"type":"string"},"example":"openai"}],"requestBody":{"content":{"application/json":{"example":{"label":"work","provider":"openai","token":"sk-user-owned-key"},"schema":{"$ref":"#/components/schemas/provider.credentialIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"connected":true,"connector":{"account":"me@acme.com","connectedAt":"2026-07-01T10:00:00Z","expiresAt":"","externalId":"u-42","id":"openai:work","label":"work","provider":"openai","scopes":["api"]}},"schema":{"$ref":"#/components/schemas/provider.credentialOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/connection/{provider}/device":{"post":{"operationId":"post_connection_by_provider_device","summary":"Begins a device sign-in and returns the code to show the user plus how to poll for completion.","description":"Begins a device sign-in and returns the code to show the user plus\nhow to poll for completion. KMS readiness is checked NOW rather than dead-ending\nthe user at poll-done (connect() parity), and the per-provider connector cap is\nchecked before the provider is called. The provider's device code is persisted\nonly in the encrypted grants table and is NEVER returned.","tags":["provider"],"parameters":[{"name":"provider","in":"path","required":true,"description":"Provider is the user-scoped provider's registry id, from the path.","schema":{"type":"string"},"example":"openai"}],"requestBody":{"content":{"application/json":{"example":{"label":"work","provider":"openai"},"schema":{"$ref":"#/components/schemas/provider.deviceStartIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"expiresAt":"2026-07-01T10:15:00Z","flow":"g_7f2c","interval":5,"userCode":"WDJB-MJHT","verifyUrl":"https://example.com/device"},"schema":{"$ref":"#/components/schemas/provider.deviceStartOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/connection/{provider}/device/{flow}/poll":{"post":{"operationId":"post_connection_by_provider_device_by_flow_poll","summary":"Advances a device sign-in.","description":"Advances a device sign-in. Terminal outcomes are DATA, not errors\n(verifyConn {active:false} discipline) — the status set is closed:\npending|connected|denied|expired. pollSlow collapses to \"pending\" on the\nwire; the raised cadence rides interval.","tags":["provider"],"parameters":[{"name":"provider","in":"path","required":true,"description":"Provider is the user-scoped provider's registry id, from the path.","schema":{"type":"string"},"example":"openai"},{"name":"flow","in":"path","required":true,"description":"Flow is the id deviceStartOut returned. Expired or another user's flow is\nindistinguishable from an unknown one: 404.","schema":{"type":"string"},"example":"g_7f2c"}],"responses":{"200":{"content":{"application/json":{"example":{"connector":{"account":"me@acme.com","connectedAt":"2026-07-01T10:05:00Z","expiresAt":"2026-07-01T11:00:00Z","externalId":"u-42","id":"openai:work","label":"work","provider":"openai","scopes":["api"]},"status":"connected"},"schema":{"$ref":"#/components/schemas/provider.devicePollOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/content/board":{"get":{"operationId":"get_content_board","summary":"Aggregates the caller org's marketing content across every publishable content type into ONE queue board — the cross-type read the framework's per-DocType list cannot give.","description":"Aggregates the caller org's marketing content across every publishable\ncontent type into ONE queue board — the cross-type read the framework's\nper-DocType list cannot give. It never fails on a partial outage: a content type\nthe org has not installed, or one whose search errors, is skipped and logged\nrather than failing the whole board.","tags":["content"],"parameters":[{"name":"status","in":"query","required":false,"description":"Status keeps only items in one lifecycle state (draft, in_review, approved,\nqueued, published, archived). An undefined state is refused.","schema":{"type":"string"},"example":"queued"},{"name":"project","in":"query","required":false,"description":"Project keeps only items in one brand/site sub-scope.","schema":{"type":"string"}},{"name":"doctype","in":"query","required":false,"description":"DocType keeps only one content type; omitted, the board spans every\npublishable type. An unknown type is refused.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned, clamped to 1000. Defaults to 200, which is also\nwhat a non-positive or unparseable value takes.","schema":{"format":"int64","type":"integer"},"example":50}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/content.boardPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"content","x-public":true,"x-tool":true}},"/v1/content/channels":{"get":{"operationId":"get_content_channels","summary":"Lists the distribution channels the caller's org has connected — the social integrations a publish can target.","description":"Lists the distribution channels the caller's org has connected — the\nsocial integrations a publish can target. A deployment with no distribution edge\nwired answers 503 rather than an empty list that would read as \"no channels\".","tags":["content"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/content.channelList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"content","x-public":true,"x-tool":true}},"/v1/content/generate":{"post":{"operationId":"post_content_generate","summary":"Draft a provider of marketing content and file it in the CMS as a draft.","description":"Draft a provider of marketing content and file it in the CMS as a draft.\n\nAnswers 201 with the created draft's identity — {doctype, name, status} — and the\ndocument itself lands in the CMS through the SAME validate and lifecycle-hook\npipeline an ordinary create runs. This is a WRITE, not a preview: there is no\ndry-run, and every call that succeeds leaves a document behind.\n\n`doctype` picks which of two generation planes runs, and they are the only two.\nCampaign and SocialPost are drafted as brand COPY on the platform AI plane (zen5 by\ndefault, overridable per request with `model` or per deployment); Asset is a studio\nimage render the AI plane never sees. Everything else about the call is identical.\n\nMONEY, metered in exactly one place per mode and never both. Copy rides the\nplatform's own inference meter — the org's balance is authorised before the model\ncall and debited at the exact token cost after — so content never re-bills it. A\nstudio render is invisible to that meter, so content is the sole meter for it: the\norg is gated BEFORE the GPU compute and refused 402 when out of funds or over its\nspend cap, and the debit is recorded only once the render actually returns, because\nthe billable event is the consumed compute and not the CMS row. `project` rides the\nBODY rather than a server-minted identity claim, so it attributes spend but a\nproject-scoped cap stays soft on it — the org is the value that is enforced.\n\nThe org is the caller's own, resolved once from the validated principal and never\nread from the body; a caller without one is refused 401. Status is not the\ngenerator's to choose: a generated item is ALWAYS a draft, and the storage-boundary\nhook enforces that a second time.\n\nIt fails closed rather than inventing anything. An unknown content type is 404 and a\ndeployment whose marketing module is not installed is 409 naming the install call.\nAn AI plane or studio that is unconfigured or unreachable, a graph the studio\nrejects, and a render that does not return in time all degrade to 503 — never\nfabricated copy, never a fake render. A `source_media` that fails the SSRF and\ntraversal validator is 400 raised before the billing gate and before the studio is\ncontacted, so a hostile source never costs the caller anything.","tags":["content"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/content.GenerateInput"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/content.GenerateResult"}}},"description":"created"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/content.GenerateResult"}}},"description":"payment required"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"content","x-public":true,"x-tool":true}},"/v1/content/lifecycle":{"get":{"operationId":"get_content_lifecycle","summary":"Returns the ONE marketing-content state machine: the ordered lifecycle states, which state a fresh document starts in, which one is publicly live, and the legal successors of every state.","description":"Returns the ONE marketing-content state machine: the ordered\nlifecycle states, which state a fresh document starts in, which one is publicly\nlive, and the legal successors of every state. The console builds its board\ncolumns and its per-item action buttons from this single answer, so the UI and\nthe write-time enforcement hook can never disagree about what is legal.","tags":["content"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/content.stateGraph"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"content","x-public":true,"x-tool":true}},"/v1/content/publish":{"post":{"operationId":"post_content_publish","summary":"Publish distributes one CMS content item to the channels recorded on it and returns the honest per-channel outcome.","description":"Publish distributes one CMS content item to the channels recorded on it and\nreturns the honest per-channel outcome. The item names itself — its caption,\nmedia and channel list are read from the stored document, not from this request.\nIt is idempotent per channel (a channel already posted for this item is skipped),\nand a publish that loses the per-item lease to a live publisher answers status\n\"in_progress\" having posted nothing.","tags":["content"],"requestBody":{"content":{"application/json":{"example":{"doctype":"marketing.SocialPost","name":"spring-teaser"},"schema":{"$ref":"#/components/schemas/content.PublishInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/content.PublishResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"content","x-public":true,"x-tool":true}},"/v1/content/{doctype}/{name}/transition":{"post":{"operationId":"post_content_by_doctype_by_name_transition","summary":"Moves one content item to a new lifecycle state and, on the move to published, fans it out to the item's channels.","description":"Moves one content item to a new lifecycle state and, on the move to\npublished, fans it out to the item's channels. The edge must be legal for the\nitem's current state — an illegal move is refused with 409 — and the status write\nre-validates it at the storage boundary. Distribution is best effort: its honest\nstate is reported on the result and a distribution failure never rolls the status\nchange back.","tags":["content"],"parameters":[{"name":"doctype","in":"path","required":true,"description":"DocType is the content type to act on, from the path.","schema":{"type":"string"},"example":"marketing.SocialPost"},{"name":"name","in":"path","required":true,"description":"Name is the document to act on, from the path.","schema":{"type":"string"},"example":"spring-teaser"}],"requestBody":{"content":{"application/json":{"example":{"doctype":"marketing.SocialPost","name":"spring-teaser","to":"published"},"schema":{"$ref":"#/components/schemas/content.transitionIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/content.TransitionResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"content","x-public":true,"x-tool":true}},"/v1/crawl":{"post":{"operationId":"read_page","summary":"Fetch one URL and read it back as markdown","description":"Reads one URL and answers with the page as markdown.\n\nIt fetches a single URL from inside the cluster and answers with the address it\nactually landed on, the document's title, its content rendered to MARKDOWN, and\nwhatever the page said about itself. One URL per call: batching would make the\nanswer a partial-failure envelope every caller then has to unpack.\n\nA PAGE THAT COULD NOT BE FETCHED IS A NORMAL ANSWER, not a fault. An\nunreachable host, a refused address and a content type that is not a document\nall answer 200 with `success:false` and the reason in `error`, because the\ncaller sent a well-formed ask and gets a well-formed answer. Non-2xx is reserved\nfor a caller problem — 400 with the same body when there is no url, 401 for a\nbad key, 503 when the surface is unconfigured — so error handling can trust the\nstatus. Check `success` before reading `data`.\n\nAdmission is either a validated principal or the shared service key, presented\nas X-API-Key or a Bearer; neither is refused, and an unset key fails closed\nrather than opening the fetcher to the private network. Pages are archived under\nthe scope of the VERIFIED principal and NEVER a scope named in the body, so a\nURL already read under that scope is answered from the archive without touching\nthe network; a service caller has no org and its pages land in the shared\ncorpus.\n\nThe URL is caller-supplied and dialled from INSIDE the cluster, which makes this\na request-forgery primitive by construction. Only http and https are accepted,\nand every address actually dialled must be public unicast — loopback,\nlink-local, private and multicast are refused. The check lives in the DIALER\nrather than on the hostname, because resolving a name to validate it and then\nletting the transport resolve it again is a gap DNS rebinding walks straight\nthrough; redirects re-enter the same dialer.","tags":["crawl"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/crawl.crawlRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/crawl.crawlResult"}}},"description":"ok"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/crawl.crawlResult"}}},"description":"bad request"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"crawl","x-public":true,"x-tool":true}},"/v1/dataroom/analytics/dataroom/{dataroomId}":{"get":{"operationId":"get_dataroom_analytics_dataroom_by_dataroomid","summary":"Rolls up every share link pointing at one data room: session and page-view totals for the room, plus the per-page breakdown for each link beneath it.","description":"Rolls up every share link pointing at one data room:\nsession and page-view totals for the room, plus the per-page breakdown for each\nlink beneath it.\n\nA room id outside the caller's own tenant store is not found. Only links that\nNAME the room are counted — a link created over a single document contributes\nnothing here, even when that document also sits in the room.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["dataroom"],"parameters":[{"name":"dataroomId","in":"path","required":true,"description":"DataroomID is the room to report on. It is the path segment, resolved in\nthe caller's own tenant store.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.dataroomStats"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataroom","x-public":true,"x-tool":true}},"/v1/dataroom/analytics/link/{linkId}":{"get":{"operationId":"get_dataroom_analytics_link_by_linkid","summary":"Reports how one share link was actually read: total viewing sessions, total page views, and per page the view count, the summed dwell measure and its average.","description":"Reports how one share link was actually read: total viewing\nsessions, total page views, and per page the view count, the summed dwell\nmeasure and its average.\n\nThe link is resolved in the caller's OWN tenant store, so another org's link id\nis not found — knowing a link id is enough to OPEN the room it shares, and\nnever enough to read who has been reading it.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["dataroom"],"parameters":[{"name":"linkId","in":"path","required":true,"description":"LinkID is the link to report on. It is the path segment, resolved in the\ncaller's own tenant store.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.dataroomLinkStats"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataroom","x-public":true,"x-tool":true}},"/v1/dataroom/datarooms":{"get":{"operationId":"get_dataroom_datarooms","summary":"Returns every data room in the caller org's own store, newest first, with its short public id, name, description and timestamps.","description":"Returns every data room in the caller org's own store, newest\nfirst, with its short public id, name, description and timestamps.\n\nDocuments are not included — a room's contents come from reading the single\nroom.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["dataroom"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.dataroomRooms"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataroom","x-public":true,"x-tool":true},"post":{"operationId":"post_dataroom_datarooms","summary":"Opens a new data room for the caller org and answers with it, including the short public id it is addressed by.","description":"Opens a new data room for the caller org and answers with it,\nincluding the short public id it is addressed by.\n\n`name` is required; without it the call is refused and the tenant store is\nuntouched, because a dispatch answering 4xx rolls its transaction back. A new\nroom holds no documents and is reachable by NOBODY until a share link is\ncreated over it — opening a room and granting access are two separate acts, so\na room cannot leak by existing.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["dataroom"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.dataroomCreate"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.dataroomRoomOne"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataroom","x-public":true,"x-tool":true}},"/v1/dataroom/datarooms/{id}":{"get":{"operationId":"get_dataroom_datarooms_by_id","summary":"Reads one of the caller org's data rooms together with every document in it, each carrying its membership id and order index.","description":"Reads one of the caller org's data rooms together with every\ndocument in it, each carrying its membership id and order index.\n\nThe documents are sorted by that index with unordered ones last and creation\ntime breaking ties — the SAME order a link's visitor sees, so this is what the\nroom looks like from the outside. A room id outside the caller's own tenant\nstore is not found.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["dataroom"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the room to read. It is the path segment: the URL is the addressing\nauthority, and the org it is resolved in comes from the caller's principal,\nso an id from another tenant is simply not found.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.dataroomRoomDetailOne"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataroom","x-public":true,"x-tool":true}},"/v1/dataroom/datarooms/{id}/documents":{"post":{"operationId":"post_dataroom_datarooms_by_id_documents","summary":"Puts an already-uploaded document into one of the caller org's data rooms and answers with the new membership id.","description":"Puts an already-uploaded document into one of the caller\norg's data rooms and answers with the new membership id.\n\nIt ATTACHES, it never uploads: the bytes must already be stored, so the usual\norder is upload the document, then add it to the room. Both the room and the\ndocument must exist in the caller's own store — either missing is not found —\nand a document already in the room is refused as a conflict rather than\nduplicated.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["dataroom"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the room to add to. It is the path segment: the URL is the addressing\nauthority, and the org it is resolved in comes from the caller's principal,\nso an id from another tenant is simply not found.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.dataroomAddDocument"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.dataroomMembership"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataroom","x-public":true,"x-tool":true}},"/v1/dataroom/documents":{"get":{"operationId":"get_dataroom_documents","summary":"Returns every document in the caller org's own store, newest first — name, opaque storage key, content type, page count, size and timestamps.","description":"Returns every document in the caller org's own store, newest\nfirst — name, opaque storage key, content type, page count, size and\ntimestamps.\n\nTenant isolation is the per-org store itself: there is one SQLite file per org\nand the org is never a parameter, so no input the caller controls can address\nanother tenant's documents. Metadata only — the bytes come from the file route.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["dataroom"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.dataroomDocuments"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataroom","x-public":true,"x-tool":true},"post":{"operationId":"post_dataroom_documents","summary":"Upload a document's bytes and record it","description":"Takes the file ITSELF as the raw request body — not a JSON envelope, not multipart — stores it on the object-storage client, and records the metadata row, answering with the new document. `?name=` names it (default \"document\"), the request's Content-Type is recorded as the document's mime type, and `?numPages=` is optional. That recorded type is metadata the owner sees; what the file is later SERVED as is read from the bytes.\n\nRequires a validated principal that is a SuperAdmin or an admin of the org; 401 without one, 403 for a member who is neither. An empty body is 400 and anything over 64 MiB is 413 — a data room holds decks and PDFs, not a media library.\n\nThe storage key is 128 random bits under the tenant's own key prefix, minted before the bytes are written: if the system's randomness is unavailable the upload fails 500 rather than fall back to a predictable key that could overwrite another document's bytes. A storage write that fails is 502 and no metadata row is recorded, so a document never exists without its file.","tags":["dataroom"],"x-app":"dataroom","x-public":true}},"/v1/dataroom/documents/{id}":{"get":{"operationId":"get_dataroom_documents_by_id","summary":"Reads one of the caller org's documents — its name, opaque storage key, content type, page count, size and timestamps.","description":"Reads one of the caller org's documents — its name, opaque storage\nkey, content type, page count, size and timestamps.\n\nThe lookup runs in the caller's own tenant store, so an id belonging to another\norg is not found exactly like one that never existed. Metadata only: the bytes\nare a separate read.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["dataroom"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the document to read. It is the path segment: the URL is the\naddressing authority, and the org it is resolved in comes from the caller's\nprincipal, so an id from another tenant is simply not found.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.dataroomDocumentOne"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataroom","x-public":true,"x-tool":true}},"/v1/dataroom/documents/{id}/file":{"get":{"operationId":"get_dataroom_documents_by_id_file","summary":"Download a document's bytes as its owner","description":"Streams the stored file back under the type read from its BYTES — a raster image or a PDF renders in place, and anything else is served as application/octet-stream with an attachment disposition, so a stored file never executes as markup in this origin. Every response carries nosniff, which keeps the declared type binding.\n\nRequires a validated principal that is a SuperAdmin or an admin of the org; 401 without one, 403 for a member who is neither, and the document is resolved in the caller's own tenant store, so another org's id is a 404. This is the OWNER's path and applies no link gate at all — the per-link password, email and download controls live on the viewer surface, not here. Bytes that cannot be fetched from object storage are 502, never a truncated or empty file.","tags":["dataroom"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"dataroom","x-public":true}},"/v1/dataroom/health":{"get":{"operationId":"get_dataroom_health","summary":"Reports that the data room subsystem is up.","description":"Reports that the data room subsystem is up.\n\nIt answers before the bundle loads, holds no state and touches no store, so it\nstays true in exactly the situation an operator is probing for. It says nothing\nabout whether a room can be OPENED — that is what the room operations answer —\nbecause a liveness probe that fails on a dependency takes a working process out\nof rotation.","tags":["dataroom"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.dataroomLiveness"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataroom","x-public":true,"x-tool":true}},"/v1/dataroom/links":{"get":{"operationId":"get_dataroom_links","summary":"Returns every live share link in the caller org's own store, newest first, with the controls a visitor will meet: whether an address is required, whether a password is set, the allow and deny lists, whether download is permitted, and when the link expires.","description":"Returns every live share link in the caller org's own store,\nnewest first, with the controls a visitor will meet: whether an address is\nrequired, whether a password is set, the allow and deny lists, whether download\nis permitted, and when the link expires.\n\nArchived links are omitted entirely. A link reports only THAT a password is\nset — the stored form is a bcrypt hash and no route returns it.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["dataroom"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.dataroomLinks"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataroom","x-public":true,"x-tool":true},"post":{"operationId":"post_dataroom_links","summary":"Grants access: it mints a public share link over one data room (`dataroomId`) or one document (`documentId`) — one of the two is required — and answers with the link, whose `id` is the token a visitor opens it with.","description":"Grants access: it mints a public share link over one data\nroom (`dataroomId`) or one document (`documentId`) — one of the two is\nrequired — and answers with the link, whose `id` is the token a visitor opens\nit with.\n\nThis is how a party is let in. The controls are declared HERE and enforced on\nthe viewer surface: `password` is hashed with bcrypt before storage and is\nnever readable back, `emailProtected` (on by default) makes a visitor state an\naddress, `allowList`/`denyList` narrow which addresses pass, `allowDownload`\n(off by default) governs downloads, and `expiresAt` closes the link. The target\nroom or document must exist in the caller's own store or it is not found.\n\nCreating a link also writes dataroom's ONE cross-tenant row: the link id to\nowning org mapping an anonymous visitor is routed through. That write is part\nof the operation — if it fails the call is 500 — so a link that no visitor\ncould open is never handed back as usable.\n\nThe address a visitor later states is recorded UNVERIFIED, so a link gated only\nby email is openable by anyone the link reaches. Use a password for a link that\nmust not travel.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["dataroom"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.dataroomLinkCreate"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.dataroomLinkOne"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataroom","x-public":true,"x-tool":true}},"/v1/dataroom/trust":{"get":{"operationId":"get_dataroom_trust","summary":"Answers the caller org's OWN trust centre: its settings, every item it holds in both tiers, the requests waiting on it, and the grants it has made.","description":"Answers the caller org's OWN trust centre: its settings, every item it\nholds in both tiers, the requests waiting on it, and the grants it has made.\n\nThe org is the caller's, taken from the validated bearer and from nothing else,\nso this op cannot be pointed at another tenant — there is no field for one. An\norg that has never opened a centre reads back an empty one rather than an error,\nbecause having no trust centre is an ordinary state and this is the read that\ntells you so.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["dataroom"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.trustDesk"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataroom","x-public":true,"x-tool":true},"put":{"operationId":"put_dataroom_trust","summary":"SetCenter opens, publishes or withdraws the caller org's trust centre and answers with the centre as it now stands.","description":"SetCenter opens, publishes or withdraws the caller org's trust centre and answers\nwith the centre as it now stands.\n\nPublishing requires a name and an address, and the address must be free: another\norg already answering there is a conflict, never a takeover. Withdrawing closes\nthe public endpoint only — items, grants and the access record are untouched, so\nan org can go quiet and come back without losing anything.\n\nOnly an admin of the org may call it. The org is the caller's own, so there is no\nfield naming one and no way to point this at another tenant.","tags":["dataroom"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.trustSettings"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.trustDesk"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataroom","x-public":true,"x-tool":true}},"/v1/dataroom/trust/artifacts":{"post":{"operationId":"post_dataroom_trust_artifacts","summary":"Puts an item on the caller org's trust centre and answers with it.","description":"Puts an item on the caller org's trust centre and answers with it.\n\nThe item is GATED unless it says otherwise, so a kind nobody has thought of yet\narrives private and someone has to release it deliberately — that default is what\nkeeps an auditor's report from becoming readable because a field went unset. An\nitem whose attester is \"auditor\" cannot be public at all: the database refuses the\npair, so no path through this API can publish one.\n\nA file is optional and is uploaded FIRST, through POST /v1/dataroom/documents,\nthen named here — the data room is the one place bytes enter, so a trust centre\ndocument is an ordinary data-room document and inherits its storage, its grants\nand its page-by-page access record. A gated item that has a file is added to the\norg's release room, which is what lets a party be granted the whole gated tier in\none link.\n\nOnly an admin of the org may call it.","tags":["dataroom"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.trustPublish"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.trustItemView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataroom","x-public":true,"x-tool":true}},"/v1/dataroom/trust/artifacts/{id}":{"patch":{"operationId":"patch_dataroom_trust_artifacts_by_id","summary":"Changes an item on the caller org's trust centre — replace its file with a newer edition, move it between public and gated, rewrite what it says, or retire it — and answers with the item as it now stands.","description":"Changes an item on the caller org's trust centre — replace its file with a\nnewer edition, move it between public and gated, rewrite what it says, or retire\nit — and answers with the item as it now stands.\n\nRetiring is the withdrawal: the item leaves the public centre immediately and can\nno longer be granted, while grants already made over it stand, because a release\nthat happened is part of the record and un-happening it in the record would be a\nlie. Restoring is the same call with retired false.\n\nMoving an item an independent auditor signed to the public tier is refused, and\nrefused by the database rather than only here. Only an admin of the org may call\nit, and the item is resolved in that org's own store, so another org's id is not\nfound.","tags":["dataroom"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the item to change, taken from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.trustEdit"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.trustItemView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataroom","x-public":true,"x-tool":true}},"/v1/dataroom/trust/center/{slug}":{"get":{"operationId":"get_dataroom_trust_center_by_slug","summary":"Answers an org's public trust centre: its name, the text a party must accept to ask for a document, and every item it publishes.","description":"Answers an org's public trust centre: its name, the text a party must\naccept to ask for a document, and every item it publishes.\n\nAn item is either available NOW — the things the org states itself, its policies,\nits filled questionnaires, its subprocessor list, its knowledge base — or\navailable ON REQUEST, which is everything an independent auditor put their name\nto. Both are listed by name and kind, so a reader can see WHAT exists before\nasking for it; only the second withholds the content.\n\nNo principal is involved and none is accepted: the org is resolved from the\naddress, which answers only for a centre its owner has published. An address\nnobody publishes at is not found, the same answer an unpublished one gets.","tags":["dataroom"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the centre's public address. It resolves only for an org that has\npublished; anything else is not found, so this cannot be used to learn which\norgs exist.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.trustPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataroom","x-public":true,"x-tool":true}},"/v1/dataroom/trust/center/{slug}/file/{item}":{"get":{"operationId":"get_dataroom_trust_center_by_slug_file_by_item","summary":"Read a public trust-centre item's bytes","description":"Streams the file behind an item a trust centre publishes openly — a policy, a filled questionnaire, a knowledge-base attachment — under the type read from its bytes: a picture or a PDF renders in place, anything else downloads inert.\n\nNo principal and no link: these are the things an org states about itself, so they are served to anyone who asks. The narrowing is in the lookup rather than in a check: the item must be public, must not be retired, and must belong to a centre its owner has published, so an item released only on request is NOT FOUND here rather than refused — the same answer an id that never existed gets, which is what stops this reporting what the released-on-request tier holds.\n\nBytes that cannot be fetched from object storage are 502, never a truncated file.","tags":["dataroom"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"item","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"dataroom","x-public":true}},"/v1/dataroom/trust/center/{slug}/requests":{"post":{"operationId":"post_dataroom_trust_center_by_slug_requests","summary":"Records a request to read what an independent auditor signed, and answers with its id.","description":"Records a request to read what an independent auditor signed, and\nanswers with its id.\n\nThe org that owns the centre decides. Nothing is released here and no link is\nminted: this writes the ask down, which is the whole promise the form makes.\nThe write is the answer — a request that could not be stored is an error, never\na receipt, so a form can never appear to have been sent and be gone.\n\n`email` is required and is the ONLY address the eventual grant will admit, so an\naddress the asker cannot read is an ask that cannot be answered. Where the centre\nstates an NDA, `accept` must be true and the text in force is recorded verbatim\nagainst the request.\n\nAsking twice for the same thing from the same address is the SAME ask: the second\nanswers with the first's id rather than opening a second row, which is also what\nkeeps an anonymous endpoint from filling a tenant's store.","tags":["dataroom"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the centre's public address, taken from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.trustAsk"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.trustAsked"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataroom","x-public":true,"x-tool":true}},"/v1/dataroom/trust/requests/{id}/grant":{"post":{"operationId":"post_dataroom_trust_requests_by_id_grant","summary":"Answers a request by opening access: it mints a share link over what was asked for, addressed to the address that asked and closing at expiry, records the decision, and mails the asker.","description":"Answers a request by opening access: it mints a share link over what was\nasked for, addressed to the address that asked and closing at expiry, records the\ndecision, and mails the asker.\n\nThe link is NEVER a public URL. It carries the asker's address on its allow list,\nso forwarding it to somebody else does not open it, and it expires. What the\nparty then does with it — which document, which page, for how long — is recorded\nby the data room's own view tracking, which is where the access record for this\nrelease lives; there is no second log.\n\nA request that was already answered is refused rather than answered twice, so a\nsecond click cannot mint a second link. Only an admin of the org may call it, and\nthe request is resolved in that org's own store, so another org's request id is\nnot found — which is also what stops one org deciding another's queue.\n\nMail is best effort and the grant does not depend on it: a deployment that sends\nno mail still records the grant and says so in `delivery`, so the approver knows\nto pass the address on themselves.","tags":["dataroom"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the request to answer, taken from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.trustDecision"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.trustGranted"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataroom","x-public":true,"x-tool":true}},"/v1/dataroom/trust/requests/{id}/refuse":{"post":{"operationId":"post_dataroom_trust_requests_by_id_refuse","summary":"Answers a request by declining it, recording who declined and why.","description":"Answers a request by declining it, recording who declined and why.\n\nNothing is released and no link is minted. The refusal STAYS on the record beside\nthe ask — a request that was turned down is part of the access record exactly as\none that was granted is, and deleting it would leave a queue that only ever shows\nthe decisions somebody liked.\n\nA request that was already answered is refused rather than answered twice. Only an\nadmin of the org may call it, and the request is resolved in that org's own store,\nso another org's request id is not found.","tags":["dataroom"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the request to answer, taken from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.trustDecision"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataroom.trustRefused"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataroom","x-public":true,"x-tool":true}},"/v1/dataroom/view/{linkId}":{"get":{"operationId":"get_dataroom_view_by_linkid","summary":"What a share link's visitor sees before authenticating","description":"Answers the pre-auth face of a link to anyone holding its id: name and type, which gates apply (whether an address is required, whether a password is set), whether download is permitted, whether it has expired, and the name and description of the room behind it — or, for a single-document link, that document's name and page count.\n\nNo principal is involved: the owning org is resolved from the link id through dataroom's one cross-tenant routing table, and an unknown or archived link is a 404.\n\nIt is metadata only — a room's document list and every file stay behind the authenticate step. An expired link is REPORTED as expired here rather than refused, so a visitor learns why the next step will fail; nothing about the password beyond its existence is disclosed.","tags":["dataroom"],"parameters":[{"name":"linkId","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"dataroom","x-public":true}},"/v1/dataroom/view/{linkId}/authenticate":{"post":{"operationId":"post_dataroom_view_by_linkid_authenticate","summary":"Pass a share link's gates and open a viewing session","description":"Clears the link's access controls and answers with the viewing session — a `viewId`, whether download is permitted, and the documents behind the link — which every later viewer call is authorised by.\n\nNo principal: the visitor is whoever holds the link id, and the org is resolved from it. The gates run in a fixed order and each is a flat refusal, never a hint. An archived or unknown link is 404 and an expired one 403. A missing address on an email-protected link is 401. An address on the deny list is 403, checked BEFORE the allow list so deny always wins. An address the allow list does not admit is 403 — an EMPTY allow list admits everyone, so a link with no list enforces the email gate alone. A wrong or absent password is 401, decided against the stored bcrypt hash.\n\nThe address is taken as stated and recorded UNVERIFIED: it names a viewer for analytics and repeat visits from it reuse one viewer record, but it proves nothing about who is on the other end. A link gated only by email is openable by anyone the link reaches.","tags":["dataroom"],"parameters":[{"name":"linkId","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"dataroom","x-public":true}},"/v1/dataroom/view/{linkId}/document/{documentId}/file":{"get":{"operationId":"get_dataroom_view_by_linkid_document_by_documentid_file","summary":"Read a document's bytes as an authorised link visitor","description":"Streams a document's bytes to a visitor holding an open viewing session, under the type read from those bytes: a picture or a PDF renders in place, anything else downloads inert.\n\nNo principal: `?viewId=` from the authenticate step is the authorisation and must belong to this link, or the call is 403 — holding the link id alone gets no bytes. The document must be reachable THROUGH this link (a member of the room the link opens, or the single document the link names), so a visitor cannot walk to an unrelated document by guessing an id; anything else is a 404, as is an unknown or archived link. Bytes that cannot be fetched from object storage are 502.\n\n`?download=1` additionally requires the link's `allowDownload` and is 403 when the owner did not permit it. Read that flag precisely: it gates the DOWNLOAD intent, not access to the bytes — without the parameter an authorised visitor is served the file for in-place viewing whether or not downloads are allowed.","tags":["dataroom"],"parameters":[{"name":"linkId","in":"path","required":true,"schema":{"type":"string"}},{"name":"documentId","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"dataroom","x-public":true}},"/v1/dataroom/view/{linkId}/pageview":{"post":{"operationId":"post_dataroom_view_by_linkid_pageview","summary":"Record one page-view against an open viewing session","description":"Appends a single per-page analytics event — {viewId, pageNumber, documentId, versionNumber, duration} — and answers with its id. These events are what the owner's analytics count.\n\nNo principal: the `viewId` from the authenticate step IS the authorisation, and it must belong to THIS link or the call is 404, so a session opened on one link cannot write events onto another. `pageNumber` is required (400 without it); `documentId` falls back to the document the session was opened on, and `duration` is the caller's own dwell measure, summed per page by analytics.\n\nEvents are additive: the same page reported twice is two views, which is the metric's whole point.","tags":["dataroom"],"parameters":[{"name":"linkId","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"dataroom","x-public":true}},"/v1/dataset":{"get":{"operationId":"riskDatasets","summary":"List this org's datasets","description":"Datasets lists this org's datasets, each with its newest version. An org that\nhas declared none gets an empty list; a store that cannot be reached gets a\nrefusal, never an empty list, because the two read identically and only one of\nthem is true.","tags":["dataset"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataset.riskDatasetList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataset","x-public":true,"x-tool":true},"post":{"operationId":"riskCreateDataset","summary":"Declare the next version of a dataset","description":"Declares the next version of a dataset from a bound query over\nthis org's own feature surface.\n\nIt mints a VERSION and writes no rows: a version is declared, then materialised\nonce, then never rewritten. Version numbers are monotone and never reused, so\n\"version 3 of signups\" means one thing forever — which is the whole reason a\nmodel can cite one.\n\nThe window is bounded by the source's retention, the horizon by a year, the\nrows by the plane's cap, and the number of datasets and versions per org by\ntheir own limits. Every refusal names which bound it hit.","tags":["dataset"],"requestBody":{"content":{"application/json":{"example":{"from":"2026-01-01T00:00:00Z","horizon":14,"kind":"person","name":"signups","to":"2026-04-01T00:00:00Z"},"schema":{"$ref":"#/components/schemas/dataset.riskDatasetSpec"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataset.riskDataset"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataset","x-public":true,"x-tool":true}},"/v1/dataset/{name}":{"delete":{"operationId":"riskDeleteDataset","summary":"Dispose of one dataset and every version of it","description":"Disposes of one dataset and every version of it: the rows are\ndropped and the register is marked with what went.\n\nThis is the ONLY expiry in this plane. Neither table carries a TTL, deliberately:\na table TTL is a fleet-wide clock no tenant can hold longer or shorten, which is\nthe opposite of a retention decision belonging to the tenant whose records they\nare. The drop is a partition drop on (org, dataset), so the tenant is the first\ncomponent of the thing being dropped and a disposal cannot be spelled across one.\n\nThe BYTES are what goes. The register keeps one `disposed` row per version — the\nname, the number, the spec, the digest and who disposed of it when — for two\nreasons: a retention obligation is answered by a record of the deletion, not by\nsilence; and version numbers must stay monotone, so that after `orders` is\ndisposed of and declared again the next version is 4 and not 1. A number that\ncould be reused would make every citation of `orders v3` ambiguous forever.\n\nIt is not reversible and there is no soft state in between. A version a model\ncited has no rows once this returns, and every read of it says so.","tags":["dataset"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the dataset, from the path.","schema":{"type":"string"},"example":"signups"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataset.riskDatasetDisposal"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataset","x-public":true,"x-tool":true},"get":{"operationId":"riskDataset","summary":"Describe every version of one dataset","description":"Dataset describes every version of one dataset, newest first — the whole\nhistory, because the point of a version is that the older ones are still there\nand a model fitted last quarter cites one of them.\n\nA name this org does not own answers 404, exactly as an unknown name does, so a\nprobe learns nothing about another tenant's datasets.","tags":["dataset"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the dataset, from the path.","schema":{"type":"string"},"example":"signups"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataset.riskDatasetVersions"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataset","x-public":true,"x-tool":true}},"/v1/dataset/{name}/export":{"get":{"operationId":"riskExportDataset","summary":"Read a version's rows back, one page at a time","description":"Reads a published version's rows back, one bounded page at a\ntime, in the version's own stable row order.\n\nOnly a published version can be exported. Rows written by an attempt that never\ncompleted are inert — no register row names them — and they are disposed of with\nthe dataset.","tags":["dataset"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the dataset, from the path.","schema":{"type":"string"},"example":"signups"},{"name":"version","in":"query","required":false,"description":"Version is the version to read. Zero takes the newest published one.","schema":{"format":"int64","type":"integer"},"example":1},{"name":"split","in":"query","required":false,"description":"Split narrows to train, val or test. Empty reads every split.","schema":{"type":"string"},"example":"train"},{"name":"offset","in":"query","required":false,"description":"Offset is where the page starts, in the version's own row order (by id,\nwhich is derived from the row and therefore stable forever).","schema":{"format":"int64","type":"integer"}},{"name":"limit","in":"query","required":false,"description":"Limit is how many rows to return. Zero and anything above the plane's bound\ntake the bound.","schema":{"format":"int64","type":"integer"},"example":500}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataset.riskDatasetRows"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataset","x-public":true,"x-tool":true}},"/v1/dataset/{name}/lineage":{"get":{"operationId":"riskDatasetLineage","summary":"Show where a version's rows came from, and whether that can still be demonstrated","description":"Shows where a version's rows came from and whether that can\nstill be demonstrated.\n\nThe answer is MEASURED, not recalled: the plane asks the source the same\nbounded question again and compares it to the fingerprint taken when the\nversion was built. Anything but exact agreement is reported as drift — the\nsource is fed by a rollup that runs behind the events, so \"it holds more now\"\nis the ordinary case and it means re-running the spec would not reproduce this\nversion. An admitted gap is actionable; an unfalsifiable claim is not.\n\nIT IS A PRICED, BOUNDED READ, because it is the same statement a\nmaterialisation is charged for: an exact distinct-count over up to 400 days of\nthis org's feature surface. It takes the org's ONE source-scan slot, so a\ntenant looping it spends one scan and not a thousand; it counts against the\nplane's ceiling, so the fleet's warehouse is bounded too; and it runs under\nthis plane's own deadline rather than the caller's patience.","tags":["dataset"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the dataset, from the path.","schema":{"type":"string"},"example":"signups"},{"name":"version","in":"query","required":false,"description":"Version is the version to trace. Zero takes the newest published one.","schema":{"format":"int64","type":"integer"},"example":1}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataset.riskLineage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataset","x-public":true,"x-tool":true}},"/v1/dataset/{name}/materialize":{"post":{"operationId":"riskMaterializeDataset","summary":"Materialise the declared version into immutable rows","description":"Builds the declared version into immutable rows and answers\n202 as soon as the attempt is on record.\n\nIt never holds the request open for the work: a materialisation is a bounded\nwarehouse scan, and letting an HTTP client's timeout be a data plane's timeout\nis how one tenant's retry loop becomes everyone's outage. ONE materialisation\nruns per org at a time; a second is refused rather than queued, because a queue\nadmits the same work later and the honest answer to \"again\" while one is\nrunning is that one is running.\n\nOnly a DECLARED version is admitted. A published version is immutable, and a\nversion whose earlier attempt did not complete is never re-attempted — that\nwould union two runs' rows under one number and make the digest a lie. In both\ncases the answer is to declare a new version, which is what a second run over a\nmoving source honestly is.","tags":["dataset"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the dataset, from the path.","schema":{"type":"string"},"example":"signups"}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dataset.riskDataset"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"dataset","x-public":true,"x-tool":true}},"/v1/decisions":{"post":{"operationId":"post_decisions","summary":"Implements POST /v1/decisions (the Decisions API).","description":"Implements POST /v1/decisions (the Decisions API).\n\nBody: {\"model\": \"kai\", \"state\": \"...\"|{...}|[...], \"questions\": {\"\u003cname\u003e\":\n{\"type\": \"boolean\"|\"choice\"|\"score\", \"instructions\": ..., \"criteria\": ...}}}.\nmodel is kai, Kai's versioned id kai-\u003c12 hex of the weights' sha256\u003e — priced as\nkai and sent as asked — or Jev by OpenRouter's vendor ids, typesafe/jev-1.13 and\n~typesafe/jev-latest, which reach Jev itself and bill at Jev's list price, or Zen\nby zenlm/zen6 and zenlm/zen6-flash, answered by a chat completion under a strict\nschema and billed its output beside its input. No Jev id is ever answered by Kai:\na bare one, such as jev-latest, is an unknown model. model is required; state\nand questions are required unless the request names a handle, which carries\nneither. instructions is optional and any JSON. A choice names at least 2 labels\nand a score at least 1 level, bounded by the token budget rather than a count;\nquestions holds 1 to 100.\n\nA boolean is a yes/no probability, answered {\"type\": \"boolean\", \"probability\":\np}. noul is accepted as Jev's spelling of it and answered in Jev's shape,\n{\"type\": \"noul\", \"noul\": p}; an older Kai adds confidence and answer_confidence to\na noul's. A boolean carries no confidence. Jev is asked a boolean as a noul, and\nits answer comes back as exactly the boolean.\n\nobserve holds the state under an id, and a later request naming that id as its\nhandle decides over it again. An id is 1 to 128 characters of A-Z, a-z, 0-9, '.',\n'_' and '-'. A handle belongs to the org that observed it: no other org's request\ncan name it.\n\nResponse: {\"id\",\"model\",\"provider\",\"answers\":{\"\u003cname\u003e\":{\"type\",...}},\n\"usage\":{\"input_tokens\",\"output_tokens\"},\"routing\",\"state_hash\",\"latency_ms\"}.\nusage.input_tokens is the billed count — the request's text counted once, the\nstate once and each question's instructions and options once; a decision over a\nhandle bills the state once, when it was observed.\n\nThe body may be sent gzip, deflate, br or zstd encoded; decoded, it is bounded as\nsent.\n\nRefusals are {\"error\":{\"code\",\"message\"}}: 400 malformed JSON or unknown model,\n401 no valid credential, 402 insufficient balance, 403 a key kind that may not\ncall this (pk-), 415 any other Content-Encoding, 422 an invalid question or handle\nid, a state beyond the checkpoint's reach (code state_too_long) or a body past 16\nMiB (code request_too_long), 429 rate limited or queue full, 502 the service\nfailed, 503 the model is known and not served, 529 overloaded. 402, 429 and 529\ncarry Retry-After and Retry-After-Ms, and every answer carries X-Request-Id.\nBilled on the answer's input and output tokens at the model's price.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.DecisionsRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.DecisionsResponse"}}},"description":"Success.","headers":{"X-Request-Id":{"description":"The id this answer is filed under: the caller's own X-Request-Id, or a fresh one.","schema":{"type":"string"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.DecisionsRefused"}}},"description":"Malformed JSON, or a model this path does not serve.","headers":{"X-Request-Id":{"description":"The id this answer is filed under: the caller's own X-Request-Id, or a fresh one.","schema":{"type":"string"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.DecisionsRefused"}}},"description":"No credential, or one this service does not accept.","headers":{"X-Request-Id":{"description":"The id this answer is filed under: the caller's own X-Request-Id, or a fresh one.","schema":{"type":"string"}}}},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.DecisionsRefused"}}},"description":"The balance cannot cover the call. Retry-After is when a top-up is read.","headers":{"Retry-After":{"description":"Seconds to wait before asking again.","schema":{"type":"integer"}},"Retry-After-Ms":{"description":"Milliseconds to wait before asking again.","schema":{"type":"integer"}},"X-Request-Id":{"description":"The id this answer is filed under: the caller's own X-Request-Id, or a fresh one.","schema":{"type":"string"}}}},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.DecisionsRefused"}}},"description":"A credential whose kind may not call this, such as a publishable (pk-) key.","headers":{"X-Request-Id":{"description":"The id this answer is filed under: the caller's own X-Request-Id, or a fresh one.","schema":{"type":"string"}}}},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.DecisionsRefused"}}},"description":"A question that is not valid, a state beyond what the checkpoint reads (code state_too_long), or a body past the bound both the gateway and the service hold (code request_too_long).","headers":{"X-Request-Id":{"description":"The id this answer is filed under: the caller's own X-Request-Id, or a fresh one.","schema":{"type":"string"}}}},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.DecisionsRefused"}}},"description":"Rate limited, or the queue is full.","headers":{"Retry-After":{"description":"Seconds to wait before asking again.","schema":{"type":"integer"}},"Retry-After-Ms":{"description":"Milliseconds to wait before asking again.","schema":{"type":"integer"}},"X-Request-Id":{"description":"The id this answer is filed under: the caller's own X-Request-Id, or a fresh one.","schema":{"type":"string"}}}},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.DecisionsRefused"}}},"description":"The decision service failed.","headers":{"X-Request-Id":{"description":"The id this answer is filed under: the caller's own X-Request-Id, or a fresh one.","schema":{"type":"string"}}}},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.DecisionsRefused"}}},"description":"The model is known and not served.","headers":{"X-Request-Id":{"description":"The id this answer is filed under: the caller's own X-Request-Id, or a fresh one.","schema":{"type":"string"}}}},"529":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.DecisionsRefused"}}},"description":"Overloaded.","headers":{"Retry-After":{"description":"Seconds to wait before asking again.","schema":{"type":"integer"}},"Retry-After-Ms":{"description":"Milliseconds to wait before asking again.","schema":{"type":"integer"}},"X-Request-Id":{"description":"The id this answer is filed under: the caller's own X-Request-Id, or a fresh one.","schema":{"type":"string"}}}}},"x-app":"ai","x-public":true}},"/v1/decisions/{decision}/corrections":{"get":{"operationId":"decisionsCorrections","summary":"Answers one of the org's decisions' corrections, each captured (it can teach) or missing (the decision was made with capture off).","description":"Answers one of the org's decisions' corrections, each\ncaptured (it can teach) or missing (the decision was made with capture off).","tags":["ai"],"parameters":[{"name":"decision","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Corrections"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ai","x-public":true,"x-tool":true},"post":{"operationId":"decisionsCorrect","summary":"Files a correction of one question of one of the org's Kai decisions: the right answer, which must be one of that question's options and not what Kai answered, and why.","description":"Files a correction of one question of one of the org's Kai\ndecisions: the right answer, which must be one of that question's options and\nnot what Kai answered, and why. A decision Kai captured can teach a capability\nof its question (/v1/capabilities); one made with capture off is kept with\nstate missing and cannot. The org's first correction turns capture on, so its\nnext decisions can teach. Refused: 409 not_wrong when the answer is Kai's own,\n409 corrected when the question already has a correction, 404 when the\ndecision captured no such question.","tags":["ai"],"parameters":[{"name":"decision","in":"path","required":true,"description":"Decision is the decision's id.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"answer":"refund","note":"the customer asked for their money back","question":"intent"},"schema":{"$ref":"#/components/schemas/CorrectIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Correction"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ai","x-public":true,"x-tool":true}},"/v1/decisions/{decision}/corrections/{id}":{"delete":{"operationId":"decisionsUncorrect","summary":"Deletes one correction of one of the org's decisions.","description":"Deletes one correction of one of the org's decisions.\nA capability already taught from it keeps its versions.","tags":["ai"],"parameters":[{"name":"decision","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ai","x-public":true,"x-tool":true}},"/v1/deploy/applications":{"get":{"operationId":"get_deploy_applications","summary":"Returns the fleet as an argocd ApplicationList: one projected Application per operator App CR, carrying the image tag the CR DECLARES, the tag actually RUNNING in the cluster's Deployment, the reconciled health, and the sync verdict those two produce (declared == running ⇒ Synced, both known and different ⇒ OutOfSync, either unknown ⇒ Unknown).","description":"Returns the fleet as an argocd ApplicationList: one\nprojected Application per operator App CR, carrying the image tag the CR\nDECLARES, the tag actually RUNNING in the cluster's Deployment, the reconciled\nhealth, and the sync verdict those two produce (declared == running ⇒ Synced,\nboth known and different ⇒ OutOfSync, either unknown ⇒ Unknown).\n\nIt is TENANT-SCOPED: a platform SuperAdmin reads every platform namespace, a\nvalidated org member reads only its own org's tenant namespace and only the App\nCRs labelled with its org, and anyone else is refused. A cross-tenant CR is\nnever projected into an answer.","tags":["deploy"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/deploy.argoAppList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"deploy","x-public":true,"x-tool":true}},"/v1/deploy/applications/{name}":{"get":{"operationId":"get_deploy_applications_by_name","summary":"Returns ONE projected argocd Application by name, with status.resources filled in from its reconciled resource tree — which is what makes it the detail view rather than a row of the list.","description":"Returns ONE projected argocd Application by name, with\nstatus.resources filled in from its reconciled resource tree — which is what\nmakes it the detail view rather than a row of the list.\n\nIt is TENANT-SCOPED, and a name that belongs to another org is reported NOT\nFOUND rather than refused: a 403 would confirm the application exists, so the\nroute would become a cross-tenant existence oracle. A name that is not a\nDNS-1123 label is a 400 before any cluster read.","tags":["deploy"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the application to read, from the path. It must be a DNS-1123 label\n(lowercase alphanumerics and hyphens, starting and ending alphanumeric) —\nevery operator App CR's metadata.name satisfies that, and anything else is a\n400 rather than a lookup.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/deploy.argoApp"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"deploy","x-public":true,"x-tool":true}},"/v1/deploy/applications/{name}/resource-tree":{"get":{"operationId":"get_deploy_applications_by_name_resource-tree","summary":"Returns one application's argocd ApplicationTree: the objects the operator reconciled from its App CR, reached by ownerRef — the Deployment and, under it, the ReplicaSet and Pods, plus the Service, Ingress, HorizontalPodAutoscaler, PodDisruptionBudget and ConfigMaps it owns — each node carrying its parent edges and its health.","description":"Returns one application's argocd ApplicationTree: the\nobjects the operator reconciled from its App CR, reached by ownerRef — the\nDeployment and, under it, the ReplicaSet and Pods, plus the Service, Ingress,\nHorizontalPodAutoscaler, PodDisruptionBudget and ConfigMaps it owns — each node\ncarrying its parent edges and its health.\n\nSecrets are DELIBERATELY not walked, so no materialized environment can ever\nappear in the tree. Tenant-scoped exactly like the application read: another\norg's name is not found, a malformed name is a 400.","tags":["deploy"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the application to read, from the path. It must be a DNS-1123 label\n(lowercase alphanumerics and hyphens, starting and ending alphanumeric) —\nevery operator App CR's metadata.name satisfies that, and anything else is a\n400 rather than a lookup.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/deploy.argoTree"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"deploy","x-public":true,"x-tool":true}},"/v1/deploy/applications/{name}/revisions/{revision}/metadata":{"get":{"operationId":"get_deploy_applications_by_name_revisions_by_revision_metadata","summary":"Returns the argocd RevisionMetadata for one revision of one application — what the detail view shows beside a revision.","description":"Returns the argocd RevisionMetadata for one revision\nof one application — what the detail view shows beside a revision.\n\nAn App CR is IMAGE-pinned rather than commit-pinned: the deploy names an image\ntag, and the git source this projection reports is the display-only manifest\nrepo, not the application's own source. Nothing in this process can read a\ncommit's author or message for an arbitrary revision. So rather than 404 (which\nthe SPA turns into an error toast) or invent a git author, it answers the\nHONEST minimum: date is when the App CR was created, message is the revision\nasked for — with the empty revision and \"HEAD\" resolving to the image tag the\nCR declares — and author is empty. An over-long revision is truncated before it\nis echoed back.\n\nTenant-scoped exactly like the application read.","tags":["deploy"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the application to read, from the path. It must be a DNS-1123 label.","schema":{"type":"string"}},{"name":"revision","in":"path","required":true,"description":"Revision is the revision to describe, from the path. The empty revision and\n\"HEAD\" both mean \"whatever this application currently declares\".","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/deploy.argoRevisionMetadata"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"deploy","x-public":true,"x-tool":true}},"/v1/deploy/applications/{name}/rollback":{"post":{"operationId":"post_deploy_applications_by_name_rollback","summary":"Serves the console's rollback control, and today it requests a reconcile and nothing more.","description":"Serves the console's rollback control, and today it\nrequests a reconcile and nothing more.\n\nThe opening verb is not style. zipdoc drops a leading CamelCase symbol only\nwhen a plain verb follows it and never before a copula (internal/zipdoc/\nextract.go:811-824, \"CompleteDeployment IS the CI completion hook\" would\notherwise become \"Is the CI completion hook\") — so \"RollbackDeployApplication\nis …\" would publish a Go symbol no caller can see into the summary an SDK\ndocstring, an MCP tool list and a CLI help line all show.\n\nIt performs exactly what the sync action performs — the same stamp on the same\nApp CR, the same application re-projected — and it does NOT select, pin or\nrevert to a prior image tag. That is the one thing to know before wiring\nanything to it: the name is the console's, the behaviour is the sync. Pinning a\nprevious release rides the release client, which this address does not call yet.\n\nSame gate, same refusals and the same absent request body as the sync it shares\na core with.","tags":["deploy"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the application to read, from the path. It must be a DNS-1123 label\n(lowercase alphanumerics and hyphens, starting and ending alphanumeric) —\nevery operator App CR's metadata.name satisfies that, and anything else is a\n400 rather than a lookup.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/deploy.argoApp"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"deploy","x-public":true,"x-tool":true}},"/v1/deploy/applications/{name}/syncwindows":{"get":{"operationId":"get_deploy_applications_by_name_syncwindows","summary":"Returns one application's argocd ApplicationSyncWindowState — the answer to \"is anything blocking a sync of this application right now?\".","description":"Returns one application's argocd\nApplicationSyncWindowState — the answer to \"is anything blocking a sync of this\napplication right now?\".\n\nThis platform runs NO sync windows, so the answer is always the permissive\nempty one: canSync true, with no active and no assigned windows. The\napplication is still resolved first, so a name that is not the caller's is not\nfound rather than handed the static body — the endpoint discloses nothing about\nanother tenant's fleet.","tags":["deploy"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the application to read, from the path. It must be a DNS-1123 label\n(lowercase alphanumerics and hyphens, starting and ending alphanumeric) —\nevery operator App CR's metadata.name satisfies that, and anything else is a\n400 rather than a lookup.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/deploy.argoSyncWindows"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"deploy","x-public":true,"x-tool":true}},"/v1/deploy/clusters":{"get":{"operationId":"get_deploy_clusters","summary":"Returns the argocd ClusterList of the destinations the caller's applications reconcile into: one entry per distinct destination server, carrying the count of applications reconciling into it.","description":"Returns the argocd ClusterList of the destinations the\ncaller's applications reconcile into: one entry per distinct destination\nserver, carrying the count of applications reconciling into it. The in-cluster\ndestination is always present, so an empty fleet still answers one cluster, and\nno cluster credential can appear — the projected type physically has no config\nfield.\n\nIt is TENANT-SCOPED and reads the SAME App CRs the applications list reads: a\nplatform SuperAdmin counts the whole fleet, a validated org member counts only\nits own org's applications, anyone else is refused.","tags":["deploy"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/deploy.argoClusterList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"deploy","x-public":true,"x-tool":true}},"/v1/deploy/health":{"get":{"operationId":"get_deploy_health","summary":"Reports whether this deployment can observe the delivery plane.","description":"Reports whether this deployment can observe the delivery plane.\n\n200 only when the Kubernetes API answers AND the App custom resource is served;\n503 with the same shape otherwise, naming which half failed. It reports BOOLEANS\nand never the underlying error, because the route is unauthenticated — liveness\nmust be probe-able without a token — and a raw client error can disclose the\napiserver address or an RBAC detail. That detail is logged server-side instead.","tags":["deploy"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/deploy.deployHealth"}}},"description":"ok"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/deploy.deployHealth"}}},"description":"service unavailable"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"deploy","x-public":true,"x-tool":true}},"/v1/deploy/login":{"get":{"operationId":"get_deploy_login","summary":"Start the sign-in round trip for this console","description":"Redirects the browser to IAM's authorize endpoint, having minted a nonce and a PKCE verifier into a short-lived, single-use flow cookie. The nonce comes back as `state` and is what proves the code belongs to the round trip THIS browser started; the verifier never appears in the address bar.\n\nNecessarily public — this is how a browser gets a principal for this host in the first place — and it grants nothing by itself. An optional `returnTo` names where to land afterwards and is run through the open-redirect guard, so only a same-host path survives. A deployment with no sign-in configured answers 503 rather than redirecting nowhere.","tags":["deploy"],"x-app":"deploy","x-public":true}},"/v1/deploy/logout":{"post":{"operationId":"post_deploy_logout","summary":"Ends the console session on this host.","description":"Ends the console session on this host.\n\nIt clears this console's session cookie and answers the signed-out state with\nthe sign-in URL to start again. IAM's own session is untouched — this ends the\nconsole session only, so signing back in may not prompt for credentials.\n\nIt is a POST because it CHANGES STATE. As a GET it was reachable by a\ncross-site top-level navigation, which a SameSite=Lax cookie still rides, so\nany page could sign a SuperAdmin out; a POST is not carried cross-site by that\ncookie. It reads no request body and takes no argument: the session it ends is\nthe one the request already carries.","tags":["deploy"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/deploy.sessionEnded"}}},"description":"ok","headers":{"Set-Cookie":{"description":"Set by POST /v1/deploy/logout.","schema":{"type":"string"}}}},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"deploy","x-public":true,"x-tool":true}},"/v1/deploy/projects":{"get":{"operationId":"get_deploy_projects","summary":"Returns the argocd AppProjectList this console groups and filters applications by.","description":"Returns the argocd AppProjectList this console groups and\nfilters applications by. Projects are owned by Hanzo IAM rather than by argocd,\nso they are REFLECTED read-only from the IAM project store and nothing is\npersisted here: a validated org member gets its own organization's projects and\na platform SuperAdmin gets every organization's.\n\nA SuperAdmin whose IAM store is not reachable falls back to the real\nargoproj.io AppProject CRs when that CRD is served, and otherwise to one\npermissive synthesized project per distinct project name the App CRs declare.\nA project named \"default\" is always present, because that is what an App CR\ncarrying no project label projects to.","tags":["deploy"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/deploy.argoProjectList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"deploy","x-public":true,"x-tool":true}},"/v1/deploy/session/userinfo":{"get":{"operationId":"get_deploy_session_userinfo","summary":"Answers \"is this browser signed in, and if not where does it sign in?\" — the dashboard SPA's bootstrap question, and the only route on this plane that answers for an anonymous caller.","description":"Answers \"is this browser signed in, and if not where does it\nsign in?\" — the dashboard SPA's bootstrap question, and the only route on this\nplane that answers for an anonymous caller.\n\nThe anonymous answer carries loggedIn:false and a URL and NOTHING else: no\nusername, no org, no groups, no issuer, no hint about who the caller might be or\nwhat exists in the cluster. Answering it costs nothing (the caller already knows\nwhether it holds a cookie) and withholding it costs the whole sign-in journey.\n\nThe predicate is the platform SuperAdmin fact — the SAME one every other route\nhere gates on, minted from a validated principal whose org is the reserved admin\norg — so a validated-but-not-SuperAdmin caller is reported as NOT signed in,\nwhich is the truth as this console defines it: they cannot use it.","tags":["deploy"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/deploy.sessionUser"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"deploy","x-public":true,"x-tool":true}},"/v1/deploy/stream/applications":{"get":{"operationId":"get_deploy_stream_applications","summary":"Live application fleet updates as Server-Sent Events","description":"Holds the connection open as text/event-stream and pushes one watch event per application change. It opens with an `ADDED` frame for every application currently present — the same projection the applications list serves, so a client renders a complete fleet from the stream alone — and then forwards `ADDED`, `MODIFIED` and `DELETED` as they happen, with a keep-alive every 25 seconds that is also how a vanished client is noticed and its watch torn down.\n\nRead-only and TENANT-SCOPED, fail-closed: a platform SuperAdmin streams the whole fleet, a validated org member streams only its own org's applications, anyone else gets 403 and no stream. No cluster client configured is 503. If the deployment is not granted the watch verb the stream degrades to keep-alives only — the initial state still renders, it simply stops updating — rather than failing the connection.","tags":["deploy"],"x-app":"deploy","x-public":true}},"/v1/deploy/stream/applications/{name}/resource-tree":{"get":{"operationId":"get_deploy_stream_applications_by_name_resource-tree","summary":"Live resource tree for one application, as Server-Sent Events","description":"Holds the connection open as text/event-stream and pushes the application's whole resource tree — its live child objects and each one's derived health — once immediately and again on every keep-alive tick, so a client always has a current picture without polling. The refresh IS the keep-alive: it is a cheap rebuild rather than a watch, so there is no multi-resource watch to leak.\n\nTENANT-SCOPED and fail-closed BEFORE the stream opens, which is the rule that matters: the caller's scope and the application's namespace are resolved first, so an unvalidated caller gets a plain 403 and an application belonging to another tenant gets a plain 404 — never an opened stream that emits nothing. A SuperAdmin reaches the whole fleet, an org member only its own org's applications. No cluster client configured is 503.","tags":["deploy"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"deploy","x-public":true}},"/v1/destination":{"get":{"operationId":"get_destination","summary":"Reports every destination this deployment can forward to, each with the caller org's connection state: whether it is connected, whether it is enabled, whether a credential resolves right now, and the config fields the console renders for it.","description":"Reports every destination this deployment can forward to, each with the\ncaller org's connection state: whether it is connected, whether it is enabled,\nwhether a credential resolves right now, and the config fields the console\nrenders for it.","tags":["destination"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/destination.destinationList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"destination","x-public":true,"x-tool":true}},"/v1/destination/{platform}":{"delete":{"operationId":"delete_destination_by_platform","summary":"Forgets a destination for the caller's org: every credential held in KMS, then the stored config.","description":"Forgets a destination for the caller's org: every credential held in\nKMS, then the stored config. Idempotent, and it requires org admin.","tags":["destination"],"parameters":[{"name":"platform","in":"path","required":true,"description":"Platform is the destination to act on, from the path: ga4 | meta | tiktok |\nlinkedin | x | reddit | insights.","schema":{"type":"string"},"example":"ga4"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/destination.destinationDisconnected"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"destination","x-public":true,"x-tool":true},"get":{"operationId":"get_destination_by_platform","summary":"Reports one destination's card for the caller's org — its config fields, its connection state, and whether a credential resolves right now.","description":"Reports one destination's card for the caller's org — its config fields,\nits connection state, and whether a credential resolves right now. A platform\nthis deployment does not carry is not found.","tags":["destination"],"parameters":[{"name":"platform","in":"path","required":true,"description":"Platform is the destination to act on, from the path: ga4 | meta | tiktok |\nlinkedin | x | reddit | insights.","schema":{"type":"string"},"example":"ga4"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/destination.DestinationStatus"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"destination","x-public":true,"x-tool":true},"post":{"operationId":"post_destination_by_platform","summary":"Connect one conversion destination for your org, or update the one you have","description":"Stores the addressed platform's non-secret ids (its measurement, pixel or dataset ids) and seals its API credential into KMS under a path scoped to the caller's own org, then answers the same status card the read routes do — with live telling you whether the credential actually resolves right now. The body's property NAMES are the platform's own: each field the platform declares, plus each secret under its camelCase name, so the accepted keys differ per platform and a missing REQUIRED field is refused. Connecting is an ORG ADMIN action — a validated member without the admin bit gets 403 — and it fails closed with 503 when the KMS master key is unavailable rather than persisting a destination whose secret was never sealed. The secret itself never appears in the response, in the store, or in a log line; only its NAME is ever published. Set enabled to false to keep the connection but stop the analytics fan-out to it.","tags":["destination"],"parameters":[{"name":"platform","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}}},"responses":{"2XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DestinationStatus"}}},"description":"Success"}},"x-app":"destination","x-public":true}},"/v1/destination/{platform}/test":{"post":{"operationId":"post_destination_by_platform_test","summary":"Sends ONE synthetic conversion through the connected destination end to end and reports what the platform said.","description":"Sends ONE synthetic conversion through the connected destination end to\nend and reports what the platform said. Where the platform can check one without\nrecording it, it is a lead and nothing is kept: GA4 answers from its validation\nserver, Google Ads validates without importing, and Meta files it under the\nconnection's Test Event Code (and is refused without one). Anywhere else it is a\npage view. A send the platform refuses is reported as data — {\"ok\": false,\n\"error\": …} at 200 — so the console shows the platform's own words rather than\nan error about Hanzo. It requires org admin.","tags":["destination"],"parameters":[{"name":"platform","in":"path","required":true,"description":"Platform is the destination to act on, from the path: ga4 | meta | tiktok |\nlinkedin | x | reddit | insights.","schema":{"type":"string"},"example":"ga4"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/destination.destinationTest"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"destination","x-public":true,"x-tool":true}},"/v1/dns/health":{"get":{"operationId":"get_dns_health","summary":"Check the DNS control plane","description":"Reports whether the DNS control plane is answering. The plane owns the authoritative zone and record store behind every name pointed at Hanzo; this head keeps none of it. The address and the query string ARE the plane's own, relayed verbatim, and the plane's answer comes back unchanged — its status code, its Content-Type, and its Location on a redirect this head never follows.\n\nIt travels under the CALLER'S OWN identity and substitutes no service credential, which would collapse tenants: the caller's validated session bearer goes upstream as Authorization and the server-validated org as X-Org-Id, so a caller in one org reaches only that org's zones, exactly as if it had called the plane directly. The upstream host comes only from deployment config, never from the request, so no path can re-target another host.\n\nFails closed before a byte leaves cloud: no validated principal is 403; an API key is 401, because a pk-/sk- key is not a JWT the OIDC-gated plane can validate and there is no substitute credential to send in its place; a path that normalizes outside /v1/dns, or still carries a percent-escape or a `..` after one decode, is 400; an unconfigured plane is 503 and an unreachable one 502.","tags":["dns"],"x-app":"dns","x-public":true}},"/v1/dns/sync":{"post":{"operationId":"post_dns_sync","summary":"Push a set of zones and records in one call","description":"Replaces the calling org's zones and their records in bulk. The owning org is the caller's own validated claim, never the body, so a sync reaches nobody else's zones. The plane owns the authoritative zone and record store behind every name pointed at Hanzo; this head keeps none of it. The address and the query string ARE the plane's own, relayed verbatim, and the plane's answer comes back unchanged — its status code, its Content-Type, and its Location on a redirect this head never follows.\n\nIt travels under the CALLER'S OWN identity and substitutes no service credential, which would collapse tenants: the caller's validated session bearer goes upstream as Authorization and the server-validated org as X-Org-Id, so a caller in one org reaches only that org's zones, exactly as if it had called the plane directly. The upstream host comes only from deployment config, never from the request, so no path can re-target another host.\n\nFails closed before a byte leaves cloud: no validated principal is 403; an API key is 401, because a pk-/sk- key is not a JWT the OIDC-gated plane can validate and there is no substitute credential to send in its place; a path that normalizes outside /v1/dns, or still carries a percent-escape or a `..` after one decode, is 400; an unconfigured plane is 503 and an unreachable one 502.","tags":["dns"],"x-app":"dns","x-public":true}},"/v1/dns/zones":{"get":{"operationId":"get_dns_zones","summary":"List your org's DNS zones","description":"Lists every DNS zone the calling org holds, authoritative and provider-backed alike. The plane owns the authoritative zone and record store behind every name pointed at Hanzo; this head keeps none of it. The address and the query string ARE the plane's own, relayed verbatim, and the plane's answer comes back unchanged — its status code, its Content-Type, and its Location on a redirect this head never follows.\n\nIt travels under the CALLER'S OWN identity and substitutes no service credential, which would collapse tenants: the caller's validated session bearer goes upstream as Authorization and the server-validated org as X-Org-Id, so a caller in one org reaches only that org's zones, exactly as if it had called the plane directly. The upstream host comes only from deployment config, never from the request, so no path can re-target another host.\n\nFails closed before a byte leaves cloud: no validated principal is 403; an API key is 401, because a pk-/sk- key is not a JWT the OIDC-gated plane can validate and there is no substitute credential to send in its place; a path that normalizes outside /v1/dns, or still carries a percent-escape or a `..` after one decode, is 400; an unconfigured plane is 503 and an unreachable one 502.","tags":["dns"],"x-app":"dns","x-public":true},"post":{"operationId":"post_dns_zones","summary":"Create a DNS zone","description":"Creates a zone for the calling org — authoritative, or backed by a DNS provider the org has connected. The plane owns the authoritative zone and record store behind every name pointed at Hanzo; this head keeps none of it. The address and the query string ARE the plane's own, relayed verbatim, and the plane's answer comes back unchanged — its status code, its Content-Type, and its Location on a redirect this head never follows.\n\nIt travels under the CALLER'S OWN identity and substitutes no service credential, which would collapse tenants: the caller's validated session bearer goes upstream as Authorization and the server-validated org as X-Org-Id, so a caller in one org reaches only that org's zones, exactly as if it had called the plane directly. The upstream host comes only from deployment config, never from the request, so no path can re-target another host.\n\nFails closed before a byte leaves cloud: no validated principal is 403; an API key is 401, because a pk-/sk- key is not a JWT the OIDC-gated plane can validate and there is no substitute credential to send in its place; a path that normalizes outside /v1/dns, or still carries a percent-escape or a `..` after one decode, is 400; an unconfigured plane is 503 and an unreachable one 502.","tags":["dns"],"x-app":"dns","x-public":true}},"/v1/dns/zones/{zone}":{"delete":{"operationId":"delete_dns_zones_by_zone","summary":"Delete a DNS zone","description":"Removes one of the calling org's zones, and the records in it, from the DNS control plane. The plane owns the authoritative zone and record store behind every name pointed at Hanzo; this head keeps none of it. The address and the query string ARE the plane's own, relayed verbatim, and the plane's answer comes back unchanged — its status code, its Content-Type, and its Location on a redirect this head never follows.\n\nIt travels under the CALLER'S OWN identity and substitutes no service credential, which would collapse tenants: the caller's validated session bearer goes upstream as Authorization and the server-validated org as X-Org-Id, so a caller in one org reaches only that org's zones, exactly as if it had called the plane directly. The upstream host comes only from deployment config, never from the request, so no path can re-target another host.\n\nFails closed before a byte leaves cloud: no validated principal is 403; an API key is 401, because a pk-/sk- key is not a JWT the OIDC-gated plane can validate and there is no substitute credential to send in its place; a path that normalizes outside /v1/dns, or still carries a percent-escape or a `..` after one decode, is 400; an unconfigured plane is 503 and an unreachable one 502.","tags":["dns"],"parameters":[{"name":"zone","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"dns","x-public":true},"get":{"operationId":"get_dns_zones_by_zone","summary":"Read one DNS zone","description":"Reads one of the calling org's zones by name. The plane owns the authoritative zone and record store behind every name pointed at Hanzo; this head keeps none of it. The address and the query string ARE the plane's own, relayed verbatim, and the plane's answer comes back unchanged — its status code, its Content-Type, and its Location on a redirect this head never follows.\n\nIt travels under the CALLER'S OWN identity and substitutes no service credential, which would collapse tenants: the caller's validated session bearer goes upstream as Authorization and the server-validated org as X-Org-Id, so a caller in one org reaches only that org's zones, exactly as if it had called the plane directly. The upstream host comes only from deployment config, never from the request, so no path can re-target another host.\n\nFails closed before a byte leaves cloud: no validated principal is 403; an API key is 401, because a pk-/sk- key is not a JWT the OIDC-gated plane can validate and there is no substitute credential to send in its place; a path that normalizes outside /v1/dns, or still carries a percent-escape or a `..` after one decode, is 400; an unconfigured plane is 503 and an unreachable one 502.","tags":["dns"],"parameters":[{"name":"zone","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"dns","x-public":true}},"/v1/dns/zones/{zone}/records":{"get":{"operationId":"get_dns_zones_by_zone_records","summary":"List a zone's DNS records","description":"Lists the records in one zone. A provider-backed zone is read from the provider, which is its source of truth. The plane owns the authoritative zone and record store behind every name pointed at Hanzo; this head keeps none of it. The address and the query string ARE the plane's own, relayed verbatim, and the plane's answer comes back unchanged — its status code, its Content-Type, and its Location on a redirect this head never follows.\n\nIt travels under the CALLER'S OWN identity and substitutes no service credential, which would collapse tenants: the caller's validated session bearer goes upstream as Authorization and the server-validated org as X-Org-Id, so a caller in one org reaches only that org's zones, exactly as if it had called the plane directly. The upstream host comes only from deployment config, never from the request, so no path can re-target another host.\n\nFails closed before a byte leaves cloud: no validated principal is 403; an API key is 401, because a pk-/sk- key is not a JWT the OIDC-gated plane can validate and there is no substitute credential to send in its place; a path that normalizes outside /v1/dns, or still carries a percent-escape or a `..` after one decode, is 400; an unconfigured plane is 503 and an unreachable one 502.","tags":["dns"],"parameters":[{"name":"zone","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"dns","x-public":true},"post":{"operationId":"post_dns_zones_by_zone_records","summary":"Create a DNS record","description":"Creates a record in one zone. A provider-backed zone is written at the provider first, then mirrored locally so the resolver serves it. The plane owns the authoritative zone and record store behind every name pointed at Hanzo; this head keeps none of it. The address and the query string ARE the plane's own, relayed verbatim, and the plane's answer comes back unchanged — its status code, its Content-Type, and its Location on a redirect this head never follows.\n\nIt travels under the CALLER'S OWN identity and substitutes no service credential, which would collapse tenants: the caller's validated session bearer goes upstream as Authorization and the server-validated org as X-Org-Id, so a caller in one org reaches only that org's zones, exactly as if it had called the plane directly. The upstream host comes only from deployment config, never from the request, so no path can re-target another host.\n\nFails closed before a byte leaves cloud: no validated principal is 403; an API key is 401, because a pk-/sk- key is not a JWT the OIDC-gated plane can validate and there is no substitute credential to send in its place; a path that normalizes outside /v1/dns, or still carries a percent-escape or a `..` after one decode, is 400; an unconfigured plane is 503 and an unreachable one 502.","tags":["dns"],"parameters":[{"name":"zone","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"dns","x-public":true}},"/v1/dns/zones/{zone}/records/{record}":{"delete":{"operationId":"delete_dns_zones_by_zone_records_by_record","summary":"Delete a DNS record","description":"Removes one record from one zone. The plane owns the authoritative zone and record store behind every name pointed at Hanzo; this head keeps none of it. The address and the query string ARE the plane's own, relayed verbatim, and the plane's answer comes back unchanged — its status code, its Content-Type, and its Location on a redirect this head never follows.\n\nIt travels under the CALLER'S OWN identity and substitutes no service credential, which would collapse tenants: the caller's validated session bearer goes upstream as Authorization and the server-validated org as X-Org-Id, so a caller in one org reaches only that org's zones, exactly as if it had called the plane directly. The upstream host comes only from deployment config, never from the request, so no path can re-target another host.\n\nFails closed before a byte leaves cloud: no validated principal is 403; an API key is 401, because a pk-/sk- key is not a JWT the OIDC-gated plane can validate and there is no substitute credential to send in its place; a path that normalizes outside /v1/dns, or still carries a percent-escape or a `..` after one decode, is 400; an unconfigured plane is 503 and an unreachable one 502.","tags":["dns"],"parameters":[{"name":"zone","in":"path","required":true,"schema":{"type":"string"}},{"name":"record","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"dns","x-public":true},"get":{"operationId":"get_dns_zones_by_zone_records_by_record","summary":"Read one DNS record","description":"Reads one record of one zone by its id. The plane owns the authoritative zone and record store behind every name pointed at Hanzo; this head keeps none of it. The address and the query string ARE the plane's own, relayed verbatim, and the plane's answer comes back unchanged — its status code, its Content-Type, and its Location on a redirect this head never follows.\n\nIt travels under the CALLER'S OWN identity and substitutes no service credential, which would collapse tenants: the caller's validated session bearer goes upstream as Authorization and the server-validated org as X-Org-Id, so a caller in one org reaches only that org's zones, exactly as if it had called the plane directly. The upstream host comes only from deployment config, never from the request, so no path can re-target another host.\n\nFails closed before a byte leaves cloud: no validated principal is 403; an API key is 401, because a pk-/sk- key is not a JWT the OIDC-gated plane can validate and there is no substitute credential to send in its place; a path that normalizes outside /v1/dns, or still carries a percent-escape or a `..` after one decode, is 400; an unconfigured plane is 503 and an unreachable one 502.","tags":["dns"],"parameters":[{"name":"zone","in":"path","required":true,"schema":{"type":"string"}},{"name":"record","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"dns","x-public":true},"patch":{"operationId":"patch_dns_zones_by_zone_records_by_record","summary":"Amend a DNS record","description":"Amends one record of one zone. Only the fields the body carries change; the rest keep the values they hold at the plane. The plane owns the authoritative zone and record store behind every name pointed at Hanzo; this head keeps none of it. The address and the query string ARE the plane's own, relayed verbatim, and the plane's answer comes back unchanged — its status code, its Content-Type, and its Location on a redirect this head never follows.\n\nIt travels under the CALLER'S OWN identity and substitutes no service credential, which would collapse tenants: the caller's validated session bearer goes upstream as Authorization and the server-validated org as X-Org-Id, so a caller in one org reaches only that org's zones, exactly as if it had called the plane directly. The upstream host comes only from deployment config, never from the request, so no path can re-target another host.\n\nFails closed before a byte leaves cloud: no validated principal is 403; an API key is 401, because a pk-/sk- key is not a JWT the OIDC-gated plane can validate and there is no substitute credential to send in its place; a path that normalizes outside /v1/dns, or still carries a percent-escape or a `..` after one decode, is 400; an unconfigured plane is 503 and an unreachable one 502.","tags":["dns"],"parameters":[{"name":"zone","in":"path","required":true,"schema":{"type":"string"}},{"name":"record","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"dns","x-public":true},"put":{"operationId":"put_dns_zones_by_zone_records_by_record","summary":"Amend a DNS record","description":"Amends one record of one zone. Only the fields the body carries change; this is the same partial update PATCH performs, not a replacement of the whole record. The plane owns the authoritative zone and record store behind every name pointed at Hanzo; this head keeps none of it. The address and the query string ARE the plane's own, relayed verbatim, and the plane's answer comes back unchanged — its status code, its Content-Type, and its Location on a redirect this head never follows.\n\nIt travels under the CALLER'S OWN identity and substitutes no service credential, which would collapse tenants: the caller's validated session bearer goes upstream as Authorization and the server-validated org as X-Org-Id, so a caller in one org reaches only that org's zones, exactly as if it had called the plane directly. The upstream host comes only from deployment config, never from the request, so no path can re-target another host.\n\nFails closed before a byte leaves cloud: no validated principal is 403; an API key is 401, because a pk-/sk- key is not a JWT the OIDC-gated plane can validate and there is no substitute credential to send in its place; a path that normalizes outside /v1/dns, or still carries a percent-escape or a `..` after one decode, is 400; an unconfigured plane is 503 and an unreachable one 502.","tags":["dns"],"parameters":[{"name":"zone","in":"path","required":true,"schema":{"type":"string"}},{"name":"record","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"dns","x-public":true}},"/v1/domain/availability":{"get":{"operationId":"get_domain_availability","summary":"Checks exact names rather than searching for them, and answers the same quote shape search does — purchasable, premium, first-term and renewal price in cents.","description":"Checks exact names rather than searching for them, and answers the\nsame quote shape search does — purchasable, premium, first-term and renewal price\nin cents.\n\nIt requires a validated principal; 401 without one. Nothing is charged and\nnothing is held. A deployment with no registrar credentials answers 503.","tags":["domain"],"parameters":[{"name":"domain","in":"query","required":true,"description":"Domain is one name, or several comma-separated, to check in one call. Names\nare lowercased. It is required.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/domain.quoteList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"domain","x-public":true,"x-tool":true}},"/v1/domain/domains":{"get":{"operationId":"get_domain_domains","summary":"Is the domains your org has bought here, newest registration first, each carrying the name, when it was registered, when it expires, what the org paid, the registrar order id and the nameservers it points at.","description":"Is the domains your org has bought here, newest registration first, each\ncarrying the name, when it was registered, when it expires, what the org paid,\nthe registrar order id and the nameservers it points at.\n\nScoped to the validated principal's org — 401 without one, and there is no\nparameter that reaches another org's holdings.\n\nThis is the deployment's OWN ownership record, not a query to the registrar: it\nlists what was bought THROUGH this surface, so a domain the org holds elsewhere\nis not here. The default store is in-process, so a deployment that has not\nswapped in a durable store answers from what this process registered.","tags":["domain"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/domain.holdings"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"domain","x-public":true,"x-tool":true}},"/v1/domain/health":{"get":{"operationId":"get_domain_health","summary":"Reports registrar reachability honestly: ok only when the wholesale credentials are present AND name.com accepted them on a live call made while you waited.","description":"Reports registrar reachability honestly: ok only when the wholesale\ncredentials are present AND name.com accepted them on a live call made while you\nwaited.\n\nMissing credentials or an unreachable registrar is 503 carrying configured,\nreachable and the reason, so an operator reads the blocker instead of guessing at\nit. It takes no principal, like every subsystem health probe.","tags":["domain"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/domain.reachability"}}},"description":"ok"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/domain.reachability"}}},"description":"service unavailable"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"domain","x-public":true,"x-tool":true}},"/v1/domain/register":{"post":{"operationId":"post_domain_register","summary":"Buys a domain for your org and answers the ownership record together with the quote it was bought at.","description":"Buys a domain for your org and answers the ownership record together\nwith the quote it was bought at.\n\nThe order of operations is the product guarantee: quote, refuse anything\nunpurchasable or unpriced, AUTHORIZE the org's prepaid balance, provision the\nauthoritative zone in Hanzo DNS, register at the registrar already pointing at\nHanzo's nameservers, and only then CAPTURE the charge and record ownership. A\nregistrar failure therefore leaves the balance untouched — the org is never\nbilled for a domain it did not get.\n\nIt requires a validated principal; that principal's org owns the domain and is\nthe ledger the charge lands on. Re-buying a name the org already holds is 409,\nnot a second purchase.\n\nRefusals are distinct on purpose: 402 when the prepaid balance cannot cover the\nquoted price, 409 when the name is not available, 503 when the deployment has no\nregistrar credentials, and the registrar's own message with its own 4xx — or 502\nfor its 5xx — when it rejects the purchase. Zone provisioning is best-effort: if\nthe zone service is down the domain is still registered against Hanzo's\nnameservers and the zone reconciles afterwards, rather than the purchase failing.","tags":["domain"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/domain.order"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/domain.RegisterResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"domain","x-public":true,"x-tool":true}},"/v1/domain/renew":{"post":{"operationId":"post_domain_renew","summary":"Extends a domain your org already owns and answers the updated record with its new expiry alongside what was paid.","description":"Extends a domain your org already owns and answers the updated record with\nits new expiry alongside what was paid.\n\nOwnership is the gate: a name the caller's org does not hold is 404, so a renewal\ncan never reach another tenant's domain.\n\nThe price is re-quoted at the CURRENT renewal rate rather than the one paid at\npurchase. If the registrar returns no renewal price the org's original price is\ncharged instead, so a renewal is never accidentally free. The balance is\nauthorized before the registrar is called and captured after it confirms — 402\nwhen the prepaid balance cannot cover it, 503 when the deployment has no\nregistrar credentials. Requires a validated principal.","tags":["domain"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/domain.renewReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/domain.RenewResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"domain","x-public":true,"x-tool":true}},"/v1/domain/search":{"get":{"operationId":"get_domain_search","summary":"Finds names built from the keyword q, plus the registrar's alternate-TLD suggestions, and answers a quote for each: the name, whether it is purchasable, whether it is premium, the first-term and renewal price in cents, and the TLD.","description":"Finds names built from the keyword q, plus the registrar's alternate-TLD\nsuggestions, and answers a quote for each: the name, whether it is purchasable,\nwhether it is premium, the first-term and renewal price in cents, and the TLD.\n\nPrices are RETAIL — this deployment's markup is already applied and the wholesale\ncost is never on the wire.\n\nIt requires a validated principal; 401 without one. Nothing is charged and\nnothing is held — a quote is not a reservation, and the price is re-quoted at\npurchase, so a name quoted here can be gone or dearer by the time you buy it. A\ndeployment with no registrar credentials answers 503.","tags":["domain"],"parameters":[{"name":"q","in":"query","required":true,"description":"Q is the keyword to build names from. It is required.","schema":{"type":"string"}},{"name":"tld","in":"query","required":false,"description":"TLD narrows the search to a comma-separated set of top-level domains.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/domain.quoteList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"domain","x-public":true,"x-tool":true}},"/v1/domain/transfer":{"post":{"operationId":"post_domain_transfer","summary":"Moves a domain you own at another registrar onto your org here, using its authCode, and answers the same record-plus-quote a purchase does.","description":"Moves a domain you own at another registrar onto your org here, using\nits authCode, and answers the same record-plus-quote a purchase does.\n\nIt is priced and charged exactly like a registration: authorize the org's prepaid\nbalance, ask the registrar for the transfer, capture only after the registrar\naccepts. A name the registrar will not price is 409, an insufficient balance is\n402, and a deployment with no registrar credentials is 503.\n\nIt requires a validated principal; the ownership record is written under that org\nas soon as the registrar ACCEPTS the request, which is not the same instant the\ntransfer completes at the losing registrar. Unlike a registration this does not\nprovision a zone, so the record carries this deployment's configured nameservers.","tags":["domain"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/domain.transferReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/domain.RegisterResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"domain","x-public":true,"x-tool":true}},"/v1/email":{"get":{"operationId":"get_email","summary":"Retrieves sent email messages for the authenticated organization.","description":"Retrieves sent email messages for the authenticated organization.\n\nGET /v1/email","tags":["email"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit is the maximum number of messages to return (default 50, max 200).","schema":{"format":"int64","type":"integer"}},{"name":"status","in":"query","required":false,"description":"Status filters messages by delivery status.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/email.ListMessagesResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"email","x-public":true,"x-tool":true},"post":{"operationId":"post_email","summary":"Sends commercial email from the org: one message per recipient, each carrying its own signed unsubscribe link in the footer and in List-Unsubscribe and List-Unsubscribe-Post (RFC 8058).","description":"Sends commercial email from the org: one message per recipient,\neach carrying its own signed unsubscribe link in the footer and in\nList-Unsubscribe and List-Unsubscribe-Post (RFC 8058). Every recipient is\nfirst asked of the one suppression check (marketing_clearance): an address the\norg's list holds, whose company unsubscribed, or that the platform blocks is\nnot sent to, and is answered in refused with status 422 and the reason; when\nevery recipient is refused the request is 422. A list that cannot answer sends\nnothing (503). Every message, sent or refused, goes on the CRM record of the\nperson the org holds for the address. Transactional mail — a code, a receipt —\nis not this route's: it goes by /v1/notify, which no opt-out stops.\n\nPOST /v1/email","tags":["email"],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"IdempotencyKey prevents duplicate message dispatches on network retries.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/email.SendMessageInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/email.Dispatch"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"email","x-public":true,"x-tool":true}},"/v1/email/sendgrid/status":{"get":{"operationId":"get_email_sendgrid_status","summary":"Inspects the authenticated organization's dedicated SendGrid outreach configuration (separate from standard Twilio notify) and whitelabel DNS records.","description":"Inspects the authenticated organization's dedicated SendGrid outreach configuration (separate from standard Twilio notify) and whitelabel DNS records.\n\nGET /v1/email/sendgrid/status","tags":["email"],"parameters":[{"name":"domain","in":"query","required":false,"description":"Domain is an optional sending domain to generate SendGrid whitelabel DKIM, Return-Path, and DMARC records for.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/email.SendGridStatusResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"email","x-public":true,"x-tool":true}},"/v1/email/ses/status":{"get":{"operationId":"get_email_ses_status","summary":"Inspects the authenticated organization's Amazon SES configuration, sending limits, and Easy DKIM / MAIL FROM DNS records.","description":"Inspects the authenticated organization's Amazon SES configuration, sending limits, and Easy DKIM / MAIL FROM DNS records.\n\nGET /v1/email/ses/status","tags":["email"],"parameters":[{"name":"domain","in":"query","required":false,"description":"Domain optionally specifies the sending domain to generate Easy DKIM and MAIL FROM records for.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/email.SESStatusResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"email","x-public":true,"x-tool":true}},"/v1/email/verify":{"post":{"operationId":"post_email_verify","summary":"Evaluates an email address using explicitly selected, composable checks.","description":"Evaluates an email address using explicitly selected, composable checks.\n\nA signed-in caller only: the SMTP check connects to the address's mail server\nfrom ours, so an anonymous caller could probe mailboxes and get our addresses\nblocked. Each caller may run 120 checks an hour and 20 of them SMTP probes, and\nthe deployment 6,000 and 400; past either is 429.\n\nPOST /v1/email/verify","tags":["email"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/email.VerificationInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/email.VerificationResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"email","x-public":true,"x-tool":true}},"/v1/email/webhooks/sendgrid":{"post":{"operationId":"post_email_webhooks_sendgrid","summary":"Receives SendGrid's Signed Event Webhook: the delivery is an array of events, signed (ECDSA P-256, SHA-256) over its timestamp header followed by the body, under the public key the organization holds (the webhook-public-key credential).","description":"Receives SendGrid's Signed Event Webhook: the delivery is an\narray of events, signed (ECDSA P-256, SHA-256) over its timestamp header\nfollowed by the body, under the public key the organization holds\n(the webhook-public-key credential). A delivery signed more than ten minutes\nfrom now is refused, so a captured one cannot be replayed.\n\nPOST /v1/email/webhooks/sendgrid?org=\u003corg\u003e","tags":["email"],"x-app":"email","x-public":true}},"/v1/email/webhooks/ses":{"post":{"operationId":"post_email_webhooks_ses","summary":"Receives Amazon SES events as an SNS HTTPS subscription delivers them.","description":"Receives Amazon SES events as an SNS HTTPS subscription delivers\nthem. The organization is named in the address (?org=) and holds the SNS topic\nits events arrive on (the sns-topic-arn credential): a message is accepted when\nit is signed by SNS, is from that topic, and its certificate comes from that\ntopic's region. A subscription confirmation is completed the same way and\nrecords nothing.\n\nPOST /v1/email/webhooks/ses?org=\u003corg\u003e","tags":["email"],"x-app":"email","x-public":true}},"/v1/email/{id}":{"get":{"operationId":"get_email_by_id","summary":"Retrieves message delivery status by ID for the authenticated organization.","description":"Retrieves message delivery status by ID for the authenticated organization.\n\nGET /v1/email/:id","tags":["email"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the unique identifier of the message to retrieve.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/email.MessageRecord"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"email","x-public":true,"x-tool":true}},"/v1/embeddings":{"post":{"operationId":"post_embeddings","summary":"Implements POST /v1/embeddings (OpenAI-compatible).","description":"Implements POST /v1/embeddings (OpenAI-compatible).\n\nBody: {\"model\": \"...\", \"input\": \"...\"|[\"...\", ...], \"encoding_format\"?, \"dimensions\"?}\nIt authenticates the caller, resolves the model to its upstream provider via\nthe shared routing table, rewrites the user-facing model name to the upstream\nid, and proxies the request to the provider's /embeddings endpoint verbatim.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/openai.EmbeddingRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/openai.EmbeddingResponse"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/engine/model":{"get":{"operationId":"engineModel","summary":"Read one model's load state on the serving runtime","description":"Reads one model's load state — loaded, unloading, or not_found, as\nthe engine itself reports it.","tags":["engine"],"parameters":[{"name":"model","in":"query","required":false,"description":"Model is the model id to inspect, exactly as the model list reports it.","schema":{"type":"string"},"example":"Qwen/Qwen3-4B"}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"engine","x-public":true,"x-tool":true}},"/v1/engine/models":{"get":{"operationId":"engineModels","summary":"List the models the serving runtime holds, with each one's load state","description":"Lists the models the engine serves, each with its load state — the\nserver's own model table (its standard list envelope, load status\nincluded), relayed verbatim.","tags":["engine"],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"engine","x-public":true,"x-tool":true}},"/v1/engine/status":{"get":{"operationId":"engineStatus","summary":"Whether the serving runtime is reachable, and which build it runs","description":"Reports whether the engine deployment is reachable and which build\nrevision it runs — an honest lens for \"is the serving runtime up\", never a\nfabricated ok.","tags":["engine"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/engine.engineStatus"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"engine","x-public":true,"x-tool":true}},"/v1/engine/system":{"get":{"operationId":"engineSystem","summary":"The serving host's own inventory: devices, memory and build capabilities","description":"Reads the engine host's inventory: OS, CPU, memory, every accelerator\ndevice with its VRAM and compute capability, and the build's capabilities\n(CUDA/Metal/flash-attention) — the real hardware under the serving runtime,\nrelayed verbatim.","tags":["engine"],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"engine","x-public":true,"x-tool":true}},"/v1/entitlement":{"get":{"operationId":"get_entitlement","summary":"Reports which console apps the CALLER's org may open, and the plan slug that decides it.","description":"Reports which console apps the CALLER's org may open, and the plan slug\nthat decides it. It is the READ side of the unified paywall: the org's plan tier\nresolved from commerce, which is a different authority from the enablement store\nbehind GET /v1/entitlement/orgs/{org} (that one is the org's own on/off intent).\n\nIt never answers 500: an unvalidated principal is a 403, and an app whose plan\ncannot be confirmed is reported locked at 200, so the shell always renders. The\npaywall applies the same rule when it enforces: access follows a confirmed\nstanding.","tags":["entitlement"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/entitlement.projectionView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"entitlement","x-public":true,"x-tool":true}},"/v1/entitlement/orgs/{org}":{"get":{"operationId":"get_entitlement_orgs_by_org","summary":"Lists the products an org has ENABLED — its own intent, which the console's paid-product sidebar reads to decide what to show.","description":"Lists the products an org has ENABLED — its own intent, which the console's\npaid-product sidebar reads to decide what to show. It is distinct from what the\norg's plan ENTITLES it to (that is GET /v1/entitlement, resolved from commerce).\n\nA caller may only read its OWN org's row; a platform super admin may read any.","tags":["entitlement"],"parameters":[{"name":"org","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/entitlement.entitlementsView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"entitlement","x-public":true,"x-tool":true},"post":{"operationId":"post_entitlement_orgs_by_org","summary":"Turns products on or off for an org and returns the enabled set afterwards.","description":"Turns products on or off for an org and returns the enabled set afterwards.\n\nA product may only be ENABLED if the org's plan already ENTITLES it, so enabling\nnever spends new money — a product the plan does not grant answers 402 and the\nconsole routes that to an upgrade prompt. DISABLING is never gated. A platform\nsuper admin bypasses the plan check (operator comp/grant) and may target any org;\neveryone else may only change their own. Commerce unreachable is a 503, never an\nimplicit yes.","tags":["entitlement"],"parameters":[{"name":"org","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"add":["chat"],"remove":["engine"]},"schema":{"$ref":"#/components/schemas/entitlement.mutateReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/entitlement.entitlementsView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"entitlement","x-public":true,"x-tool":true}},"/v1/environment":{"get":{"operationId":"get_environment","summary":"Lists every codebase in your org that has an environment.","description":"Lists every codebase in your org that has an environment.\n\nAn environment is what a coding run does to its checkout before its agent\nstarts: the install script, the start command and the secrets it exports.\nSecret values are never answered — only which names are set. A codebase with\nnothing saved and nothing proposed is not listed.","tags":["environment"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/environment.envList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"environment","x-public":true,"x-tool":true}},"/v1/environment/{repo}":{"delete":{"operationId":"delete_environment_by_repo","summary":"Forgets one codebase's environment, and its secrets with it.","description":"Forgets one codebase's environment, and its secrets with it.\n\nLater runs on the codebase start bare. Each secret's value is removed from KMS\nfirst; one that will not go stops the forget, so no value outlives the record\nthat names it. Org admin only.","tags":["environment"],"parameters":[{"name":"repo","in":"path","required":true,"description":"Repo is the repository's name in the caller's org — a name, never owner/name.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"environment","x-public":true,"x-tool":true},"get":{"operationId":"get_environment_by_repo","summary":"Reads one codebase's environment.","description":"Reads one codebase's environment.\n\nA codebase with none answers 200 with state `none` and empty scripts, so a\nsurface can always draw the editor. `proposed` means a setup run's answer is\nwaiting in `proposal`; nothing in it runs until it is saved.","tags":["environment"],"parameters":[{"name":"repo","in":"path","required":true,"description":"Repo is the repository's name in the caller's org — a name, never owner/name.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/environment.Environment"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"environment","x-public":true,"x-tool":true},"put":{"operationId":"put_environment_by_repo","summary":"Saves one codebase's install and start scripts.","description":"Saves one codebase's install and start scripts.\n\nEvery later sandbox run on this codebase runs the install script in its fresh\ncheckout before the agent starts, and leaves the start command running in the\nbackground. Saving clears any pending proposal: saving is the review. Secrets\nare set one at a time on their own address and are left as they are. Org admin\nonly.","tags":["environment"],"parameters":[{"name":"repo","in":"path","required":true,"description":"Repo is the repository's name in the caller's org.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/environment.envSave"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/environment.Environment"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"environment","x-public":true,"x-tool":true}},"/v1/environment/{repo}/secrets/{name}":{"delete":{"operationId":"delete_environment_by_repo_secrets_by_name","summary":"Removes one secret from a codebase.","description":"Removes one secret from a codebase.\n\nThe value is removed from KMS, then the name from the environment; later runs\nno longer export it. Removing a name that is not set is a 404. Org admin only.","tags":["environment"],"parameters":[{"name":"repo","in":"path","required":true,"description":"Repo is the repository's name in the caller's org.","schema":{"type":"string"}},{"name":"name","in":"path","required":true,"description":"Name is the secret's environment variable name.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/environment.Environment"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"environment","x-public":true,"x-tool":true},"put":{"operationId":"put_environment_by_repo_secrets_by_name","summary":"Sets one secret on a codebase.","description":"Sets one secret on a codebase.\n\nThe value is sealed in KMS and exported to every later sandbox run on this\ncodebase under its name, a setup run included. It is blinded out of every\nstream the run publishes, and no route answers it back. Setting a name that is\nalready set replaces its value. Org admin only.","tags":["environment"],"parameters":[{"name":"repo","in":"path","required":true,"description":"Repo is the repository's name in the caller's org.","schema":{"type":"string"}},{"name":"name","in":"path","required":true,"description":"Name is the environment variable the run exports the value under.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/environment.envSecret"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/environment.Environment"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"environment","x-public":true,"x-tool":true}},"/v1/esign/documents":{"get":{"operationId":"get_esign_documents","summary":"Returns your org's documents, newest first.","description":"Returns your org's documents, newest first.\n\nEach carries its status, recipients and field layout. The listing is capped at\n200 and there is no paging, so treat it as the recent window rather than a\ncomplete export. It reads the caller's own tenant store, so no other org's\ndocuments can appear in it.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["esign"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/esign.esignDocuments"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"esign","x-public":true,"x-tool":true},"post":{"operationId":"post_esign_documents","summary":"Uploads a PDF and opens a draft ready for recipients and fields.","description":"Uploads a PDF and opens a draft ready for recipients and fields.\n\nIt answers 201 with the document in DRAFT — the state where recipients and\nfields may still be added, and the only state they may. The bytes go to object\nstorage rather than into the tenant database, and the original is kept under its\nown key so it survives sealing untouched: a completed document can always be\ncompared against what was uploaded. Creation is recorded on the audit trail.\n\nThis is the sender's surface: a validated principal is required, and the document\nlands in that principal's OWN org. Isolation is physical rather than a filter —\neach tenant has its own store — so another org's document id is simply not\nthere. A body over 32 MiB is refused with 413.\n\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["esign"],"requestBody":{"content":{"application/json":{"example":{"pdfBase64":"JVBERi0xLjQK…","signingOrder":"SEQUENTIAL","title":"Mutual NDA"},"schema":{"$ref":"#/components/schemas/esign.esignUploadIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/esign.esignDocument"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"esign","x-public":true,"x-tool":true}},"/v1/esign/documents/{id}":{"get":{"operationId":"get_esign_documents_by_id","summary":"Returns one document with its recipients and field layout.","description":"Returns one document with its recipients and field layout.\n\nIt answers the document, its recipients with each one's read and signing status,\nand every field with its type, page and position — the view a sender's UI\nrenders, and where the field ids come from. The id is resolved in the caller's\nOWN tenant store, so another org's document id is a 404 rather than a refusal\nthat would confirm it exists.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["esign"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the document to act on. It is the path segment: the URL is the\naddressing authority, and the org it is resolved in comes from the caller's\nprincipal, so an id belonging to another tenant is simply not found.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/esign.esignDocument"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"esign","x-public":true,"x-tool":true}},"/v1/esign/documents/{id}/audit":{"get":{"operationId":"get_esign_documents_by_id_audit","summary":"Returns the document's full audit trail, oldest first.","description":"Returns the document's full audit trail, oldest first.\n\nIt answers every recorded event for the document in order — created, recipient\nadded, field created, sent, opened, each field inserted, each recipient\ncompleted or rejected, and completion — with the actor and timestamp on each.\nThis is the evidence record behind a signature, so it is append-only and nothing\nin the surface edits it.\n\nThe id is resolved in the caller's OWN tenant store, so another org's document\nid is a 404.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["esign"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the document to act on. It is the path segment: the URL is the\naddressing authority, and the org it is resolved in comes from the caller's\nprincipal, so an id belonging to another tenant is simply not found.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/esign.esignTrail"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"esign","x-public":true,"x-tool":true}},"/v1/esign/documents/{id}/download":{"get":{"operationId":"get_esign_documents_by_id_download","summary":"Returns the document — the sealed PDF once it is complete.","description":"Returns the document — the sealed PDF once it is complete.\n\nIt answers the document's current PDF as base64 with a sealed flag and a\nfilename. Before completion that is the original upload; once every signer has\nfinished it is the SEALED artifact, with the field values rendered onto the page\nand a real x509 PKCS#7 digital signature applied. There is one pdfBase64 field\neither way, so sealed is what tells you which you are holding.\n\nThe id is resolved in the caller's OWN tenant store, so another org's document\nid is a 404.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["esign"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the document to act on. It is the path segment: the URL is the\naddressing authority, and the org it is resolved in comes from the caller's\nprincipal, so an id belonging to another tenant is simply not found.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/esign.esignPDF"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"esign","x-public":true,"x-tool":true}},"/v1/esign/documents/{id}/fields":{"post":{"operationId":"post_esign_documents_by_id_fields","summary":"Places a field on the page for one recipient to fill.","description":"Places a field on the page for one recipient to fill.\n\nIt adds a signature, date, name, email or text box at a page and position for\nONE named recipient, and answers 201 with its id. The recipient must belong to\nthis document; one from elsewhere is refused.\n\nFields are what make a recipient signable: a document cannot be sent while any\nsigning recipient has none. Only while DRAFT — adding a field to a sent document\nis a 409 — and an unknown document is a 404. The addition is recorded on the\naudit trail.\n\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["esign"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"page":1,"positionX":72,"positionY":640,"recipientId":"rec_2f…","type":"SIGNATURE"},"schema":{"$ref":"#/components/schemas/esign.esignFieldIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/esign.esignPlacement"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"esign","x-public":true,"x-tool":true}},"/v1/esign/documents/{id}/recipients":{"post":{"operationId":"post_esign_documents_by_id_recipients","summary":"Adds someone to a draft and mints their signing token.","description":"Adds someone to a draft and mints their signing token.\n\nIt answers 201 with the recipient's id and their signing TOKEN — the\ncrypto-random capability that is the only credential the signer's surface\naccepts — so this response is where the signing link is built from. A CC\nrecipient is recorded as already complete, because they are never asked to\nsign.\n\nOnly while DRAFT: adding a recipient to a document already sent is a 409,\nbecause the field layout and the turn order were fixed when it went out. An\nunknown document is a 404. The addition is recorded on the audit trail.\n\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["esign"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"email":"counterparty@example.com","name":"Dana Lee","role":"SIGNER"},"schema":{"$ref":"#/components/schemas/esign.esignRecipientIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/esign.esignInvite"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"esign","x-public":true,"x-tool":true}},"/v1/esign/documents/{id}/send":{"post":{"operationId":"post_esign_documents_by_id_send","summary":"Sends the document out and answers each signer's link.","description":"Sends the document out and answers each signer's link.\n\nIt moves the document from DRAFT to PENDING and answers the signing tokens — one\nper signing recipient, with the path to hand them — which is how the links reach\nthe people who must sign. Nothing is emailed by this call; delivering the links\nis the caller's.\n\nIt refuses to send an unsignable document: no recipients at all is a 400, and so\nis any signing recipient with no fields to fill, named in the error. Re-sending\nan already-pending document is allowed and re-issues the same links rather than\nrestarting anything; a completed document is a 409, and an unknown one a 404.\nThe send is recorded on the audit trail.\n\nOnly a SuperAdmin or an admin of the org may call it; a member who is neither is\nrefused 403.","tags":["esign"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the document to send. The URL is the addressing authority.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/esign.esignLinks"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"esign","x-public":true,"x-tool":true}},"/v1/esign/health":{"get":{"operationId":"get_esign_health","summary":"Reports whether the e-signature surface is mounted.","description":"Reports whether the e-signature surface is mounted.\n\nIt answers ok whenever the subsystem is mounted, takes no tenant and needs no\nprincipal. It is deliberately shallow: it is registered before the document host\nis built, so it still answers on a deployment that came up WITHOUT object\nstorage and therefore serves nothing else. Read it as reachability, never as a\npromise that documents can be stored.","tags":["esign"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/esign.esignHealth"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"esign","x-public":true,"x-tool":true}},"/v1/esign/o/{org}/sign/{token}":{"get":{"operationId":"get_esign_o_by_org_sign_by_token","summary":"Opens a document you were asked to sign, using your signing link.","description":"Opens a document you were asked to sign, using your signing link.\n\nIt answers the document, the recipient the link identifies, the fields THAT\nrecipient must fill, and the PDF to display. The first open also marks the\nrecipient as having opened it and records that on the audit trail, so this read\nhas a side effect by design.\n\nThis surface takes NO account: the signing token is the entire credential, and\nit names the recipient, so a signer sees only their own fields and never the\nother recipients' tokens. The token resolves to its owning tenant FIRST, before\nany per-tenant store is opened, and the org segment is only checked against\nthat answer. An unknown or wrong-org token is one and the same 404, never a\nhint that some other document exists.","tags":["esign"],"parameters":[{"name":"org","in":"path","required":true,"schema":{"type":"string"}},{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/esign.esignSession"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"esign","x-public":true,"x-tool":true}},"/v1/esign/o/{org}/sign/{token}/complete":{"post":{"operationId":"post_esign_o_by_org_sign_by_token_complete","summary":"Finishes your signing — and seals the document if you were the last.","description":"Finishes your signing — and seals the document if you were the\nlast.\n\nIt marks this recipient as done and answers whether the DOCUMENT sealed with it.\nWhen every signing recipient has completed, sealing happens right here in the\nsame call: the collected values are rendered onto the PDF, a real x509 PKCS#7\nsignature is applied, the sealed bytes are stored beside the untouched original,\nand the document moves to COMPLETED. Until then the answer is the recipient's\nown completion with the document still pending.\n\nIt refuses to complete a half-filled signature: a recipient with any unfilled\nfield is a 400 naming how many remain. A document not out for signature is a\n409, as is a recipient who has already completed, and under SEQUENTIAL order a\nsigner out of turn is a 403. The token is the whole credential — no account, and\na token that does not resolve under the org segment is a 404. Sealing and\ncompletion are one transaction, so a failure anywhere leaves the document\nexactly as it was.","tags":["esign"],"parameters":[{"name":"org","in":"path","required":true,"schema":{"type":"string"}},{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/esign.esignCompletion"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"esign","x-public":true,"x-tool":true}},"/v1/esign/o/{org}/sign/{token}/fields/{fieldId}":{"post":{"operationId":"post_esign_o_by_org_sign_by_token_fields_by_fieldid","summary":"Fills in one of your fields.","description":"Fills in one of your fields.\n\nIt records a value for one field and marks it inserted. A signature field takes\na value with isBase64 true for drawn image bytes, or false for a typed\nsignature; a date, name or email field falls back to today, the recipient's name\nor their email when the value is omitted; any other type requires one.\n\nNothing is sealed here — filling every field still leaves the document pending\nuntil the completion call. The token is the whole credential and it bounds what\ncan be written: a field belonging to another recipient is refused with 401 even\nunder a valid token, an unknown field is a 404, and a field already filled is a\n409. A document not out for signature is a 409, as is a recipient who has\nalready completed or rejected. Under SEQUENTIAL order a signer whose turn has\nnot come is refused 403 until every earlier signer has signed. Each insertion is\nrecorded on the audit trail.","tags":["esign"],"parameters":[{"name":"org","in":"path","required":true,"schema":{"type":"string"}},{"name":"token","in":"path","required":true,"schema":{"type":"string"}},{"name":"fieldId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"isBase64":false,"value":"Dana Lee"},"schema":{"$ref":"#/components/schemas/esign.esignValueIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/esign.esignInsertion"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"esign","x-public":true,"x-tool":true}},"/v1/esign/o/{org}/sign/{token}/reject":{"post":{"operationId":"post_esign_o_by_org_sign_by_token_reject","summary":"Declines to sign, with an optional reason.","description":"Declines to sign, with an optional reason.\n\nIt records this recipient's refusal and moves the WHOLE DOCUMENT to REJECTED —\none declining signer ends it for everyone, and there is no route back: the\ndocument cannot then be signed or completed. An optional reason is stored and\nwritten onto the audit trail with the rejection, which is what the sender sees.\n\nA document not out for signature is a 409, and so is a recipient who has already\nsigned or already rejected — a refusal cannot be taken back or repeated. The\ntoken is the whole credential; one that does not resolve under the org segment\nis a 404.","tags":["esign"],"parameters":[{"name":"org","in":"path","required":true,"schema":{"type":"string"}},{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"reason":"Terms changed since we agreed them."},"schema":{"$ref":"#/components/schemas/esign.esignRejectIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/esign.esignRejection"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"esign","x-public":true,"x-tool":true}},"/v1/eval/datasets":{"get":{"operationId":"get_eval_datasets","summary":"Is the datasets your org has, each with its name, description, metadata and timestamps.","description":"Is the datasets your org has, each with its name, description,\nmetadata and timestamps.\n\nIt is the only way to enumerate what an org holds. Requires a validated\nprincipal; 401 without one. Every row is filtered on the validated org, so\nthere is no parameter that reaches another tenant's datasets. The item count is\nNOT populated here — read one dataset to get it.","tags":["eval"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned. It defaults to 100 and is capped at 500; a\nnon-positive or unparseable value falls back to the default rather than\nfailing, because a typo about paging is not a reason to refuse a read.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.datasetList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"eval","x-public":true,"x-tool":true},"post":{"operationId":"post_eval_datasets","summary":"Writes a dataset — the named set of graded examples a run scores a model against — under the caller's org and answers 201 with it.","description":"Writes a dataset — the named set of graded examples a run scores\na model against — under the caller's org and answers 201 with it.\n\nThe NAME is the key, not an id: posting a name the org already has updates that\ndataset's description and metadata and keeps its original creation time, so this\nis create-or-edit and never a duplicate. Its items are untouched.\n\nRequires a validated principal; 401 without one. The org comes from the\nvalidated owner claim, never from a client X-Org-Id, so a dataset can only ever\nbe written under the caller's own tenant. A description over 64 KiB is 400.","tags":["eval"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.datasetReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.datasetView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"eval","x-public":true,"x-tool":true}},"/v1/eval/datasets/{name}":{"delete":{"operationId":"delete_eval_datasets_by_name","summary":"Removes the named dataset of the caller's org AND all of its examples, in one transaction.","description":"Removes the named dataset of the caller's org AND all of its\nexamples, in one transaction.\n\nThis is not a detach: the examples are gone with the set, so a dataset cannot\nbe resurrected by re-creating the name. A name this org does not have is 404 —\nnever a silent success — and a name belonging to another tenant is the same\n404, because the delete is predicated on the validated org. Requires a\nvalidated principal; 401 without one. Runs and scores already recorded against\nthe dataset are telemetry events and are NOT deleted with it.","tags":["eval"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the dataset the URL names.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"eval","x-public":true,"x-tool":true},"get":{"operationId":"get_eval_datasets_by_name","summary":"Returns one dataset of the caller's org by name, together with its live item count — the one read that answers how big the set actually is.","description":"Returns one dataset of the caller's org by name, together with its\nlive item count — the one read that answers how big the set actually is.\n\nA name this org does not have is 404, which is also what another tenant's\ndataset looks like from here. Requires a validated principal; 401 without one.","tags":["eval"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the dataset the URL names.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.datasetView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"eval","x-public":true,"x-tool":true}},"/v1/eval/datasets/{name}/items":{"get":{"operationId":"get_eval_datasets_by_name_items","summary":"Is the examples in one of your datasets — the set is named in the path, because this collection only exists inside one.","description":"Is the examples in one of your datasets — the set is named in the\npath, because this collection only exists inside one.\n\nArchived examples are included, so the caller sees the whole set rather than\nonly what a run would use. Requires a validated principal; 401 without one, and\nthe read is filtered on the validated org, so naming another tenant's dataset\nreturns nothing rather than its contents.","tags":["eval"],"parameters":[{"name":"name","in":"path","required":true,"description":"Dataset is the set to read, from the path — this collection only exists\ninside one.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned. It defaults to 100 and is capped at 500; a\nnon-positive or unparseable value falls back to the default rather than\nfailing, because a typo about paging is not a reason to refuse a read.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.itemList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"eval","x-public":true,"x-tool":true},"post":{"operationId":"post_eval_datasets_by_name_items","summary":"Writes one graded example — its input, its expected output, free-form metadata and a status — into the dataset named in the path, and answers 201 with it.","description":"Writes one graded example — its input, its expected output,\nfree-form metadata and a status — into the dataset named in the path, and\nanswers 201 with it.\n\nThat dataset MUST already exist for this org: an unknown one is 404, never a\nsilent create. Requires a validated principal; 401 without one.","tags":["eval"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.itemReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.itemView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"eval","x-public":true,"x-tool":true}},"/v1/eval/evaluators":{"get":{"operationId":"get_eval_evaluators","summary":"Is the judges your org has defined, each with its judge model, criteria and the score name it writes under.","description":"Is the judges your org has defined, each with its judge model,\ncriteria and the score name it writes under.\n\nRequires a validated principal; 401 without one, and the listing is filtered on\nthe validated org.","tags":["eval"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned. It defaults to 100 and is capped at 500; a\nnon-positive or unparseable value falls back to the default rather than\nfailing, because a typo about paging is not a reason to refuse a read.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.evaluatorList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"eval","x-public":true,"x-tool":true},"post":{"operationId":"post_eval_evaluators","summary":"Saves a reusable judge for the caller's org — the judge model and the written criteria it grades against — and answers 201 with it.","description":"Saves a reusable judge for the caller's org — the judge model\nand the written criteria it grades against — and answers 201 with it.\n\nLike a dataset, the NAME is the key: re-posting a name edits that judge rather\nthan adding a second one. Requires a validated principal; 401 without one.","tags":["eval"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.evaluatorReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.evaluatorView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"eval","x-public":true,"x-tool":true}},"/v1/eval/metrics":{"get":{"operationId":"get_eval_metrics","summary":"Is your org's AI overview board over a window: totals (generations, prompt and completion tokens, cost in cents, errors, success rate, distinct models and users), a gap-filled time series, a per-model breakdown with the long tail folded into \"other\", and latency percentiles read from the GenAI spans.","description":"Is your org's AI overview board over a window: totals\n(generations, prompt and completion tokens, cost in cents, errors, success\nrate, distinct models and users), a gap-filled time series, a per-model\nbreakdown with the long tail folded into \"other\", and latency percentiles read\nfrom the GenAI spans.\n\nThe window the answer was actually computed over is echoed back, so a client\nnever has to infer it. A platform admin sees the board across ALL orgs;\neveryone else sees their own.\n\nThe board is HONEST-EMPTY where it cannot be computed: with no datastore wired,\nor under a named project scope the usage ledger does not yet carry, it answers a\nvalid board with zero totals and a flat series rather than a fabricated number\nor a 500. Requires a validated principal; 401 without one.","tags":["eval"],"parameters":[{"name":"range","in":"query","required":false,"description":"Range is 24h (the default), 7d or 30d. Anything else normalises to 24h\nrather than failing, so the board always has a valid window.","schema":{"type":"string"}},{"name":"interval","in":"query","required":false,"description":"Interval overrides the bucket the series is grouped into: \"hour\" or \"day\".\nAny other value leaves the range's own default in place.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.Board"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"eval","x-public":true,"x-tool":true}},"/v1/eval/rubrics":{"get":{"operationId":"get_eval_rubrics","summary":"Is the score shapes your org has declared — each name's data type, its numeric bounds and its allowed categories.","description":"Is the score shapes your org has declared — each name's data\ntype, its numeric bounds and its allowed categories.\n\nRequires a validated principal; 401 without one, and the listing is filtered on\nthe validated org.","tags":["eval"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned. It defaults to 100 and is capped at 500; a\nnon-positive or unparseable value falls back to the default rather than\nfailing, because a typo about paging is not a reason to refuse a read.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.scoreConfigList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"eval","x-public":true,"x-tool":true},"post":{"operationId":"post_eval_rubrics","summary":"Defines the shape of one score name for the caller's org and answers 201 with it.","description":"Defines the shape of one score name for the caller's org and\nanswers 201 with it.\n\nThis is the integrity contract, not documentation: once a rubric exists for a\nname, every score recorded under that name is checked against it and the\nrubric's data type is AUTHORITATIVE — a caller cannot claim a different one.\nOut-of-range values, unlisted labels and non-finite numbers are refused at\nwrite time.\n\nA CATEGORICAL rubric with no categories is 400, as is a non-finite bound or a\nminValue above maxValue. Requires a validated principal; 401 without one.","tags":["eval"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.scoreConfigReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.scoreConfigView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"eval","x-public":true,"x-tool":true}},"/v1/eval/runs":{"get":{"operationId":"get_eval_runs","summary":"Is your past runs and how they scored — the dataset and model, the judge model, how many examples were attempted and how many scored, the average score, and when it happened.","description":"Is your past runs and how they scored — the dataset and model, the\njudge model, how many examples were attempted and how many scored, the average\nscore, and when it happened.\n\nRequires a validated principal; 401 without one, and rows are filtered on the\nvalidated org. These records come from the metastore rather than the datastore,\nso they are readable on a deployment with no telemetry wired — but a run's\ntraces and scores are not.","tags":["eval"],"parameters":[{"name":"datasetName","in":"query","required":false,"description":"Dataset narrows to the runs against one dataset.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned. It defaults to 100 and is capped at 500; a\nnon-positive or unparseable value falls back to the default rather than\nfailing, because a typo about paging is not a reason to refuse a read.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.runs"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"eval","x-public":true,"x-tool":true},"post":{"operationId":"post_eval_runs","summary":"Runs a real evaluation and answers the summary when it is finished — this is synchronous work, not a job id.","description":"Runs a real evaluation and answers the summary when it is finished —\nthis is synchronous work, not a job id.\n\nFor each ACTIVE example in the dataset it calls the model under test, records a\ntrace, calls the LLM-as-judge, and records the judge's score with its\nreasoning. The answer carries the per-item results (item id, trace id, score,\noutput or error) alongside items, scored and avgScore.\n\nThe dataset must belong to the caller's org (404 otherwise) and must have at\nleast one ACTIVE example (422 otherwise).\n\nIt runs as YOU: the caller's own Authorization bearer drives the model gateway,\nso a request without one is 401 rather than a run made anonymously or under a\nservice identity. Only a non-reversible hash of that credential is recorded on\nthe traces.\n\nBounded and honest about it: an org may have at most 4 runs in flight and the\nfifth is 429 rather than queued, and the whole run is capped at 10 minutes —\nexamples past the deadline come back with an error instead of a score, and\nscored counts only real successes. A run where NOTHING scored answers 502, not\na 200 that looks like an evaluation. A run must be able to persist what it\nproduces, so a deployment with no datastore wired is 503 up front. Requires a\nvalidated principal; 401 without one.","tags":["eval"],"parameters":[{"name":"Authorization","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.runRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.runSummary"}}},"description":"ok"},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.runSummary"}}},"description":"bad gateway"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"eval","x-public":true,"x-tool":true}},"/v1/eval/scores":{"get":{"operationId":"get_eval_scores","summary":"Is the score events your org has recorded, narrowed by any of name, runName and traceId.","description":"Is the score events your org has recorded, narrowed by any of name,\nrunName and traceId.\n\nThe org is bound as an authoritative predicate on the query, never taken from a\nheader, so a filter can narrow the caller's own scores but can never widen past\nthem. Requires a validated principal; 401 without one. Scores live in the\ndatastore, so a deployment with none wired answers 503 rather than an empty\npage that would read as \"no scores\".","tags":["eval"],"parameters":[{"name":"name","in":"query","required":false,"description":"Name narrows to one score name.","schema":{"type":"string"}},{"name":"runName","in":"query","required":false,"description":"RunName narrows to the scores of one run.","schema":{"type":"string"}},{"name":"traceId","in":"query","required":false,"description":"TraceID narrows to the scores on one model call.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned. It defaults to 100 and is capped at 500; a\nnon-positive or unparseable value falls back to the default rather than\nfailing, because a typo about paging is not a reason to refuse a read.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.scoreList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"eval","x-public":true,"x-tool":true},"post":{"operationId":"post_eval_scores","summary":"Files one score event for the caller's org and answers 201 with it.","description":"Files one score event for the caller's org and answers 201 with it.\n\nThis is how human review and out-of-band graders land beside the automatic\nones: name the score, give it a value (or a stringValue for a categorical\nlabel), and attach it to a trace, a run, a dataset example, or any combination.\n\nScores are validated fail-closed. A value must be FINITE — NaN and Inf are 400\n— and if the org has declared a rubric for this name, that rubric decides the\ntype and the value must satisfy it: inside the numeric bounds, or one of the\nallowed categories. A caller cannot override the declared type by sending a\ndifferent dataType.\n\nA score is TELEMETRY, not metadata, so it needs the datastore: a deployment\nwith none wired answers 503 rather than accepting a score it cannot persist.\nRequires a validated principal; 401 without one, and the org is stamped from\nthe validated claim rather than read off the body.","tags":["eval"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.scoreReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.scoreView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"eval","x-public":true,"x-tool":true}},"/v1/eval/traces":{"get":{"operationId":"get_eval_traces","summary":"Is the traces behind your evaluations — one per model call an evaluation made, carrying its input, output, model and timing — narrowed by any of sessionId, runName and datasetName.","description":"Is the traces behind your evaluations — one per model call an\nevaluation made, carrying its input, output, model and timing — narrowed by any\nof sessionId, runName and datasetName.\n\nScoped by org AND by project: the project is the caller's server-minted scope,\nnot a parameter, so it cannot be widened by asking. Requires a validated\nprincipal; 401 without one. Traces live in the datastore, so a deployment with\nnone wired answers 503 rather than an empty page.","tags":["eval"],"parameters":[{"name":"sessionId","in":"query","required":false,"description":"SessionID narrows to one session, which for an evaluation is one run.","schema":{"type":"string"}},{"name":"runName","in":"query","required":false,"description":"RunName narrows to the calls one run made.","schema":{"type":"string"}},{"name":"datasetName","in":"query","required":false,"description":"Dataset narrows to the calls made against one dataset.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned. It defaults to 100 and is capped at 500; a\nnon-positive or unparseable value falls back to the default rather than\nfailing, because a typo about paging is not a reason to refuse a read.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/eval.traceList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"eval","x-public":true,"x-tool":true}},"/v1/event":{"post":{"operationId":"post_event","summary":"Capture product events into your org's warehouse","description":"Stores pageviews, browser errors, identifies and custom commerce events as rows in the caller's own tenant, and answers a receipt {accepted, dropped} that always totals what was sent — a beacon is never silently discarded.\n\nTHE STATUS SAYS WHETHER ANYTHING LANDED, so a green check can never mean an empty warehouse. 200 means at least one event was stored (or that nothing was sent), and a nonzero `dropped` beside a nonzero `accepted` is a PARTIAL batch, never a failed one — a batch is not refused whole for its worst element. If NOTHING was stored the request is an error, and it names the one thing that fixes it: 401 `ingest_key_required` when every event was refused for want of a credential (the same events land with a key), and 400 `unroutable_events` when the caller HAD capability and the body still named nothing storable.\n\nONE endpoint for every wire a Hanzo surface emits, dispatched by the SHAPE of the body and never by a second path: a bare event object, a bare array of them, the {batch:[…]} / {events:[…]} envelope, the team console's snake_case array, and the PostHog wire (spelled `distinct_id`/`api_key`, which the canonical wire never uses). BATCH IS A BODY, NOT A PATH — there is no /v1/event/batch, because an array already is one.\n\nWHAT THE CALLER PRESENTS DECIDES WHAT IT MAY WRITE, and the endpoint itself grants nothing. A validated bearer or an org API key writes the full event at full fidelity. A PUBLISHABLE key (pk-, on Authorization: Bearer, x-hanzo-ingest-key, or ?ingest_key= for navigator.sendBeacon, which cannot set headers) does the same, and is the credential a browser bundle ships: it is deliberately NOT a secret, it resolves WHICH tenant a beacon belongs to and nothing more. A pk- never authenticates and can READ NOTHING — not this org's errors, not a lens, not any other route on this API — so a leaked one lets a stranger write into your stream, and never lets one read out of it. Reading these rows back always takes a real bearer. A Hanzo Team space token resolves its org at REDUCED capability: the signed account names the person, so a `distinctId` in the body cannot pin events on a colleague.\n\nNO CREDENTIAL IS REFUSED: a write the server cannot attribute to a project is 401 `ingest_key_required`, and a credential that IS presented but resolves to no project is 403 `ingest_key_unknown`. Nothing is filed under a shared tenant — events nobody can read are worse than events nobody sent, because the caller is told it succeeded. A browser bundle therefore always ships a pk-, which is what /v1/event/tag.js takes.\n\nTHE STREAM IS FIRST PARTY. Every visitor's events are kept — page views, events, errors, identifies and the anonymous id — whatever they chose and under Global Privacy Control or Do Not Track alike: it is the org's own analytics, never sold or shared. Consent governs the third parties alone. Each event states the categories its visitor allowed in its `consent` property (`analytics,marketing,ads`), and that is all it may be forwarded under: Google Analytics needs analytics, the Meta pixel marketing, ad personalization ads. GPC or DNT on the request forwards nothing in any region (`consent_mode`: eu, us_privacy or global, from the country and US state the edge attests), whatever the event stated, and is stamped `refused`.\n\nA REDUCED principal — a Hanzo Team space token — writes through the PROJECTION into its own org: narrowed to what the SERVER can name (pageviews and errors, plus the closed autocapture vocabulary $click, $input, $change, $submit, $view), where every one of those names is resolved through a server-owned table and stored as that table's value, so the name on the wire is never the name in the row. Stripped, too, to the fields the projection names, so revenue, personId, groupId and every property but the element annotation cannot reach a row — and an exception is carried only on an error, never on an interaction, so a click cannot ship a stack trace into a row's attributes. It does NOT name the person: the signed account is the identity, so a `distinctId` in the body cannot pin events on a colleague. Everything refused is counted in `dropped`.\n\nThe projected lane alone is bounded: 413 over 64 KiB, 400 over 50 events, 429 on the per-client-IP and per-peer caps. Two stored values carry their own bounds on top, because a request cap does not bound one value: an element annotation over 2 KiB (or a trail over 32 steps) and an exception class over 256 bytes are dropped from the row, which still lands. Authenticated bodies are offered to the observability plane first, which claims LLM-observability ingestion batches and declines everything else.","tags":["event"],"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/CaptureEvent"},{"items":{"$ref":"#/components/schemas/CaptureEvent"},"type":"array"},{"$ref":"#/components/schemas/CaptureBatch"},{"$ref":"#/components/schemas/insightsBody"}]}}}},"responses":{"2XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaptureResult"}}},"description":"Success"}},"x-app":"event","x-public":true}},"/v1/event/economic":{"get":{"operationId":"get_event_economic","summary":"Returns, oldest first and paged, the payments the caller's org made or received in a year, with the ones a correction restates named and what either party disputes — for the org's admins.","description":"Returns, oldest first and paged, the payments the caller's org made or received in\na year, with the ones a correction restates named and what either party disputes\n— for the org's admins.","tags":["event"],"parameters":[{"name":"year","in":"query","required":true,"description":"Year is the calendar year to read, UTC.","schema":{"format":"int64","type":"integer"},"example":2026},{"name":"counterparty","in":"query","required":false,"description":"Counterparty keeps only payments with this org on the other side.","schema":{"type":"string"}},{"name":"rail","in":"query","required":false,"description":"Rail keeps only payments that moved on this rail.","schema":{"type":"string"},"example":"x402"},{"name":"cursor","in":"query","required":false,"description":"Cursor continues from the next of the page before; empty starts the year.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit is how many events to answer, default 100 and at most 1000.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/event.Economics"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"event","x-public":true,"x-tool":true}},"/v1/event/economic/dispute":{"post":{"operationId":"post_event_economic_dispute","summary":"Records that the caller's org disputes one payment it is party to — for the org's admins.","description":"Records that the caller's org disputes one payment it is party to — for the org's\nadmins. A dispute is a record both parties read beside the payment, and it changes\nnothing about it: the amount, the parties and the tax year stay as the rail stated\nthem, because only the rail that moved the money restates a payment.","tags":["event"],"requestBody":{"content":{"application/json":{"example":{"event":"econ_4f1c…","reason":"the service was never delivered"},"schema":{"$ref":"#/components/schemas/event.disputeIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/event.EconomicDispute"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"event","x-public":true,"x-tool":true}},"/v1/event/errors":{"get":{"operationId":"get_event_errors","summary":"Returns the caller org's most recently captured errors, newest first.","description":"Returns the caller org's most recently captured errors, newest first. The\nerror-tracking read view over event.error — the plane table the write core's error\nfacts land in (errors are DELIBERATELY not on event.event) — each with its captured\nexception surfaced from the attributes map as a first-class field.\n\nThe org is the validated principal's — never a parameter — and this read requires a\nreal bearer, NEVER the write-only publishable key: pk- can attribute a write and can\nread nothing. 401 without a validated bearer, 503 when the warehouse is unreachable.","tags":["event"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit is how many rows to return, newest first. Default 50, maximum 200; a\nvalue at or below zero, or one that is not a number, takes the default.","schema":{"format":"int64","type":"integer"},"example":100}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/event.errorList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"event","x-public":true,"x-tool":true}},"/v1/event/health":{"get":{"operationId":"get_event_health","summary":"Reports whether the event plane can take a write and the warehouse can answer a read.","description":"Reports whether the event plane can take a write and the warehouse can\nanswer a read.\n\nIt reports the analytics subsystem's own liveness in BOTH directions: plane is\nthe event plane it WRITES (the bus and the JetStream stream every accepted\nevent is published to, both named in the report), and datastore is the\nwarehouse it READS, with each read lens's table reported as it is provisioned\n(the LLM usage ledger and the product-event table).\n\nEITHER ONE DOWN IS A 503, and the report says WHICH — they are probed\nindependently and never collapse into a single bit. A readiness gate on this\nendpoint therefore gates on the write path as well as the read path: it\nanswers ready only when POST /v1/event can publish.\n\nplane.ready IS A REAL PROBE and walks the ingest path itself — the same\nconnection and the same stream a publish uses — so it cannot answer ready while\na publish would 503. plane.reason carries the plane's own error text when it is\nfalse.\n\ndatastore IS NOT PROBED WITH A QUERY. It is the state of the process's own\nshared client — established, and not since closed — so a warehouse accepting\nconnections and failing reads still reports true. Degraded CARRIES the report\n(status, the failing half, reason) as its body rather than an error envelope,\nso a gate reads the cause off the same object it got at 200.\n\nA MISSING LENS TABLE IS NOT A FAILURE and never moves the status: a lens\nreported available:false answers honest-empty rather than erroring, so a fresh\ndeployment whose collector has not emitted yet is legitimately 200 with the\nproduct-event lens unavailable. The lens block is reported whenever the\nwarehouse is REACHABLE — including on a report degraded by the plane, where the\ntables genuinely were probed — and is absent only when the warehouse is not,\nhaving nothing to say about tables it could not reach.\n\nUnauthenticated on purpose — liveness has to be probe-able — and it reads NO\ntenant data: table existence and stream presence only, never a row and never an\nevent.","tags":["event"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/event.healthReport"}}},"description":"ok"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/event.healthReport"}}},"description":"service unavailable"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"event","x-public":true,"x-tool":true}},"/v1/event/insights/events":{"get":{"operationId":"get_event_insights_events","summary":"Returns the caller org's most recent product events, newest first.","description":"Returns the caller org's most recent product events, newest first.\nThe console's raw-event view over event.event — the same table the capture endpoints\nfill — one row per stored event, with the row's attributes returned as the\nproperties object.\n\nWhat a platform operator did acting as someone else is left out unless impersonated\nasks for it; such a row carries impersonated and impersonated_by in its properties.\n\nThe org is the validated principal's — never a parameter — and a read requires a\nreal bearer, never the write-only publishable key. 401 without a validated bearer,\n400 on an unknown impersonated value, 503 when the warehouse is unreachable.","tags":["event"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit is how many rows to return, newest first. Default 50, maximum 200; a\nvalue at or below zero, or one that is not a number, takes the default.","schema":{"format":"int64","type":"integer"},"example":100},{"name":"impersonated","in":"query","required":false,"description":"Impersonated is which events to return against the mark a platform operator\nleaves acting as someone else: exclude (the default, the tenant's own\ntraffic), include, or only. Anything else is a 400.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/event.eventList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"event","x-public":true,"x-tool":true}},"/v1/event/insights/health":{"get":{"operationId":"get_event_insights_health","summary":"Reports that the unified insights surface is serving.","description":"Reports that the unified insights surface is serving. It reads no\ntenant data and consults no dependency, so it answers 200 unconditionally and needs\nno principal — liveness must be probe-able. The warehouse-connectivity probe is a\ndifferent question and lives at GET /v1/event/health.","tags":["event"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/event.insightsStatus"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"event","x-public":true,"x-tool":true}},"/v1/event/overview":{"get":{"operationId":"get_event_overview","summary":"Returns the caller org's analytics KPIs for one time window.","description":"Returns the caller org's analytics KPIs for one time window. Three lenses\nover one warehouse: llm is the live per-org LLM usage ledger (requests, tokens,\nspend, models, providers, errors) and is always real; web (pageviews, visitors,\nsessions) and commerce (orders, revenue, AOV) read the product-event table and\nreport available=false rather than fabricating zeros when it holds nothing yet.\n\nThe web and commerce lenses count the tenant's own traffic: what a platform\noperator did while acting as someone else is left out unless impersonated asks for\nit (include, or only). The LLM lens reads the usage ledger, which carries no such\nmark, and counts every call.\n\nThe org is the validated principal's — never a parameter — so a caller can only\never read its own tenant. 401 without a validated bearer, 400 on an unknown range\nor impersonated value, 503 when the warehouse is unreachable.","tags":["event"],"parameters":[{"name":"range","in":"query","required":false,"description":"Range is a relative window: a count and a unit — 24h, 7d, 90d, any \u003cN\u003eh or\n\u003cN\u003ed — or day, week, month, all. Default 24h. Ignored when both start and\nend are given. An unknown value, or one past the 730-day horizon, is a 400.","schema":{"type":"string"},"example":"7d"},{"name":"start","in":"query","required":false,"description":"Start is the inclusive lower bound of a custom window, RFC3339. Requires end.","schema":{"type":"string"}},{"name":"end","in":"query","required":false,"description":"End is the exclusive upper bound of a custom window, RFC3339. Requires start.","schema":{"type":"string"}},{"name":"impersonated","in":"query","required":false,"description":"Impersonated is which events the product-event lenses count against the mark\na platform operator leaves acting as someone else: exclude (the default, the\ntenant's own traffic), include, or only. Anything else is a 400.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/event.Overview"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"event","x-public":true,"x-tool":true}},"/v1/event/pixel/{key}":{"get":{"operationId":"get_event_pixel_by_key","summary":"A site's default pixel — a page view from an image, for a page that runs no script","description":"Answers a transparent 1x1 GIF and records one page view for the project whose publishable key names the address:\n\n    \u003cimg src=\"https://api.hanzo.ai/v1/event/pixel/pk-….gif\" alt=\"\" width=\"1\" height=\"1\"\u003e\n\nThe page is `?u=` when given, else the Referer. The visitor is stamped from the request like every event, is one visitor for a day, and carries no cookie. Every view is recorded: it is the site's own first-party analytics. `?consent=analytics`, the visitor's choice as the embedding page knows it, is what it may be forwarded to Google Analytics under; Do-not-track and Global Privacy Control forward nothing, and a developer's own machine records nothing. The image is answered whatever happened to the view, with no-store.","tags":["event"],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"2XX":{"content":{"image/gif":{"schema":{"format":"binary","type":"string"}}},"description":"Success"}},"x-app":"event","x-public":true}},"/v1/event/replay":{"post":{"operationId":"post_event_replay","summary":"Record a session-replay snapshot batch","description":"Accepts a batch of rrweb events from a browser recorder and hands it to the session-replay pipeline, which stores the recording and derives the session summary a player reads back.\n\nONE REQUEST IS ONE BATCH, and it is all-or-nothing: the recording is made durable before this answers, so a 200 {\"accepted\":1} means stored and never \"buffered somewhere\". There is no partial count, because a half-written recording is not a recording.\n\n`sessionId` is REQUIRED and bounded — at most 70 characters of ASCII letters, digits or '-'. It is the key every batch of one visit is grouped and ordered by, so an id outside that grammar is refused 400 here rather than accepted and dropped further down. `windowId` separates two tabs of one session and `distinctId` attributes the recording to a person; both are optional. `events` is the rrweb batch, each element a raw eventWithTime object, carried VERBATIM — the summary (click, keypress and mouse-activity counts, size) is derived downstream from exactly these bytes, so nothing is re-encoded or dropped.\n\nTHE CALLER'S CREDENTIAL DECIDES THE TENANT, and the body never does: the recording lands in the org the presented credential resolves to. It takes the SAME credentials as /v1/event — a validated bearer, an org API key, or a publishable pk- key on Authorization: Bearer, x-hanzo-ingest-key or ?ingest_key= — so a browser bundle already holding a pk- for events needs nothing new to record. A caller that presents nothing is 401 `ingest_key_required`; one whose key resolves to no project is 403 `ingest_key_unknown`; a reduced principal (a Hanzo Team space token) is 403 `insufficient_capability`, because a full-fidelity screen recording has no projected form that is safe for a guest to write into a host org.\n\nBOUNDS: 413 over 512 KiB of body, and that is the only bound on one batch — a recorder is expected to chunk a long session rather than send it whole, and the cap is the size one message can carry rather than an arbitrary number. 503 when the pipeline cannot take the batch: honest unavailability the caller can retry, never a 200 over a discarded recording.","tags":["event"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/replayBody"}}}},"responses":{"2XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaptureResult"}}},"description":"Success"}},"x-app":"event","x-public":true}},"/v1/event/tag.js":{"get":{"operationId":"get_event_tag.js","summary":"The Hanzo event tag — the one-line install for a surface with no bundler","description":"Serves the browser tag that autocaptures pageviews (initial and SPA) and uncaught errors onto the canonical wire at POST /v1/event.\n\nInstall is one line, and it is the same line for a Hanzo property and for a customer's own page:\n\n    \u003cscript defer src=\"https://api.hanzo.ai/v1/event/tag.js\" data-key=\"pk-…\"\u003e\u003c/script\u003e\n\n`data-key` is the publishable key the project mints; `data-product` optionally names the emitting surface. The key may also ride the src as `?key=` for a host that strips data attributes.\n\nTHE STREAM IS FIRST PARTY; THE THIRD PARTIES FOLLOW THE VISITOR'S REGION. Every page view, event, error and identify goes to the site's own stream for every visitor, under its anonymous id and session, whatever they chose and under Global Privacy Control or Do Not Track alike: it is the site's own analytics, never sold or shared. The rule for Google Analytics, the Meta pixel and the other platforms is the one GET /v1/project/tags serves for the visitor's region. `eu` (the EU, the EEA, the UK, Switzerland, and any visitor no edge placed): Google Analytics runs for everyone under Consent Mode v2 with all four flags denied (cookieless) and is upgraded by Performance and Targeted Advertising; Meta is init'ed after `fbq('consent','revoke')` and sends nothing until Marketing; no other platform loads before a choice. `us_privacy` (a US state with a privacy law, or no attested state) and `global`: everything runs at once under Consent Mode granted, and Targeted Advertising off is exactly `fbq('dataProcessingOptions',['LDU'],0,0)` and ad_storage, ad_user_data and ad_personalization denied. Under GPC or DNT no third party loads in any region, Google Analytics included. The choice is the `__Host-hz_consent` cookie, written by the @hanzo/ui consent banner or this tag's own, beside the version and the rule it was made under: `eu` counts only a choice made under `eu`, and the policy floor voids a choice's grants, never its refusals. Each event states the grants in force when it is sent, and that is what cloud may forward under.\n\n`data-banner` draws Hanzo's consent design by region. In `eu`, for a visitor who has not chosen and whose browser has not refused: a card with Manage preferences, Accept all and a × that keeps essential cookies only, so refusing is as easy as accepting. In `global`, a notice (\"We use cookies to improve your experience. By continuing to browse, you agree.\") until the visitor closes it with ×. In `us_privacy`, no card: a \"Your Privacy Choices\" link with the opt-out icon at the foot of the page, unless the page carries its own (an element marked `data-hz-consent-link`). Manage preferences or the link opens the sheet — Strictly Necessary Cookies (always active, the site's own first-party analytics included), Performance (Google Analytics), Marketing (the Meta pixel), and Sell, Share, or Use Your Data for Targeted Advertising, each chosen apart; outside `eu` each is on by default and Targeted Advertising off is the opt-out. Withdrawing a category clears the third-party cookies it allowed, on every domain above the page, and never an essential one. The sheet links only the policies the page names: `data-cookies` its cookie policy, `data-banner`'s value its privacy policy, `data-terms` its terms. `window.hzConsent.open()` opens the sheet again from a page's own link.\n\nWITHOUT A KEY THE TAG SENDS NOTHING. A keyless beacon is accepted 200 into $public, a reserved tenant the owning org cannot read — so silence is the honest failure, and the tag picks it rather than reporting success into a tenant nobody reads.","tags":["event"],"responses":{"2XX":{"content":{"application/javascript":{"schema":{"format":"binary","type":"string"}}},"description":"Success"}},"x-app":"event","x-public":true}},"/v1/event/timeseries":{"get":{"operationId":"get_event_timeseries","summary":"Returns the caller org's LLM usage over time as an evenly-spaced series.","description":"Returns the caller org's LLM usage over time as an evenly-spaced series.\nOne point per hour or per day — the bucket the window implies, 24h giving hours and\n7d/30d giving days — carrying requests, total tokens and spend in cents. Empty\nbuckets are filled with zeros so a client charts a continuous line.\n\nThe org is the validated principal's — never a parameter. 401 without a validated\nbearer, 400 on an unknown range, 503 when the warehouse is unreachable.","tags":["event"],"parameters":[{"name":"range","in":"query","required":false,"description":"Range is a relative window: a count and a unit — 24h, 7d, 90d, any \u003cN\u003eh or\n\u003cN\u003ed — or day, week, month, all. Default 24h. Ignored when both start and\nend are given. An unknown value, or one past the 730-day horizon, is a 400.","schema":{"type":"string"},"example":"30d"},{"name":"start","in":"query","required":false,"description":"Start is the inclusive lower bound of a custom window, RFC3339. Requires end.","schema":{"type":"string"}},{"name":"end","in":"query","required":false,"description":"End is the exclusive upper bound of a custom window, RFC3339. Requires start.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/event.Timeseries"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"event","x-public":true,"x-tool":true}},"/v1/event/top":{"get":{"operationId":"get_event_top","summary":"Returns the caller org's ranked lenses for one window, five of them at once.","description":"Returns the caller org's ranked lenses for one window, five of them at once.\nmodels ranks LLM models by spend and is always real; products ranks commerce orders\nby revenue; topPages ranks requested paths, topReferrers the external referrer\ndomains (\"(direct)\" for a missing or same-origin one) and topSources the utm_source\ncampaigns (\"(none)\" when absent), each by pageviews. Every lens carries each row's\nshare of the in-window total, so a top-N honestly shows the long tail.\n\nThe four event lenses report available=false rather than fabricating zeros when the\nproduct-event table holds nothing yet, and count the tenant's own traffic: what a\nplatform operator did acting as someone else is left out unless impersonated asks\nfor it (include, or only). Models reads the usage ledger, which carries no such\nmark. The org is the validated principal's — never a parameter. 401 without a\nvalidated bearer, 400 on an unknown range or impersonated value, 503 when the\nwarehouse is unreachable.","tags":["event"],"parameters":[{"name":"range","in":"query","required":false,"description":"Range is a relative window: a count and a unit — 24h, 7d, 90d, any \u003cN\u003eh or\n\u003cN\u003ed — or day, week, month, all. Default 24h. Ignored when both start and\nend are given. An unknown value, or one past the 730-day horizon, is a 400.","schema":{"type":"string"},"example":"7d"},{"name":"start","in":"query","required":false,"description":"Start is the inclusive lower bound of a custom window, RFC3339. Requires end.","schema":{"type":"string"}},{"name":"end","in":"query","required":false,"description":"End is the exclusive upper bound of a custom window, RFC3339. Requires start.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit bounds every ranked lens in the response. Default 10, maximum 100; a\nvalue at or below zero, or one that is not a number, takes the default.","schema":{"format":"int64","type":"integer"},"example":25},{"name":"impersonated","in":"query","required":false,"description":"Impersonated is which events the product-event lenses count against the mark\na platform operator leaves acting as someone else: exclude (the default, the\ntenant's own traffic), include, or only. Anything else is a 400.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/event.Top"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"event","x-public":true,"x-tool":true}},"/v1/exec":{"post":{"operationId":"post_exec","summary":"Run a code snippet in a sandboxed interpreter","description":"Executes a program in a throwaway sandbox and answers with what it printed\nand what it left behind.\n\n`lang` names one of the thirteen the sandbox image carries — py, js, ts, bash, r,\nphp, go, rs, c, cpp, java, d, f90 — and `code` is the whole program, not a\nfragment: a compiled language is compiled and then run, an interpreted one is\ninterpreted, and `args` becomes the program's own argv either way. Nothing is\ninstalled for you; the image is the environment.\n\nA PROGRAM THAT FAILS IS A SUCCESSFUL CALL. A non-zero exit answers 200 with the\ndiagnostics on `stderr`, because \"the code threw\" and \"the interpreter is down\"\nare different facts a caller renders differently. Only the second is an error\nstatus.\n\nRuns are stateful through `session_id`. Omit it and the run gets a fresh sandbox\nwhose id comes back on the answer; pass that id again and the next run sees the\nsame filesystem, so a program can write a file one call and read it the next.\n`files` names bytes already uploaded to a session (POST /v1/exec/upload), copied in\nbefore the program starts. `files` on the ANSWER is what the program created or\nchanged, by comparison against a marker taken at start — so it is the run's real\noutput, not a listing of the directory — and each is fetched from\nGET /v1/exec/download/{session}/{name}.\n\nThe tenant is the caller's, never the body's, at every entry point. A typed op is\nalso an MCP tool and an op-plane op; MCP's tools/call invokes it directly, with no\nroute and therefore no middleware, so nothing there could have checked a\ncredential. tenantOf refuses a context carrying no validated principal, so those\nentry points fail closed without a second gate to keep in step.","tags":["exec"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/exec.CodeRun"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/exec.CodeResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"exec","x-public":true,"x-tool":true}},"/v1/exec/files/{sid}":{"get":{"operationId":"get_exec_files_by_sid","summary":"Lists the files in an execution session.","description":"Lists the files in an execution session.\n\nEverything the session's sandbox holds — the uploads a run can read and the\nartifacts it produced — each then fetched from GET /v1/exec/download.\n\nThe answer is a BARE JSON ARRAY of {name, lastModified}, where `name` is the\nsame {session_id}/{fileId} identifier download takes, because that is what the\nclient matches on. The obvious typed shape, `{files: […]}`, would have been a\nsilent wire change: the request still succeeds and `response.data.find(...)`\nfinds nothing, which reads as a session holding no files.\n\nIt lists with one recursive `find`, the same traversal the artifact sweep\nmakes, so a nested artifact a run reports in its reply is listed here too: one\ntraversal of the directory, one answer about what a session holds.","tags":["exec"],"parameters":[{"name":"sid","in":"path","required":true,"description":"SID is the session identifier — the sandbox this listing is of. The URL is\nthe addressing authority: a path segment binds after the body and after the\nquery, so the address decides which session is read whatever else is sent.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/exec.listing"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"exec","x-public":true,"x-tool":true}},"/v1/exec/upload":{"post":{"operationId":"post_exec_upload","summary":"Upload a file into an execution session","description":"Takes a multipart upload and writes the file into the session's sandbox, so a later run can read it. Answers the session id and the identifier the file is addressed by; `session_id` in the form joins an existing session instead of opening one.\n\nThe body is multipart/form-data, which is why this is not a typed operation: every non-empty typed body is decoded as JSON.","tags":["exec"],"x-app":"exec","x-public":true}},"/v1/experiment":{"get":{"operationId":"get_experiment","summary":"Is every experiment in the caller's org, with its variants, status and decision, ordered by project then id.","description":"Is every experiment in the caller's org, with its variants, status and\ndecision, ordered by project then id.\n\nScoped to the org resolved from the validated principal — a distinct org is a\ndistinct physical store, so no query here can reach another tenant's rows — and\nfurther narrowed to the caller's project scope when the credential carries one.\nA principal with NO project scope sees the org's experiments across all of its\nprojects, which is the answer a reader most often expects to be filtered and is\nnot.\n\nRequires a validated principal; refuses without one rather than answering an\nempty list.","tags":["experiment"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/experiment.experimentList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"experiment","x-public":true,"x-tool":true},"post":{"operationId":"post_experiment","summary":"Registers a controlled experiment AND puts its assignment flag live, in that order, so the arms start bucketing subjects the moment this returns 201 — the flag is created active at 100% rollout, with each variant weighted as declared.","description":"Registers a controlled experiment AND puts its assignment flag live, in\nthat order, so the arms start bucketing subjects the moment this returns 201 —\nthe flag is created active at 100% rollout, with each variant weighted as\ndeclared. There is no separate start call; creating IS starting.\n\nA variant carries an opaque payload this primitive never interprets: a feature\nconfig, an ad-creative id, a subject line, a model id.\n\nRequires a validated principal, and refuses without one. The org and project are\ntaken from that principal and the creator is stamped from the credential — none\nof the three is a body field, so an experiment cannot be filed against another\ntenant. An id already used in this project is a conflict, never a silent\noverwrite: re-creating would stomp the assignment flag of a run in progress.\n\nIt fails closed on the flag write. An experiment whose assignment flag does not\nexist would assign nobody, so if that write fails nothing is registered.","tags":["experiment"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/experiment.createBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/experiment.Trial"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"experiment","x-public":true,"x-tool":true}},"/v1/experiment/health":{"get":{"operationId":"get_experiment_health","summary":"Is whether the experiments subsystem is mounted and serving in this process.","description":"Is whether the experiments subsystem is mounted and serving in this\nprocess.\n\nIt answers unconditionally. It proves exactly one thing — that this binary\nregistered the experiments routes and is dispatching them — and deliberately no\nmore: it reads no principal, opens no per-org registry, and touches neither the\nflags engine nor the analytics plane, so a 200 here says nothing about whether a\ngiven tenant's store will open or whether an analysis can run. It is the only\nroute on this surface that needs no org.\n\nThe static path is registered ahead of the /:id read, so it always wins the\nfirst-match scan. \"health\" is a legal experiment id, which means an experiment\ncreated under that id can never be fetched by id — pick another.","tags":["experiment"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/experiment.health"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"experiment","x-public":true,"x-tool":true}},"/v1/experiment/{id}":{"get":{"operationId":"get_experiment_by_id","summary":"Is one experiment's definition and lifecycle: variants, weights, control arm, status and winner.","description":"Is one experiment's definition and lifecycle: variants, weights, control\narm, status and winner.\n\nIt reads the registry row only — the definition and the decision, never live\nmeasurements. Assignment lives in the flags plane and outcomes in analytics;\nthis is the value that names both.\n\nScoped to the caller's org and project from the validated principal, so another\ntenant's experiment of the same id is simply not found. An id that is not a\nlegal slug is answered the same way, without a store read — the shape check and\nthe existence check are one answer, so neither leaks the other.","tags":["experiment"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the experiment the URL names.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/experiment.Trial"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"experiment","x-public":true,"x-tool":true}},"/v1/experiment/{id}/analyze":{"post":{"operationId":"post_experiment_by_id_analyze","summary":"Is per-variant conversion, lift and statistical significance against the control arm.","description":"Is per-variant conversion, lift and statistical significance against\nthe control arm.\n\nIt reads per-subject outcomes from the analytics plane over a window, folds them\ninto per-variant samples, and returns each arm's exposed count, conversions,\nrate, lift versus control, two-proportion z, two-tailed p-value and whether it\nclears alpha. Arms with no data still appear with zero exposed, so the read is\ncomplete over the experiment's declared arms; the control arm sorts first. The\npooled-variance estimator is used and the p-value is exact; a degenerate\ncomparison (an empty arm, no variance) answers z 0 and p 1 — not significant,\nnever an error.\n\nOnly EXPOSED subjects are counted, and each is joined to its arm by re-evaluating\nthe assignment flag AT ANALYSIS TIME — not from what was in force during the\nwindow. That is the one rule to get right: analyzing an experiment after its\nwinner has been promoted re-buckets every subject into the promoted arm,\ncollapsing the control to zero exposed and making the result meaningless. Read\nthe analysis before deciding. A subject the flag cannot place is dropped rather\nthan allowed to poison the fold.\n\nThe winner in the response is ADVISORY — the significant, control-beating arm\nwith the highest rate, or empty when inconclusive. It promotes nothing; the\ndecision is a separate, explicit act.\n\nEvery plane read is scoped to the caller's org. Per-variant samples are also\nwritten to the research evidence plane as immutable ab rows, best-effort: the\nanalysis is still returned if that write fails, because the samples are\nrecomputable, and the failure is logged rather than swallowed.","tags":["experiment"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the experiment the URL names.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/experiment.analyzeQuery"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/experiment.Analysis"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"experiment","x-public":true,"x-tool":true}},"/v1/experiment/{id}/assign":{"get":{"operationId":"get_experiment_by_id_assign","summary":"Is the variant one subject is bucketed into, and the payload that variant carries.","description":"Is the variant one subject is bucketed into, and the payload that\nvariant carries.\n\nThe bucketing is a deterministic hash of the subject, so the same subject gets\nthe same arm on every call for as long as the flag definition is unchanged —\nand this is a pure READ: it records nothing. In particular it does NOT record an\nexposure. The caller's SDK must emit the experiment's exposure event itself, or\nthe analysis has an empty denominator and every arm measures zero.\n\nAn empty variant with on false is not an error — it means the flag returned\nnothing for this subject, so the subject is not enrolled. A flags engine that is\nunavailable refuses rather than defaulting to an arm. Requires a validated\nprincipal, and the experiment must exist in the caller's org and project.","tags":["experiment"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the experiment the URL names.","schema":{"type":"string"}},{"name":"subject","in":"query","required":true,"description":"Subject is the unit to bucket — a user, org, session or audience key,\nmatching the experiment's subjectKind.","schema":{"type":"string"}},{"name":"props","in":"query","required":false,"description":"Props is a JSON object of person properties for targeting. A value that is\nnot valid JSON is dropped rather than refused, so a malformed one changes\nthe bucketing without saying so.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/experiment.assignment"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"experiment","x-public":true,"x-tool":true}},"/v1/experiment/{id}/decide":{"post":{"operationId":"post_experiment_by_id_decide","summary":"Promotes one variant to the whole rollout and records who decided.","description":"Promotes one variant to the whole rollout and records who decided.\n\nIt rewrites the assignment flag so the named winner serves 100% of the rollout\nand every other arm 0%, preserving the flag's targeting groups and payloads,\nthen stamps the experiment decided with the winner, the deciding credential and\nthe time. This is a production behaviour change that takes effect immediately\nfor every subject the flag evaluates.\n\nIt requires an ORG ADMIN of the caller's own org — a stricter gate than the rest\nof this surface, matching the flags write plane, because promoting is a flag\nwrite. The admin check runs AFTER the experiment is found, so a caller from\nanother tenant is answered not-found rather than forbidden and learns nothing\nabout what exists.\n\nAn experiment whose assignment flag has gone missing is a conflict rather than a\nsilent no-op — there is nothing to promote.\n\nDeciding is NOT terminal. A second call re-promotes a different variant and\nre-stamps the row; the status stays decided and the previous winner is\noverwritten with no record that it was ever chosen. Nothing here reverts the\nflag to its original weights either, so an experiment cannot be un-decided\nthrough this route — restoring a split means writing the flag definition back\nthrough the flags plane.","tags":["experiment"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/experiment.decideBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/experiment.Trial"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"experiment","x-public":true,"x-tool":true}},"/v1/explorer/indexers":{"get":{"operationId":"get_explorer_indexers","summary":"Reports the deployment's chain indexer(s) and how far each has indexed.","description":"Reports the deployment's chain indexer(s) and how far each has\nindexed. Identity and health come from the indexer's /health; the latest indexed\nblock (height + time) from its /v1/explorer/blocks. The row EXISTS if EITHER call\nreaches the indexer; when the indexer is entirely unreachable the answer degrades\nto an honest-EMPTY list at 200, not a 502. No chain HEAD is exposed by the indexer\nREST, so `lag` is honestly omitted rather than fabricated.","tags":["explorer"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/explorer.indexersOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"explorer","x-public":true,"x-tool":true}},"/v1/explorer/oracles":{"get":{"operationId":"get_explorer_oracles","summary":"Reports the on-chain price/data oracles from the graph's O-Chain PriceFeed registry.","description":"Reports the on-chain price/data oracles from the graph's O-Chain\nPriceFeed registry. A reachable graph with no feeds answers an honest empty list;\nan unreachable or erroring graph likewise degrades to an empty list at 200 rather\nthan a 502, so the console never error-toasts. No feed is ever fabricated.","tags":["explorer"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/explorer.oraclesOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"explorer","x-public":true,"x-tool":true}},"/v1/flag":{"post":{"operationId":"post_flag","summary":"Runs the caller's flag definitions for one identity and returns the flag verdict: which flags are on (or which variant), their payloads, and whether any definition failed to compute.","description":"Runs the caller's flag definitions for one identity and returns the\nflag verdict: which flags are on (or which variant), their payloads,\nand whether any definition failed to compute. Evaluation is in-process over the\ncaller's own (org, project) definitions — no network hop, no shared KV — so a\ntenant can only ever evaluate its own flags.","tags":["flag"],"requestBody":{"content":{"application/json":{"example":{"distinct_id":"u1","groups":{"0":{"key":"acme"}},"person_properties":{"plan":"pro"}},"schema":{"$ref":"#/components/schemas/flag.evaluateIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"errorsWhileComputingFlags":false,"featureFlagPayloads":{},"featureFlags":{"new-editor":true}},"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flag","x-public":true,"x-tool":true}},"/v1/flag/activity":{"get":{"operationId":"get_flag_activity","summary":"Returns the caller's flag change log newest-first: every create, update and delete, with the actor and the time.","description":"Returns the caller's flag change log newest-first: every\ncreate, update and delete, with the actor and the time.","tags":["flag"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned. 1–500; anything else takes the default 100.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/flag.activityOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flag","x-public":true,"x-tool":true}},"/v1/flag/decide":{"post":{"operationId":"post_flag_decide","summary":"Runs the caller's flag definitions for one identity and returns the flag verdict: which flags are on (or which variant), their payloads, and whether any definition failed to compute.","description":"Runs the caller's flag definitions for one identity and returns the\nflag verdict: which flags are on (or which variant), their payloads,\nand whether any definition failed to compute. Evaluation is in-process over the\ncaller's own (org, project) definitions — no network hop, no shared KV — so a\ntenant can only ever evaluate its own flags.","tags":["flag"],"requestBody":{"content":{"application/json":{"example":{"distinct_id":"u1","groups":{"0":{"key":"acme"}},"person_properties":{"plan":"pro"}},"schema":{"$ref":"#/components/schemas/flag.evaluateIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"errorsWhileComputingFlags":false,"featureFlagPayloads":{},"featureFlags":{"new-editor":true}},"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flag","x-public":true,"x-tool":true}},"/v1/flag/defs":{"get":{"operationId":"get_flag_defs","summary":"Returns every flag definition in the caller's (org, project) store, by key, with its version and who last changed it.","description":"Returns every flag definition in the caller's (org,\nproject) store, by key, with its version and who last changed it.","tags":["flag"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/flag.defsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flag","x-public":true,"x-tool":true}},"/v1/flag/defs/{key}":{"delete":{"operationId":"delete_flag_defs_by_key","summary":"Removes one flag definition by key and records the deletion in the change log.","description":"Removes one flag definition by key and records the\ndeletion in the change log. A key the caller's store does not hold is a 404.\nA staged capability's key is a SuperAdmin's to remove, as it is to set, and\nevery other key an owner's or admin's of the org.","tags":["flag"],"parameters":[{"name":"key","in":"path","required":true,"description":"Key is the flag key to act on, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/flag.deletedOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flag","x-public":true,"x-tool":true},"get":{"operationId":"get_flag_defs_by_key","summary":"Returns one flag definition by key, or 404 when the caller's store has none under that key.","description":"Returns one flag definition by key, or 404 when the caller's\nstore has none under that key.","tags":["flag"],"parameters":[{"name":"key","in":"path","required":true,"description":"Key is the flag key to act on, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/flag.DefRow"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flag","x-public":true,"x-tool":true},"put":{"operationId":"put_flag_defs_by_key","summary":"Creates or replaces the flag definition at the path's key and returns the stored row.","description":"Creates or replaces the flag definition at the path's key and\nreturns the stored row. The BODY IS THE DEFINITION DOCUMENT — the flag-definition\nJSON object the evaluator consumes — and it is stored verbatim except that its\n\"key\" is forced to the key in the URL, so a document can never be filed under a\nname other than the one it was addressed by. Every write bumps the version and\nappends to the change log under the caller's identity. A key that lets an org\ninto a capability that is not ga — research, machines — is a SuperAdmin's to\nset, never an org admin's, and its write is on the audit trail before it lands;\nevery other key is an owner's or admin's of the org, never a member's.","tags":["flag"],"parameters":[{"name":"key","in":"path","required":true,"description":"Key is the flag key to write, from the path.","schema":{"type":"string"},"example":"new-editor"}],"requestBody":{"content":{"application/json":{"example":{"active":true,"filters":{"groups":[{"rollout_percentage":25}]},"key":"new-editor"},"schema":{}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/flag.DefRow"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flag","x-public":true,"x-tool":true}},"/v1/flag/health":{"get":{"operationId":"get_flag_health","summary":"Reports that the flag engine is serving.","description":"Reports that the flag engine is serving. It is not gated: liveness must\nbe probe-able without a token.","tags":["flag"],"responses":{"200":{"content":{"application/json":{"example":{"engine":"hanzo-flags","ok":true},"schema":{"$ref":"#/components/schemas/flag.healthOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flag","x-public":true,"x-tool":true}},"/v1/flag/optin":{"get":{"operationId":"get_flag_optin","summary":"Answers the signed-in caller's opt-in to public betas: whether they opted in, whether the org they act in blocked it, and which betas are public.","description":"Answers the signed-in caller's opt-in to public betas: whether they\nopted in, whether the org they act in blocked it, and which betas are public. A\nbeta not listed is private, granted person by person.","tags":["flag"],"responses":{"200":{"content":{"application/json":{"example":{"blocked":false,"on":true,"public":["koma","iro"]},"schema":{"$ref":"#/components/schemas/flag.optinOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flag","x-public":true,"x-tool":true},"put":{"operationId":"put_flag_optin","summary":"Sets the signed-in caller's OWN opt-in to public betas: on, every public beta and each one promoted later is on for them; off, none is.","description":"Sets the signed-in caller's OWN opt-in to public betas: on, every\npublic beta and each one promoted later is on for them; off, none is. Self only:\nthe row written is the caller's validated subject, whatever the request says.\nOpting in while the org they act in blocked it is refused; opting out never is.","tags":["flag"],"requestBody":{"content":{"application/json":{"example":{"on":true},"schema":{"$ref":"#/components/schemas/flag.optinIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"blocked":false,"on":true,"public":["koma","iro"]},"schema":{"$ref":"#/components/schemas/flag.optinOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flag","x-public":true,"x-tool":true}},"/v1/flag/optin/org":{"put":{"operationId":"put_flag_optin_org","summary":"Blocks or unblocks the opt-in to public betas for every member of the org the caller acts in.","description":"Blocks or unblocks the opt-in to public betas for every member of\nthe org the caller acts in. An owner or admin of that org, or a SuperAdmin, may;\na member may not. It only withholds: blocked, no member gets a public beta by\nopting in, and their own choices are kept for when it is lifted; it never turns\na beta on. A shared sign-up org has no admin to speak for its members and is\nrefused. The change is on the audit trail before it lands.","tags":["flag"],"requestBody":{"content":{"application/json":{"example":{"blocked":true},"schema":{"$ref":"#/components/schemas/flag.orgOptinIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"blocked":true},"schema":{"$ref":"#/components/schemas/flag.orgOptinOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flag","x-public":true,"x-tool":true}},"/v1/flag/platform":{"get":{"operationId":"get_flag_platform","summary":"Answers the platform switches that are decided per caller — `beta`, whether the caller sees what is not yet generally available — as they apply to the signed-in caller: its validated org and user, never anything the request states.","description":"Answers the platform switches that are decided per caller — `beta`,\nwhether the caller sees what is not yet generally available — as they apply to\nthe signed-in caller: its validated org and user, never anything the request\nstates. A SuperAdmin targets them from the admin cockpit; nothing here changes\nthem. A request without a signed-in principal is refused, and a switch that\ncannot be read is 503, which a caller takes as off.","tags":["flag"],"responses":{"200":{"content":{"application/json":{"example":{"flags":{"beta":false,"beta.crm":true,"beta.erp":false}},"schema":{"$ref":"#/components/schemas/flag.platformOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flag","x-public":true,"x-tool":true}},"/v1/flow/runs":{"get":{"operationId":"get_flow_runs","summary":"Reads one workflow's recorded runs: every component build with its result, keyed by component.","description":"Reads one workflow's recorded runs: every component build with its\nresult, keyed by component. Ownership is verified first — run records never\ncross the org boundary.","tags":["flow"],"parameters":[{"name":"workflow","in":"query","required":false,"description":"Workflow is the UUID of the workflow whose run records to read. It rides\nthe query string.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flow","x-public":true,"x-tool":true},"post":{"operationId":"post_flow_runs","summary":"Executes one of the caller's workflows synchronously: the graph runs in the flow service and the response carries the run's session and outputs.","description":"Executes one of the caller's workflows synchronously: the graph runs in\nthe flow service and the response carries the run's session and outputs. A\ngraph whose components fail reports the product's own error. Runs are\nbounded by the product's five-minute sync ceiling.","tags":["flow"],"requestBody":{"content":{"application/json":{"example":{"input":"summarize today's tickets","workflow":"8f14e45f-…"},"schema":{"$ref":"#/components/schemas/flow.flowRun"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flow","x-public":true,"x-tool":true}},"/v1/flow/status":{"get":{"operationId":"get_flow_status","summary":"Reports whether the flow service is reachable and which version it runs.","description":"Reports whether the flow service is reachable and which version it\nruns. It is the product's own /health and /v1/version composed — an honest\nlens for \"is the workflow plane up\", never a fabricated ok.","tags":["flow"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/flow.flowStatus"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flow","x-public":true,"x-tool":true}},"/v1/flow/workflows":{"get":{"operationId":"get_flow_workflows","summary":"Lists the caller's workflows, paged.","description":"Lists the caller's workflows, paged. The list is scoped\nserver-side to the org's project — the page can only ever hold the caller's\nown workflows.","tags":["flow"],"parameters":[{"name":"page","in":"query","required":false,"description":"Page is the 1-based page of workflows to return.","schema":{"type":"string"}},{"name":"size","in":"query","required":false,"description":"Size is how many workflows one page holds (the product caps it at 100).","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flow","x-public":true,"x-tool":true},"post":{"operationId":"post_flow_workflows","summary":"Creates a workflow in the caller's org.","description":"Creates a workflow in the caller's org. The org's project id\nis pinned server-side from the validated principal — there is no field by\nwhich a caller could place a workflow in another org.","tags":["flow"],"requestBody":{"content":{"application/json":{"example":{"description":"route tickets","name":"support-triage"},"schema":{"$ref":"#/components/schemas/flow.flowCreate"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flow","x-public":true,"x-tool":true}},"/v1/flow/workflows/{workflow}":{"delete":{"operationId":"delete_flow_workflows_by_workflow","summary":"Deletes one of the caller's workflows and its runs.","description":"Deletes one of the caller's workflows and its runs. Ownership\nis verified first; a foreign id answers 404 and deletes nothing.","tags":["flow"],"parameters":[{"name":"workflow","in":"path","required":true,"description":"Workflow is the workflow's UUID, taken from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flow","x-public":true,"x-tool":true},"get":{"operationId":"get_flow_workflows_by_workflow","summary":"Reads one of the caller's workflows — the full record, graph included.","description":"Reads one of the caller's workflows — the full record, graph\nincluded. A workflow outside the caller's org answers 404, indistinguishable\nfrom one that does not exist.","tags":["flow"],"parameters":[{"name":"workflow","in":"path","required":true,"description":"Workflow is the workflow's UUID, taken from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flow","x-public":true,"x-tool":true},"patch":{"operationId":"patch_flow_workflows_by_workflow","summary":"Patches one of the caller's workflows: name, description, graph, or the locked flag — only the stated fields move.","description":"Patches one of the caller's workflows: name, description,\ngraph, or the locked flag — only the stated fields move. Ownership is\nverified before the patch reaches the product.","tags":["flow"],"parameters":[{"name":"workflow","in":"path","required":true,"description":"Workflow is the workflow's UUID, taken from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"description":"route tickets to the right queue"},"schema":{"$ref":"#/components/schemas/flow.flowUpdate"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"flow","x-public":true,"x-tool":true}},"/v1/framework/doctypes":{"get":{"operationId":"get_framework_doctypes","summary":"Returns every DocType defined in the caller's org.","description":"Returns every DocType defined in the caller's org. Another\ntenant's definitions are never included: the org is part of the store key.","tags":["framework"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/framework.docTypeList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"framework","x-public":true,"x-tool":true},"post":{"operationId":"post_framework_doctypes","summary":"Defines a DocType in the caller's org: the metadata that gives a document surface its fields, its naming rule, whether it has a submit/cancel lifecycle, and which role may do what to it.","description":"Defines a DocType in the caller's org: the metadata that gives a\ndocument surface its fields, its naming rule, whether it has a submit/cancel\nlifecycle, and which role may do what to it. Manager-only — on a fresh org the\nfirst caller to administer it is seeded as its System Manager, after which\nonly a System Manager (or a platform admin) may define. Answers 201.","tags":["framework"],"requestBody":{"content":{"application/json":{"example":{"autoname":"TASK-.#####","fields":[{"fieldname":"subject","fieldtype":"Data","reqd":true}],"module":"Projects","name":"Task"},"schema":{"$ref":"#/components/schemas/framework.DocType"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/framework.DocType"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"framework","x-public":true,"x-tool":true}},"/v1/framework/doctypes/{name}":{"delete":{"operationId":"delete_framework_doctypes_by_name","summary":"Removes a DocType and every document stored under it.","description":"Removes a DocType and every document stored under it. The\ndefinition and its data go together — a document with no schema can be neither\nvalidated nor read back — so there is no undo. Manager-only. Answers 204.","tags":["framework"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the DocType's ADDRESS — \"module.name\", e.g. \"kb.page\". A name\ncontaining a space (\"erp.Sales Invoice\") arrives percent-encoded and is\ndecoded before it is matched against the stored one.","schema":{"type":"string"},"example":"Projects.Task"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"framework","x-public":true,"x-tool":true},"get":{"operationId":"get_framework_doctypes_by_name","summary":"Returns one DocType definition — its fields, naming rule, permissions and lifecycle flags.","description":"Returns one DocType definition — its fields, naming rule,\npermissions and lifecycle flags. Scoped to the caller's org, so another\ntenant's DocType of the same name is simply not found.","tags":["framework"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the DocType's ADDRESS — \"module.name\", e.g. \"kb.page\". A name\ncontaining a space (\"erp.Sales Invoice\") arrives percent-encoded and is\ndecoded before it is matched against the stored one.","schema":{"type":"string"},"example":"Projects.Task"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/framework.DocType"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"framework","x-public":true,"x-tool":true},"put":{"operationId":"put_framework_doctypes_by_name","summary":"Replaces a DocType definition wholesale (PUT semantics): the stored definition becomes the body.","description":"Replaces a DocType definition wholesale (PUT semantics): the\nstored definition becomes the body. The name in the URL is authoritative over\nthe body's, and documents already stored under the DocType are left intact.\nManager-only.","tags":["framework"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"example":"Projects.Task"}],"requestBody":{"content":{"application/json":{"example":{"fields":[{"fieldname":"subject","fieldtype":"Data"}],"name":"Projects.Task"},"schema":{"$ref":"#/components/schemas/framework.DocType"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/framework.DocType"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"framework","x-public":true,"x-tool":true}},"/v1/framework/modules":{"get":{"operationId":"get_framework_modules","summary":"Returns every app lane compiled into this deployment and the DocTypes each one installs.","description":"Returns every app lane compiled into this deployment and the\nDocTypes each one installs. It describes the BINARY, not the org: what a given\norg has actually installed is the per-module state below.","tags":["framework"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/framework.moduleList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"framework","x-public":true,"x-tool":true}},"/v1/framework/modules/{module}":{"get":{"operationId":"get_framework_modules_by_module","summary":"Returns one app lane's install state for the caller's org: the DocTypes the lane declares, and which of them already exist in the org.","description":"Returns one app lane's install state for the caller's org: the\nDocTypes the lane declares, and which of them already exist in the org. That\nis the honest \"set up\" versus \"installed\" answer a console renders.","tags":["framework"],"parameters":[{"name":"module","in":"path","required":true,"description":"Module is the lane's registered name (\"cms\", \"erp\"), from the path.","schema":{"type":"string"},"example":"cms"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/framework.ModuleState"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"framework","x-public":true,"x-tool":true}},"/v1/framework/modules/{module}/install":{"post":{"operationId":"post_framework_modules_by_module_install","summary":"Creates an app lane's DocTypes in the caller's org.","description":"Creates an app lane's DocTypes in the caller's org. Idempotent:\na DocType the org already has is reported as existing and never replaced. It\nonly grows, by the fields the lane now declares and the stored definition\nlacks (reported as grown), so re-installing is how a lane's new fields reach an\norg that installed it earlier. Manager-only.","tags":["framework"],"parameters":[{"name":"module","in":"path","required":true,"description":"Module is the lane's registered name (\"cms\", \"erp\"), from the path.","schema":{"type":"string"},"example":"cms"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/framework.Install"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"framework","x-public":true,"x-tool":true}},"/v1/framework/summary":{"get":{"operationId":"get_framework_summary","summary":"Reports how much of the DocType surface the caller's org uses: how many DocTypes it has defined, and how many documents exist across them.","description":"Reports how much of the DocType surface the caller's org uses: how\nmany DocTypes it has defined, and how many documents exist across them.","tags":["framework"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/framework.summaryView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"framework","x-public":true,"x-tool":true}},"/v1/framework/{doctype}":{"get":{"operationId":"get_framework_by_doctype","summary":"Returns the caller org's documents of one DocType, filtered, ordered and projected by the query.","description":"Returns the caller org's documents of one DocType, filtered,\nordered and projected by the query. The DocType is resolved FIRST — through\nthe same permission gate the list itself uses — because the query is validated\nagainst its schema: a filter, sort or field name the DocType does not declare\nis refused rather than reaching the store.","tags":["framework"],"parameters":[{"name":"doctype","in":"path","required":true,"description":"DocType is the DocType to list, by ADDRESS — \"module.name\", from the path.","schema":{"type":"string"},"example":"Projects.Task"},{"name":"filters","in":"query","required":false,"description":"Filters is a JSON object of equality matches, e.g. {\"priority\":\"High\"}.\nEvery key must be a field the DocType declares (or the managed name /\ndocstatus); an undeclared one is refused rather than silently ignored.","schema":{"type":"string"},"example":"{\"priority\":\"High\"}"},{"name":"fields","in":"query","required":false,"description":"Fields projects the response to a subset — a JSON array [\"a\",\"b\"] or a\ncomma list \"a,b\". The envelope keys are always returned.","schema":{"type":"string"}},{"name":"order_by","in":"query","required":false,"description":"OrderBy is \"\u003cfield\u003e [asc|desc]\". Empty means most-recently-updated first.","schema":{"type":"string"},"example":"estimate asc"},{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned. Anything that is not a positive integer\nleaves the engine's default in place.","schema":{"type":"string"},"example":"20"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/framework.documentList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"framework","x-public":true,"x-tool":true},"post":{"operationId":"post_framework_by_doctype","summary":"Create one document of a DocType, from that DocType's own fields.","description":"The body is the DOCUMENT'S field data: a flat JSON object whose properties are the fieldnames the DocType declares, not a fixed envelope. That is why this operation publishes no request schema — the shape is metadata the DocType defines at run time, and no Go struct both accepts it verbatim and describes it, so nothing is asserted rather than something false.\n\nThe engine validates and coerces every field against the DocType, runs the before_insert and before_save hooks (either may reject the write), stores the document, then runs the after hooks. It answers 201 with the stored document: the field data plus the managed envelope — `name`, `doctype`, `docstatus`, `createdAt`, `updatedAt`. A Password field comes back as a fixed redaction marker and is dropped when empty; its stored value is never returned by this or any other read on this surface.\n\n`name` in the body is the REQUESTED DOCUMENT NAME, not a data field. A DocType with an autoname rule names the document itself and ignores it; a prompt-named DocType takes it. This collision is also why the two path segments cannot be folded into the body, and so why the route stays untyped.\n\nScoped to the org of the validated principal, and the engine's own permission calculus decides the rest: the caller needs create rights on this DocType through a role it holds, or a platform admin bit. A caller with no validated principal reaches the engine as the zero Caller and is refused before any store is opened — a forged org header alone buys nothing.\n\nA DocType declared Single has exactly ONE document per org, so this writes that one instance instead of adding a row. The body is size-bounded by the engine, the same bound on every host.","tags":["framework"],"parameters":[{"name":"doctype","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"framework","x-public":true}},"/v1/framework/{doctype}/{name}":{"delete":{"operationId":"delete_framework_by_doctype_by_name","summary":"Removes one document, after its on_trash hooks agree.","description":"Removes one document, after its on_trash hooks agree. A\nSUBMITTED document cannot be deleted — cancel it first. Answers 204.","tags":["framework"],"parameters":[{"name":"doctype","in":"path","required":true,"description":"DocType is the document's DocType, by ADDRESS — \"module.name\", from the path.","schema":{"type":"string"},"example":"Projects.Task"},{"name":"name","in":"path","required":true,"description":"Name is the document's name — its key within the DocType — from the path.\nA name containing a space arrives percent-encoded and is decoded before it\nis matched against the stored one.","schema":{"type":"string"},"example":"TASK-00001"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"framework","x-public":true,"x-tool":true},"get":{"operationId":"get_framework_by_doctype_by_name","summary":"Returns one document by name, with Password fields redacted.","description":"Returns one document by name, with Password fields redacted.","tags":["framework"],"parameters":[{"name":"doctype","in":"path","required":true,"description":"DocType is the document's DocType, by ADDRESS — \"module.name\", from the path.","schema":{"type":"string"},"example":"Projects.Task"},{"name":"name","in":"path","required":true,"description":"Name is the document's name — its key within the DocType — from the path.\nA name containing a space arrives percent-encoded and is decoded before it\nis matched against the stored one.","schema":{"type":"string"},"example":"TASK-00001"}],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"framework","x-public":true,"x-tool":true},"put":{"operationId":"put_framework_by_doctype_by_name","summary":"Replace a draft document's field data wholesale.","description":"PUT semantics: the stored field data BECOMES the body, so a field the body omits is not left at its previous value. The body is the document's own field data — the same metadata-defined open object the create takes, and the same reason this operation publishes no request schema.\n\nOnly a DRAFT can be edited. A document that has been submitted or cancelled is immutable and the write is refused as a conflict, so the submit lifecycle cannot be bypassed by a plain update — cancel it first, and note that a cancelled document can be deleted but never re-submitted or re-edited. The engine validates the new data against the DocType, runs before_save (which may reject), writes, then runs the after hooks, and answers 200 with the stored document plus its managed envelope, Password fields redacted.\n\nThe document name in the path is percent-decoded before it is matched, so a name containing a space is addressed as it is stored. An unknown DocType or document is not found, and the same answer covers a document that exists in another tenant: the org comes from the validated principal and is part of the store key, so a caller cannot learn that another org's document exists. Write rights on the DocType are required, decided by the engine's permission calculus.\n\nFor a Single DocType the path name is ignored — there is one instance per org and this writes it.","tags":["framework"],"parameters":[{"name":"doctype","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"framework","x-public":true}},"/v1/framework/{doctype}/{name}/cancel":{"post":{"operationId":"post_framework_by_doctype_by_name_cancel","summary":"Moves a submitted document to cancelled (docstatus 1 → 2) after its on_cancel hooks agree.","description":"Moves a submitted document to cancelled (docstatus 1 → 2) after\nits on_cancel hooks agree. Cancelling is terminal — a cancelled document\ncannot be re-submitted — but it CAN then be deleted.","tags":["framework"],"parameters":[{"name":"doctype","in":"path","required":true,"description":"DocType is the document's DocType, by ADDRESS — \"module.name\", from the path.","schema":{"type":"string"},"example":"Projects.Task"},{"name":"name","in":"path","required":true,"description":"Name is the document's name — its key within the DocType — from the path.\nA name containing a space arrives percent-encoded and is decoded before it\nis matched against the stored one.","schema":{"type":"string"},"example":"TASK-00001"}],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"framework","x-public":true,"x-tool":true}},"/v1/framework/{doctype}/{name}/submit":{"post":{"operationId":"post_framework_by_doctype_by_name_submit","summary":"Moves a draft to submitted (docstatus 0 → 1) after its on_submit hooks agree.","description":"Moves a draft to submitted (docstatus 0 → 1) after its\non_submit hooks agree. A submitted document is IMMUTABLE: further writes and\ndeletes are refused until it is cancelled. Only a submittable DocType has this\nlifecycle; any other docstatus is an illegal transition.","tags":["framework"],"parameters":[{"name":"doctype","in":"path","required":true,"description":"DocType is the document's DocType, by ADDRESS — \"module.name\", from the path.","schema":{"type":"string"},"example":"Projects.Task"},{"name":"name","in":"path","required":true,"description":"Name is the document's name — its key within the DocType — from the path.\nA name containing a space arrives percent-encoded and is decoded before it\nis matched against the stored one.","schema":{"type":"string"},"example":"TASK-00001"}],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"framework","x-public":true,"x-tool":true}},"/v1/function":{"get":{"operationId":"get_function","summary":"Is every serverless function the caller's org has published, each with its real 7-day rollup.","description":"Is every serverless function the caller's org has published, each with its\nreal 7-day rollup.\n\nA row carries the function's runtime, resource limits, deployment target and its\ninvoke endpoint, plus envCount — how many secrets it mounts. The rollup fields\nare ABSENT rather than zero when the function has not run in the window, so a\nconsole renders \"—\" instead of a fabricated 0.\n\nRequires a validated principal; the listing is scoped to its org.","tags":["function"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/function.fnList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"function","x-public":true,"x-tool":true},"post":{"operationId":"post_function","summary":"Publishes a serverless function under the caller's org and answers 201 with it.","description":"Publishes a serverless function under the caller's org and answers 201\nwith it.\n\nThe name is the key and is claimed once; the names that would shadow a\ncollection route are reserved. runtime and environment are the same field —\neither spelling is accepted — and default to node.\n\nBounds are clamped rather than refused where a clamp is honest: a timeout above\nthe 900-second ceiling becomes the ceiling instead of silently reverting to the\n30-second default, and an omitted memory limit becomes 256Mi. target=fleet runs\non the org's own GPU fleet and supports runtime=python only.\n\nRequires a validated principal; the function is owned by that principal's org.","tags":["function"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/function.definition"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/function.functionView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"function","x-public":true,"x-tool":true}},"/v1/function/deployments":{"get":{"operationId":"get_function_deployments","summary":"Is what is live right now — each function's current record IS its live deployment, so this is the deployment inventory.","description":"Is what is live right now — each function's current record IS its\nlive deployment, so this is the deployment inventory.\n\nThere is no deployment history behind it: a function has one record, and\npublishing replaces it. The 7-day rollup is deliberately absent here, because\nthis read is about what is deployed rather than about how it has performed.","tags":["function"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/function.fnList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"function","x-public":true,"x-tool":true}},"/v1/function/metrics":{"get":{"operationId":"get_function_metrics","summary":"Is the org's serverless dashboard over a window: a per-function invocation costLine and how those invocations ended.","description":"Is the org's serverless dashboard over a window: a per-function\ninvocation costLine and how those invocations ended.\n\nEvery point is a REAL count of rows that fell in that bucket — nothing is\ninterpolated or invented, so an empty window draws a flat line rather than a\nfabricated one.\n\ncostCents is null and stays null: there is no per-invocation cost source to read,\nand reporting a number computed some other way would be a guess presented as a\nmeasurement. Requires a validated principal; the read is scoped to its org.","tags":["function"],"parameters":[{"name":"range","in":"query","required":false,"description":"Range is 1H, 6H, 24H (the default), 7D or 30D. Anything else falls back to\n24H rather than failing.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/function.usage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"function","x-public":true,"x-tool":true}},"/v1/function/secrets":{"get":{"operationId":"get_function_secrets","summary":"Is the NAMES of the secrets the caller org's functions mount.","description":"Is the NAMES of the secrets the caller org's functions mount.\n\nValues are NEVER read or returned — this surface knows which names a function\nasks for and nothing about what is behind them, which is what makes it safe to\nlist at all. One row per distinct (namespace, name).","tags":["function"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/function.secretList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"function","x-public":true,"x-tool":true}},"/v1/function/triggers":{"get":{"operationId":"get_function_triggers","summary":"Is what calls the caller org's functions — one row per function.","description":"Is what calls the caller org's functions — one row per function.\n\nEvery function has exactly one trigger today, its HTTP invoke endpoint, so this\nis the function list read as \"how is each of these reached\".","tags":["function"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/function.triggerList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"function","x-public":true,"x-tool":true}},"/v1/function/{name}":{"delete":{"operationId":"delete_function_by_name","summary":"Removes one of the caller org's functions and answers 204.","description":"Removes one of the caller org's functions and answers 204.\n\nA name this org does not hold is 404 — never a silent success — and a name\nbelonging to another tenant is the same 404, because the delete is predicated on\nthe validated org.","tags":["function"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the function the URL names.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"function","x-public":true,"x-tool":true},"get":{"operationId":"get_function_by_name","summary":"Is one function with everything a detail page needs in one round-trip: its definition, its 7-day rollup, its trigger, its twenty most recent invocations and the NAMES of the secrets it mounts.","description":"Is one function with everything a detail page needs in one round-trip: its\ndefinition, its 7-day rollup, its trigger, its twenty most recent invocations\nand the NAMES of the secrets it mounts.\n\nSecret values are never read or returned. A name the caller's org does not hold\nis 404, which is also what another tenant's function looks like from here.","tags":["function"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the function the URL names.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/function.functionDetail"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"function","x-public":true,"x-tool":true}},"/v1/function/{name}/invocations":{"get":{"operationId":"get_function_by_name_invocations","summary":"Is one function's past runs, newest first — each with its status, HTTP code, method, time and duration.","description":"Is one function's past runs, newest first — each with its status,\nHTTP code, method, time and duration.\n\nThese are real recorded rows, not a projection: an invocation appears here only\nonce it actually ran. Requires a validated principal; the read is scoped to its\norg.","tags":["function"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the function the URL names.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps the page, defaulting to 100.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/function.invocationList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"function","x-public":true,"x-tool":true}},"/v1/function/{name}/invoke":{"post":{"operationId":"post_function_by_name_invoke","summary":"Runs a function and records a REAL invocation.","description":"Runs a function and records a REAL invocation.\n\nThe answer is the invocation record whatever happened to it: 200 when the org's\ncode ran clean, 502 when it ran and failed, 503 when this deployment has no\nsandbox to run code in. The record IS the evidence, so it rides the failure\nrather than being replaced by an error envelope.\n\nBilling is two-part and both parts are prepaid-then-metered on the one shared\nmeter: a flat per-invocation request fee, gated BEFORE any sandbox compute runs\nso an unfunded org gets 402 and nothing executes, and a usage-native\nGB-seconds compute debit taken after the run. Either is independently free when\nits fee is zero, so an operator can bill by request alone, by compute alone, or\nby both — and a zero request fee removes the balance gate with it.\n\nA TRANSPORT failure is not charged: the sandbox being unreachable ran no\nbillable compute. Code that ran and exited non-zero IS charged — that is a\nsuccessful invocation of a failing program, not a billing failure.\n\nWhen the sandbox is not configured on this deployment, a non-fleet function\nfails closed before anything is recorded — no execution and no fabricated\noutput. Scoped to the caller's org; requires a validated principal.","tags":["function"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/function.invokeReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/function.invocationView"}}},"description":"ok"},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/function.invocationView"}}},"description":"bad gateway"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/function.invocationView"}}},"description":"service unavailable"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"function","x-public":true,"x-tool":true}},"/v1/function/{name}/logs":{"get":{"operationId":"get_function_by_name_logs","summary":"Is the output of a function's most recent run — its error text when that run failed, else what it printed.","description":"Is the output of a function's most recent run — its error text when that\nrun failed, else what it printed.\n\nIt is the LAST run only, and it is empty when the function has never run. There\nis no log retention behind this beyond the recorded invocation itself.","tags":["function"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the function the URL names.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/function.logLines"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"function","x-public":true,"x-tool":true}},"/v1/gateway/config":{"get":{"operationId":"get_gateway_config","summary":"Returns the EFFECTIVE edge policy the caller is subject to: the platform CORS allowlist and pre-auth per-IP flood cap in force, plus the caller's own authenticated rate ceiling, edge-cache TTLs and accepted-method allowlist.","description":"Returns the EFFECTIVE edge policy the caller is subject to: the platform CORS\nallowlist and pre-auth per-IP flood cap in force, plus the caller's own authenticated\nrate ceiling, edge-cache TTLs and accepted-method allowlist. A SuperAdmin may inspect\na specific tenant's effective policy with ?org=\u003cslug\u003e.","tags":["gateway"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/gateway.Policy"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"gateway","x-public":true,"x-tool":true},"put":{"operationId":"put_gateway_config","summary":"Updates one policy scope and returns the policy in force after the write.","description":"Updates one policy scope and returns the policy in force after the write.\nWriting requires a signed-in admin of the organization, or a SuperAdmin; a\nmember and every API key are refused 403, and so is a browser session's change\nthat its own page did not send.\nA body carrying any PLATFORM field (cors_origins, per_ip_rpm, window_sec) is a\nplatform write and requires SuperAdmin; otherwise it is a per-org write (org_rpm,\ncache_ttl_sec, cache_paths, methods) scoped to the caller's own org — or, for a\nSuperAdmin, the tenant named by ?org=\u003cslug\u003e. A body that sets nothing is a 400.\nThe abuse gate's mode and an organization's rate cap (org_cap) are OPERATOR\nfields: setting either requires SuperAdmin, whichever organization it lands on,\nand an org_cap change is recorded on the audit trail with the cap before and\nafter (gateway.org_cap), or refused (503) when the trail cannot take it. The\nplatform's org_rpm is every organization's default cap, so moving it is recorded\nthe same way (gateway.default_cap). An\norganization's own org_rpm may lower its ceiling but not raise it past its cap. updated_at and updated_by are server-stamped; a client-supplied value is\nignored.","tags":["gateway"],"requestBody":{"content":{"application/json":{"example":{"cache_ttl_sec":30,"methods":["GET","POST"],"org_rpm":120},"schema":{"$ref":"#/components/schemas/gateway.Policy"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/gateway.Policy"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"gateway","x-public":true,"x-tool":true}},"/v1/gateway/traffic":{"get":{"operationId":"gatewayTraffic","summary":"Report who is calling this org's API right now","description":"Reports who is calling this organization's API right now: the request\ncount for the last minute split by AGENCY LANE — agent, human, bot, unknown —\nand the busiest callers behind it, each with its request count, its\nauthentication-failure count, how many distinct paths it touched, and any\nverdict currently held against it.\n\nThe lane split is the answer to the question a generic bot filter cannot\nanswer: which of this traffic is the customer's own automation and which is\nsomebody working through a list. It is computed from credentials we issued, not\nfrom the client's self-description, so a scraper cannot move itself into the\nagent lane by editing a header.\n\nA validated caller appears as a FINGERPRINT — a one-way, per-process digest. It\nis stable enough to recognise the same caller across a minute and cannot be\nturned back into a key, so this report is safe to read, screenshot and paste.\n\nIt also reports what the sensor's own ceilings are doing (strain, tracked,\nceiling, refused) and how many screens the scorer did not answer (unscored), so\na control that has stopped measuring or a judge that has stopped answering is a\nnumber here rather than a quiet day.\n\nScoped to the caller's own validated organization. A SuperAdmin may inspect a\nspecific tenant with ?org=\u003cslug\u003e, or the lane that has no tenant — every caller\nthe identity boundary could not validate — with an empty ?org=.","tags":["gateway"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/gateway.TrafficView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"gateway","x-public":true,"x-tool":true}},"/v1/git":{"get":{"operationId":"get_git","summary":"Browse your org's repositories","description":"The repository list for the signed-in caller's org — each repo with its description, default branch, size and last update. SIGNED OUT it renders the public explore page instead of refusing, because most Hanzo repos are open source and the open face is the default one; signed in, the caller's own org shows its private repositories alongside its public ones. This is a server-rendered browser page, not JSON — the console repo-browser reads the same repository through the JSON ops under /v1/git/repos. Repository names, paths and file contents all render through auto-escaping templates rather than being concatenated into HTML.","tags":["git"],"x-app":"git","x-public":true}},"/v1/git/explore":{"get":{"operationId":"get_git_explore","summary":"Discover public repositories across every org","description":"The open, unauthenticated face of the git host: every PUBLIC repository in the fleet, org-qualified, so a project can be found and cloned with no account at all — signing in is for private repos and for writes. Repositories live in per-org stores with no global index, so this unions each org's public rows and is bounded to a fixed number of stores per request, keeping discovery quick however many orgs exist. A fleet with no orgs yet is an empty page, not an error. This is a server-rendered browser page, not JSON — the console repo-browser reads the same repository through the JSON ops under /v1/git/repos. Repository names, paths and file contents all render through auto-escaping templates rather than being concatenated into HTML.","tags":["git"],"x-app":"git","x-public":true}},"/v1/git/link":{"post":{"operationId":"post_git_link","summary":"Links every repository of the caller's org that holds no history here and names no link to github.com/\u003cowner\u003e/\u003cname\u003e, where GitHub lets the caller read it.","description":"Links every repository of the caller's org that holds no history\nhere and names no link to github.com/\u003cowner\u003e/\u003cname\u003e, where GitHub lets the\ncaller read it. A repository with no such namesake is listed and left alone,\nand one holding history here is listed and never touched. Nothing is fetched:\na linked repository's cache fills on its first read. Org admins only.","tags":["git"],"requestBody":{"content":{"application/json":{"example":{"owner":"acme"},"schema":{"$ref":"#/components/schemas/git.linkAll"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"held":["native"],"linked":[{"cloneUrl":"https://api.hanzo.ai/v1/git/acme/widgets.git","createdAt":"2026-10-08T10:00:00Z","defaultBranch":"main","id":"repo_9f3c","link":{"cloneUrl":"https://github.com/acme/widgets.git","name":"widgets","owner":"acme","provider":"github"},"name":"widgets","org":"acme","public":false,"sizeBytes":0,"sshUrl":"git@git.hanzo.ai:acme/widgets.git"}],"unmatched":[{"name":"scratch","reason":"acme/scratch is not readable as you on GitHub: connect your GitHub account, or ask an org admin"}]},"schema":{"$ref":"#/components/schemas/git.linked"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/pools":{"get":{"operationId":"get_git_pools","summary":"Returns the capacity this org has declared and how many daemons have entered each pool.","description":"Returns the capacity this org has declared and how many daemons have\nentered each pool.","tags":["git"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/git.poolList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true},"post":{"operationId":"post_git_pools","summary":"Records the capacity an org has, and answers with the secret a runner daemon presents to enter it.","description":"Records the capacity an org has, and answers with the secret a\nrunner daemon presents to enter it.\n\nDeclaring is the ONLY way capacity comes to exist: a daemon cannot register\nagainst a pool nobody declared, because the secret it would have to present\ndoes not exist until this runs. Re-declaring an existing pool replaces its\nlabels and mints a fresh secret; runners already inside it keep working.","tags":["git"],"requestBody":{"content":{"application/json":{"example":{"labels":["ubuntu-latest","linux/amd64"],"name":"evo"},"schema":{"$ref":"#/components/schemas/git.poolDeclare"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/git.poolDeclared"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/repos":{"get":{"operationId":"get_git_repos","summary":"Returns the repos in the caller's scope, most recently updated first.","description":"Returns the repos in the caller's scope, most recently updated\nfirst. The scope is the request principal's — the gateway-minted org and its\noptional project — never anything off the wire, so a caller only ever sees its\nown. Rows carry no branches or HEAD; read one repo for those.","tags":["git"],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"cloneUrl":"https://api.hanzo.ai/v1/git/acme/widgets.git","createdAt":"2026-07-01T10:00:00Z","defaultBranch":"main","id":"repo_9f3c","name":"widgets","org":"acme","public":false,"sizeBytes":4096,"sshUrl":"git@git.hanzo.ai:acme/widgets.git"}]},"schema":{"$ref":"#/components/schemas/git.repoList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true},"post":{"operationId":"post_git_repos","summary":"Provisions an empty bare repository in the caller's scope and returns it with its clone URLs.","description":"Provisions an empty bare repository in the caller's scope and\nreturns it with its clone URLs. Answers 201. The name must be unique within\nthe scope — a repeat is a 409, never a silent overwrite of an existing repo.\nThe org comes from the validated principal, so a repo is always born owned by\nthe caller's own tenant.","tags":["git"],"requestBody":{"content":{"application/json":{"example":{"description":"the widget service","name":"widgets"},"schema":{"$ref":"#/components/schemas/git.createReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/git.repoView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/repos/{name}":{"delete":{"operationId":"delete_git_repos_by_name","summary":"Removes a repo's metadata and purges its storage.","description":"Removes a repo's metadata and purges its storage. Answers 204 with\nno body. The metadata row is the source of truth for existence, so a storage\npurge that fails is logged and the delete still succeeds — and a second call\nis a 404, not a second delete.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo's org-unique handle, from the :name path segment. A\ntrailing \".git\" is stripped.","schema":{"type":"string"},"example":"widgets"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true},"get":{"operationId":"get_git_repos_by_name","summary":"Returns one repo with its live ref state: every branch name and the resolved HEAD commit.","description":"Returns one repo with its live ref state: every branch name and the\nresolved HEAD commit. Both are read from the object store on each call, so an\nempty repo reports no branches and an empty head rather than failing. A repo\noutside the caller's scope is not found.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo's org-unique handle, from the :name path segment. A\ntrailing \".git\" is stripped.","schema":{"type":"string"},"example":"widgets"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/git.repoView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true},"patch":{"operationId":"patch_git_repos_by_name","summary":"Flips a repo's public bit, the one mutable repo setting today.","description":"Flips a repo's public bit, the one mutable repo setting today.\nPublic grants ANONYMOUS fetch only; push and the whole control plane stay\norg-authed. Returns the updated repo.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo to update, from the :name path segment.","schema":{"type":"string"},"example":"widgets"}],"requestBody":{"content":{"application/json":{"example":{"name":"widgets","public":true},"schema":{"$ref":"#/components/schemas/git.patchIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/git.repoView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/repos/{name}/blob":{"get":{"operationId":"get_git_repos_by_name_blob","summary":"Returns one file's bytes at one revision.","description":"Returns one file's bytes at one revision. Text comes back verbatim,\nbinary comes back base64, and a file past the 1 MiB view cap comes back marked\ntruncated with NO content — the client is expected to clone instead. A\nrepository in the organization's own code workspace on the forge is read from\nthere.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo to read, from the :name path segment.","schema":{"type":"string"},"example":"widgets"},{"name":"ref","in":"query","required":false,"description":"Ref is a branch, tag or commit; empty means the repo's HEAD.","schema":{"type":"string"},"example":"main"},{"name":"path","in":"query","required":false,"description":"Path is repo-relative; empty is the tree root. Traversal is stripped.","schema":{"type":"string"},"example":"go.mod"}],"responses":{"200":{"content":{"application/json":{"example":{"binary":false,"content":"module widgets\n","encoding":"utf8","path":"go.mod","size":42,"truncated":false},"schema":{"$ref":"#/components/schemas/git.blobJSON"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/repos/{name}/commits":{"get":{"operationId":"get_git_repos_by_name_commits","summary":"Walks a ref's history newest first, or one path's history when a path is given.","description":"Walks a ref's history newest first, or one path's history when a\npath is given. There is no cursor: the page is the newest `limit` commits.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo to read, from the :name path segment.","schema":{"type":"string"},"example":"widgets"},{"name":"ref","in":"query","required":false,"description":"Ref is the branch, tag or commit to walk back from; empty means HEAD.","schema":{"type":"string"},"example":"main"},{"name":"path","in":"query","required":false,"description":"Path narrows the history to commits touching it; empty walks the whole ref.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps the page. Anything not positive means 50; the cap is 100.","schema":{"format":"int64","type":"integer"},"example":2}],"responses":{"200":{"content":{"application/json":{"example":{"commits":[{"authorEmail":"ada@hanzo.ai","authorName":"Ada","date":"2026-07-01T10:00:00Z","message":"add the widget service","sha":"a1b2c3d4e5f6","shortSha":"a1b2c3d"}]},"schema":{"$ref":"#/components/schemas/git.commitsJSON"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/repos/{name}/files":{"get":{"operationId":"get_git_repos_by_name_files","summary":"Returns every file a glob selects at one revision, WITH its bytes and the revision they came from.","description":"Returns every file a glob selects at one revision, WITH its bytes\nand the revision they came from. It is the read a delivery generator makes:\none call answers \"what is the inventory at this commit, and what does it say\",\nwhere listing and then fetching would be a request per file.\n\nReturning the resolved revision matters as much as the bytes. A generator that\nlists at `main` and then reads at `main` can straddle a push and assemble half\nits inventory from one commit and half from the next; resolving once makes the\nwhole read consistent by construction.\n\nA file past the read cap comes back Truncated with no content rather than\nbeing dropped. A caller building a desired set has to know the difference\nbetween \"this file is empty\" and \"this file was not read\" — silently omitting\nit is how a pruning reconcile deletes what the missing file declared.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo to read, from the :name path segment.","schema":{"type":"string"},"example":"universe"},{"name":"ref","in":"query","required":false,"description":"Ref is a branch, tag or commit; empty means the repo's HEAD.","schema":{"type":"string"},"example":"main"},{"name":"glob","in":"query","required":false,"description":"Glob selects files, matched segment by segment so `*` never crosses a `/`.\n`**` matches zero or more whole segments.","schema":{"type":"string"},"example":"charts/app/values/*/*.yaml"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/git.filesJSON"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/repos/{name}/gc":{"post":{"operationId":"post_git_repos_by_name_gc","summary":"Repacks a repo into one bitmapped pack and rewrites its commit-graph, so the next clone reuses the bitmap instead of walking the whole object graph.","description":"Repacks a repo into one bitmapped pack and rewrites its commit-graph, so\nthe next clone reuses the bitmap instead of walking the whole object graph.\nIdempotent, and safe to interrupt — git swaps both artifacts atomically. It\nruns under one pack slot with the same memory bounds as a clone, so it can\nblock behind heavy pack traffic rather than compete with it. Storage usage is\nre-measured afterwards, since a repack reclaims space.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo's org-unique handle, from the :name path segment. A\ntrailing \".git\" is stripped.","schema":{"type":"string"},"example":"widgets"}],"responses":{"200":{"content":{"application/json":{"example":{"maintained":true,"repo":"widgets","sizeBytes":3072},"schema":{"$ref":"#/components/schemas/git.gcOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/repos/{name}/home":{"post":{"operationId":"post_git_repos_by_name_home","summary":"Moves a repository whose history is HERE to the forge (git.hanzo.ai), the one home of a repository no other host holds, and links it there: the repository is made in the org's own namespace on the forge, every branch and tag is pushed to it, the forge's refs are read back and must equal these, and only then does the row name the forge as its link, so this copy becomes the cache it can be fetched back into.","description":"Moves a repository whose history is HERE to the forge (git.hanzo.ai),\nthe one home of a repository no other host holds, and links it there: the\nrepository is made in the org's own namespace on the forge, every branch and\ntag is pushed to it, the forge's refs are read back and must equal these, and\nonly then does the row name the forge as its link, so this copy becomes the\ncache it can be fetched back into. A forge repository of that name that\nalready exists is refused, never overwritten. Org admins only.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repository, from the :name path segment.","schema":{"type":"string"},"example":"widgets"}],"responses":{"200":{"content":{"application/json":{"example":{"cloneUrl":"https://api.hanzo.ai/v1/git/acme/widgets.git","createdAt":"2026-10-08T10:00:00Z","defaultBranch":"main","id":"repo_9f3c","link":{"cloneUrl":"https://git.hanzo.ai/acme/widgets.git","name":"widgets","owner":"acme","provider":"forge"},"name":"widgets","org":"acme","public":false,"sizeBytes":4096,"sshUrl":"git@git.hanzo.ai:acme/widgets.git"},"schema":{"$ref":"#/components/schemas/git.repoView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/repos/{name}/link":{"post":{"operationId":"post_git_repos_by_name_link","summary":"Records that a repository's history lives on another host, making the repository first when the org has none of that name.","description":"Records that a repository's history lives on another host, making\nthe repository first when the org has none of that name. Nothing is copied:\na read is served from a cache filled from the host, as the host lets the\ncaller read, and a push goes to the host. A repository whose history is HERE\nis refused (409): a link would hide what only this store holds.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repository, from the :name path segment. It is made when the\norg has none of that name.","schema":{"type":"string"},"example":"widgets"}],"requestBody":{"content":{"application/json":{"example":{"name":"widgets","source":"https://github.com/acme/widgets.git"},"schema":{"$ref":"#/components/schemas/git.linkReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"cloneUrl":"https://api.hanzo.ai/v1/git/acme/widgets.git","createdAt":"2026-10-08T10:00:00Z","defaultBranch":"main","id":"repo_9f3c","link":{"cloneUrl":"https://github.com/acme/widgets.git","name":"widgets","owner":"acme","provider":"github"},"name":"widgets","org":"acme","public":false,"sizeBytes":0,"sshUrl":"git@git.hanzo.ai:acme/widgets.git"},"schema":{"$ref":"#/components/schemas/git.repoView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/repos/{name}/pulls":{"get":{"operationId":"get_git_repos_by_name_pulls","summary":"Returns a repo's pull requests, newest number first — what is waiting to be reviewed, and what has already landed.","description":"Returns a repo's pull requests, newest number first — what is\nwaiting to be reviewed, and what has already landed. Narrow it with\n?state=open or ?state=merged; omit state for every proposal.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo, from the :name path segment.","schema":{"type":"string"},"example":"widgets"},{"name":"state","in":"query","required":false,"description":"State narrows the list to \"open\" or \"merged\". Omit it for every proposal.","schema":{"type":"string"},"example":"open"}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"base":"main","createdAt":"2026-08-07T10:00:00Z","head":"agent/cache-catalog","number":4,"repo":"widgets","state":"open","title":"cache the catalog read","updatedAt":"2026-08-07T10:00:00Z"}]},"schema":{"$ref":"#/components/schemas/git.pullList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true},"post":{"operationId":"post_git_repos_by_name_pulls","summary":"Proposes a branch for merging and returns it with its number.","description":"Proposes a branch for merging and returns it with its number. Answers\n201. Both branches must already exist — a proposal naming a branch nobody\npushed is a typo, not a plan — and base defaults to the repo's default branch.\n\nProposing the same head into the same base twice is a 409 while the first\nproposal is still open, so a retried agent run leaves ONE thing to review\nrather than a pile of identical ones. A repo outside the caller's scope is a\n404, exactly as reading it is.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo the proposal belongs to, from the :name path segment.","schema":{"type":"string"},"example":"widgets"}],"requestBody":{"content":{"application/json":{"example":{"base":"main","head":"agent/cache-catalog","name":"widgets","title":"cache the catalog read"},"schema":{"$ref":"#/components/schemas/git.openReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/git.pullView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/repos/{name}/pulls/{number}":{"get":{"operationId":"get_git_repos_by_name_pulls_by_number","summary":"Returns one pull request by its per-repo number.","description":"Returns one pull request by its per-repo number. A number belonging to\nanother tenant's repo is not found, exactly as the repo itself is not.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo, from the :name path segment.","schema":{"type":"string"},"example":"widgets"},{"name":"number","in":"path","required":true,"description":"Number is the proposal's per-repo number, from the :number path segment.","schema":{"format":"int64","type":"integer"},"example":4}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/git.pullView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/repos/{name}/pulls/{number}/merge":{"post":{"operationId":"post_git_repos_by_name_pulls_by_number_merge","summary":"Merges an open pull request by FAST-FORWARDING base to head, and answers the proposal in its merged state with the revision base now points at.","description":"Merges an open pull request by FAST-FORWARDING base to head, and\nanswers the proposal in its merged state with the revision base now points at.\n\nIt merges only when base is already an ancestor of head — the case where head\ncontains every commit base has, so moving the branch loses nothing and invents\nnothing. When base has moved on independently, this REFUSES with 409 and says\nso: a real three-way merge is not implemented here, and reporting one would\nclaim a result these bytes do not produce. Rebase head onto base and merge\nagain.\n\nThe move is judged by the same ref policy a `git push` of it would face, and\nfires the same build and notify reactions, so merging is not a way around\neither. Merging an already-merged proposal is a 409.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo, from the :name path segment.","schema":{"type":"string"},"example":"widgets"},{"name":"number","in":"path","required":true,"description":"Number is the proposal's per-repo number, from the :number path segment.","schema":{"format":"int64","type":"integer"},"example":4}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/git.pullView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/repos/{name}/push":{"post":{"operationId":"post_git_repos_by_name_push","summary":"Lands a set of files as one commit without a git client — the hanzo.app builder's push.","description":"Lands a set of files as one commit without a git client — the\nhanzo.app builder's push. The repo is CREATED on first push, the files are\nmerged onto the branch tip (unlisted files survive), and the same\npush-to-deploy hook a real receive-pack fires is fired, so downstream this is\nindistinguishable from a `git push`.\n\nIt is for generated content. Changing CI through it needs an org admin (403\notherwise), and a workflow whose newest change came in through it is not run\nautomatically; CI written through git runs as usual.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo to push into, from the :name path segment. It is CREATED\non first push if it does not exist.","schema":{"type":"string"},"example":"widgets"}],"requestBody":{"content":{"application/json":{"example":{"branch":"main","files":[{"content":"\u003ch1\u003ehi\u003c/h1\u003e","path":"index.html"}],"message":"generated build","name":"widgets"},"schema":{"$ref":"#/components/schemas/git.pushReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"branch":"main","cloneUrl":"https://api.hanzo.ai/v1/git/acme/widgets.git","commit":"a1b2c3d4e5f6","sshUrl":"git@git.hanzo.ai:acme/widgets.git"},"schema":{"$ref":"#/components/schemas/git.pushResp"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/repos/{name}/readme":{"get":{"operationId":"get_git_repos_by_name_readme","summary":"Returns the README at the tree root as plain text — unrendered, so the caller decides how to present it.","description":"Returns the README at the tree root as plain text — unrendered, so\nthe caller decides how to present it. A repo with no README is not found.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo to read, from the :name path segment.","schema":{"type":"string"},"example":"widgets"},{"name":"ref","in":"query","required":false,"description":"Ref is a branch, tag or commit; empty means the repo's HEAD.","schema":{"type":"string"},"example":"main"}],"responses":{"200":{"content":{"application/json":{"example":{"content":"# widgets\n","encoding":"utf8","path":"README.md"},"schema":{"$ref":"#/components/schemas/git.readmeJSON"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/repos/{name}/refs":{"get":{"operationId":"get_git_repos_by_name_refs","summary":"Lists a repo's branches, tags and default branch — what a branch picker needs in one call.","description":"Lists a repo's branches, tags and default branch — what a branch\npicker needs in one call. Unlike the other read ops it tolerates a repo with no\ncommits: the ref sets come back empty and the default branch is still named.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo's org-unique handle, from the :name path segment. A\ntrailing \".git\" is stripped.","schema":{"type":"string"},"example":"widgets"}],"responses":{"200":{"content":{"application/json":{"example":{"branches":[{"name":"main","sha":"a1b2c3d4"}],"default":"main","tags":[]},"schema":{"$ref":"#/components/schemas/git.refsJSON"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/repos/{name}/subscriptions":{"get":{"operationId":"get_git_repos_by_name_subscriptions","summary":"Returns a repo's Slack subscriptions — which channels the lifecycle notifier posts this repo's push and deploy events to.","description":"Returns a repo's Slack subscriptions — which channels the\nlifecycle notifier posts this repo's push and deploy events to.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo's org-unique handle, from the :name path segment. A\ntrailing \".git\" is stripped.","schema":{"type":"string"},"example":"widgets"}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"channel":"#builds","createdAt":"2026-07-01T10:00:00Z","events":["push.landed"],"id":"sub_7c2e","repo":"widgets"}]},"schema":{"$ref":"#/components/schemas/git.subscriptionList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true},"post":{"operationId":"post_git_repos_by_name_subscriptions","summary":"Binds a Slack channel to a repo, so the lifecycle notifier posts that repo's push and deploy events there.","description":"Binds a Slack channel to a repo, so the lifecycle notifier posts\nthat repo's push and deploy events there. Answers 201. The same channel twice\non one repo is a 409; a repo outside the caller's scope is a 404, exactly as\nreading it is.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo to subscribe, from the :name path segment.","schema":{"type":"string"},"example":"widgets"}],"requestBody":{"content":{"application/json":{"example":{"channel":"#builds","events":["push.landed"],"name":"widgets"},"schema":{"$ref":"#/components/schemas/git.subscribeReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/git.subscriptionView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/repos/{name}/subscriptions/{id}":{"delete":{"operationId":"delete_git_repos_by_name_subscriptions_by_id","summary":"Removes one Slack subscription from a repo; the notifier stops posting that repo's events to that channel.","description":"Removes one Slack subscription from a repo; the notifier stops\nposting that repo's events to that channel. Answers 204 with no body. An id\nthat is not this repo's subscription is not found.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo, from the :name path segment.","schema":{"type":"string"},"example":"widgets"},{"name":"id","in":"path","required":true,"description":"ID is the row to remove, from the :id path segment.","schema":{"type":"string"},"example":"sub_7c2e"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/repos/{name}/targets":{"get":{"operationId":"get_git_repos_by_name_targets","summary":"Returns a repo's outbound mirror targets — the downstream remotes the mirror reactor pushes to whenever a push lands here.","description":"Returns a repo's outbound mirror targets — the downstream remotes\nthe mirror reactor pushes to whenever a push lands here.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo's org-unique handle, from the :name path segment. A\ntrailing \".git\" is stripped.","schema":{"type":"string"},"example":"widgets"}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"createdAt":"2026-07-01T10:00:00Z","host":"github.com","id":"mir_2d90","repo":"widgets","url":"https://github.com/acme/widgets.git"}]},"schema":{"$ref":"#/components/schemas/git.mirrorList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true},"post":{"operationId":"post_git_repos_by_name_targets","summary":"Registers a downstream remote the repo's advanced refs are pushed to whenever a push lands here.","description":"Registers a downstream remote the repo's advanced refs are pushed to\nwhenever a push lands here. Answers 201. The URL must be https to a host on the\nmirror allowlist (github.com / gitlab.com): the same set the mirror credential\nmay be sent to, so a target can never capture the shared token or point the push\nat an internal service. Any embedded userinfo is stripped — credentials ride\nenv-only at push time and never enter the stored URL. One mirror per host per\nrepo; a second is a 409.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo whose advanced refs are pushed downstream, from the :name\npath segment.","schema":{"type":"string"},"example":"widgets"}],"requestBody":{"content":{"application/json":{"example":{"name":"widgets","url":"https://github.com/acme/widgets.git"},"schema":{"$ref":"#/components/schemas/git.mirrorTargetReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/git.mirrorTargetView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/repos/{name}/targets/{id}":{"delete":{"operationId":"delete_git_repos_by_name_targets_by_id","summary":"Removes one outbound mirror target; later pushes stop being forwarded to it.","description":"Removes one outbound mirror target; later pushes stop being\nforwarded to it. Answers 204 with no body. Nothing is done to the downstream\nremote itself — only this repo's intent to push there is dropped.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo, from the :name path segment.","schema":{"type":"string"},"example":"widgets"},{"name":"id","in":"path","required":true,"description":"ID is the row to remove, from the :id path segment.","schema":{"type":"string"},"example":"mir_2d90"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/repos/{name}/tree":{"get":{"operationId":"get_git_repos_by_name_tree","summary":"Lists the immediate children of one directory at one revision, directories before files.","description":"Lists the immediate children of one directory at one revision,\ndirectories before files. It does not recurse — walk down a level at a time.\nA repository in the organization's own code workspace on the forge is listed\nfrom there.","tags":["git"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the repo to read, from the :name path segment.","schema":{"type":"string"},"example":"widgets"},{"name":"ref","in":"query","required":false,"description":"Ref is a branch, tag or commit; empty means the repo's HEAD.","schema":{"type":"string"},"example":"main"},{"name":"path","in":"query","required":false,"description":"Path is repo-relative; empty is the tree root. Traversal is stripped.","schema":{"type":"string"},"example":"cmd"}],"responses":{"200":{"content":{"application/json":{"example":{"entries":[{"mode":"040000","name":"server","path":"cmd/server","size":0,"type":"tree"}]},"schema":{"$ref":"#/components/schemas/git.treeJSON"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/runners":{"get":{"operationId":"get_git_runners","summary":"Returns the daemons registered into this org's pools, newest first, with when each was last heard from.","description":"Returns the daemons registered into this org's pools, newest\nfirst, with when each was last heard from.","tags":["git"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/git.runnerList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/runs":{"get":{"operationId":"get_git_runs","summary":"Returns this org's runs, newest first.","description":"Returns this org's runs, newest first.","tags":["git"],"parameters":[{"name":"repo","in":"query","required":false,"description":"Repo restricts the listing to one repository. Empty lists the whole org.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps the answer; 0 means the default of 50, and 200 is the ceiling.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/git.workflowRuns"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true},"post":{"operationId":"post_git_runs","summary":"Runs a repository's workflows at a ref, on demand.","description":"Runs a repository's workflows at a ref, on demand.\n\nIt takes the SAME path a push takes: the request is recorded in the journal\nand delivered from there, so an explicit run and a pushed one are one\nmechanism with one idempotency rule and not two that can disagree. Asking\ntwice for the same commit yields the same run.","tags":["git"],"requestBody":{"content":{"application/json":{"example":{"ref":"main","repo":"widgets"},"schema":{"$ref":"#/components/schemas/git.runStart"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/git.workflowRuns"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/runs/{id}":{"get":{"operationId":"get_git_runs_by_id","summary":"Returns one run.","description":"Returns one run.","tags":["git"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the run to read, from the :id path segment.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/git.workflowRun"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/usage":{"get":{"operationId":"get_git_usage","summary":"Returns per-repo and total storage bytes for the caller's org — the queryable, per-tenant number commerce and o11y meter on.","description":"Returns per-repo and total storage bytes for the caller's org — the\nqueryable, per-tenant number commerce and o11y meter on. It spans EVERY\nproject sub-scope, unlike the repo list, so a billing consumer sees the whole\ntenant footprint in one call. Sizes are last-measured values (create, push,\nmirror and gc each re-measure), not a live walk of the disk.","tags":["git"],"responses":{"200":{"content":{"application/json":{"example":{"org":"acme","repos":[{"name":"widgets","sizeBytes":4096},{"name":"site","project":"web","sizeBytes":8192}],"totalBytes":12288},"schema":{"$ref":"#/components/schemas/git.usageView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/webhook":{"post":{"operationId":"post_git_webhook","summary":"Retired — push-to-deploy has no inbound webhook","description":"GONE (410). Push-to-deploy is not triggered by an inbound webhook. A push into this host's own git server fires the builder in-process, and a repository whose canonical home is GitHub is delivered by the Hanzo Platform GitHub App to POST /v1/provider/github/webhook. The forge does not report a push over HTTP.\n\nEvery delivery answers 410 whatever it carries — this endpoint reads no body and authenticates nothing.\n\n410 rather than 404, because the address was real and its meaning moved, which is the distinction 410 carries. A 404 from this estate is ambiguous: Hanzo Git serves /v1, so /api/v1 404s too and reads as \"the API is switched off\". A retired endpoint says it is retired and names its replacement, so the answer carries its own fix.","tags":["git"],"x-app":"git","x-public":true}},"/v1/git/workflows":{"get":{"operationId":"get_git_workflows","summary":"Reports the workflows a repository declares at a ref and which declared pool would execute each job — the answer to \"would a push here run, and where\".","description":"Reports the workflows a repository declares at a ref and which\ndeclared pool would execute each job — the answer to \"would a push here run,\nand where\".","tags":["git"],"parameters":[{"name":"repo","in":"query","required":false,"description":"Repo is the repository whose workflows to read.","schema":{"type":"string"}},{"name":"ref","in":"query","required":false,"description":"Ref is the branch to read them at; empty means the default.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/git.workflowList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/workspace":{"post":{"operationId":"post_git_workspace","summary":"Sets the org's code workspace up for the caller and answers it: the namespace, made when the org has none, and the caller's forge account and seat there.","description":"Sets the org's code workspace up for the caller and answers it:\nthe namespace, made when the org has none, and the caller's forge account and\nseat there. Idempotent. The estate's namespace is answered from the closed\ntable and nobody is enrolled in it. A seat is a person's: an API key or an\napplication is refused, and a SuperAdmin acting in another org reads the\nworkspace as it is and makes nothing.","tags":["git"],"responses":{"200":{"content":{"application/json":{"example":{"login":"seat-ann","made":true,"owner":"acme"},"schema":{"$ref":"#/components/schemas/git.workspaceView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/git/{org}/{project}/{repo}/git-receive-pack":{"post":{"operationId":"post_git_by_org_by_project_by_repo_git-receive-pack","summary":"Accept a push, and turn it into a build","description":"The pack-transfer phase of a push, and the point at which a push becomes an EVENT. NEVER ANONYMOUS: a push always requires an authenticated org, and the org in the path must equal it.\n\nOnce the pack is on disk the repository's storage usage is metered and a build is fired for every branch whose tip actually moved, computed from the before/after branch diff rather than from what the client claimed. That runs on a cancel-immune context, so a client that hangs up the moment its push lands still gets its build, and it runs even when git itself exited non-zero — the refs on disk are the ground truth. Repacking housekeeping is detached and never blocks the response.\n\nA Content-Type other than `application/x-git-receive-pack-request` is 400. Addressed under the API prefix, with the PROJECT as a middle path segment: project scope otherwise rides a header a git client cannot send, so this path is the only usable remote for a project-scoped repository. This is git's own wire protocol, not an API call to make by hand: point a git client at the clone URL and it makes this request itself.","tags":["git"],"parameters":[{"name":"org","in":"path","required":true,"schema":{"type":"string"}},{"name":"project","in":"path","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/octet-stream":{"schema":{"format":"binary","type":"string"}}}},"x-app":"git","x-public":true}},"/v1/git/{org}/{project}/{repo}/git-upload-pack":{"post":{"operationId":"post_git_by_org_by_project_by_repo_git-upload-pack","summary":"Serve a clone or fetch","description":"The pack-transfer phase of a clone or fetch: the request and the response are git's binary pack protocol, streamed straight through git itself — request body to git's stdin, git's stdout to the response — so a multi-gigabyte clone never lands in this process's memory.\n\nA PUBLIC repository is fetched anonymously; a private one requires its own org, and a wrong or absent org is 404 rather than a hint that the repository exists. A Content-Type other than `application/x-git-upload-pack-request` is 400. Addressed under the API prefix, with the PROJECT as a middle path segment: project scope otherwise rides a header a git client cannot send, so this path is the only usable remote for a project-scoped repository. This is git's own wire protocol, not an API call to make by hand: point a git client at the clone URL and it makes this request itself.","tags":["git"],"parameters":[{"name":"org","in":"path","required":true,"schema":{"type":"string"}},{"name":"project","in":"path","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/octet-stream":{"schema":{"format":"binary","type":"string"}}}},"x-app":"git","x-public":true}},"/v1/git/{org}/{project}/{repo}/info/refs":{"get":{"operationId":"get_git_by_org_by_project_by_repo_info_refs","summary":"Advertise a repository's refs to a git client","description":"The ref-advertisement phase of git's smart-HTTP protocol — the first request a clone, a fetch and a push all make. `?service=` selects which: `git-upload-pack` advertises for a fetch, `git-receive-pack` for a push, and any other value is 400.\n\nANONYMOUS ONLY FOR FETCH, AND ONLY ON A PUBLIC REPOSITORY. The push advertisement always requires an authenticated org, and where a path org is present it must equal the authenticated one. A private repository reached without its org is 404, indistinguishable from one that does not exist. Addressed under the API prefix, with the PROJECT as a middle path segment: project scope otherwise rides a header a git client cannot send, so this path is the only usable remote for a project-scoped repository. This is git's own wire protocol, not an API call to make by hand: point a git client at the clone URL and it makes this request itself.","tags":["git"],"parameters":[{"name":"org","in":"path","required":true,"schema":{"type":"string"}},{"name":"project","in":"path","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"git","x-public":true}},"/v1/git/{org}/{repo}":{"get":{"operationId":"get_git_by_org_by_repo","summary":"Open a repository's home page","description":"A repository at a glance: its branches, the tree at the tip, its most recent commits, its README rendered, and the HTTPS and SSH clone URLs. `?ref=` selects a branch, tag or commit; the default branch is used when it is omitted. A repository with no commits yet renders its clone instructions rather than an error, which is what a caller who has just created one needs to see. A public repository is readable by anyone; a private one only by its own org. A repository that does not exist and one belonging to another org answer the SAME 404, so the page is never an existence oracle. This is a server-rendered browser page, not JSON — the console repo-browser reads the same repository through the JSON ops under /v1/git/repos. Repository names, paths and file contents all render through auto-escaping templates rather than being concatenated into HTML.","tags":["git"],"parameters":[{"name":"org","in":"path","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"git","x-public":true}},"/v1/git/{org}/{repo}/commits":{"get":{"operationId":"get_git_by_org_by_repo_commits","summary":"Read a repository's commit log","description":"The hundred most recent commits on one ref, each with its author, message and date. `?ref=` selects the branch, tag or commit, defaulting to the repository's default branch; an unknown one is 404. A public repository is readable by anyone; a private one only by its own org. A repository that does not exist and one belonging to another org answer the SAME 404, so the page is never an existence oracle. This is a server-rendered browser page, not JSON — the console repo-browser reads the same repository through the JSON ops under /v1/git/repos. Repository names, paths and file contents all render through auto-escaping templates rather than being concatenated into HTML.","tags":["git"],"parameters":[{"name":"org","in":"path","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"git","x-public":true}},"/v1/git/{org}/{repo}/git-receive-pack":{"post":{"operationId":"post_git_by_org_by_repo_git-receive-pack","summary":"Accept a push, and turn it into a build","description":"The pack-transfer phase of a push, and the point at which a push becomes an EVENT. NEVER ANONYMOUS: a push always requires an authenticated org, and the org in the path must equal it.\n\nOnce the pack is on disk the repository's storage usage is metered and a build is fired for every branch whose tip actually moved, computed from the before/after branch diff rather than from what the client claimed. That runs on a cancel-immune context, so a client that hangs up the moment its push lands still gets its build, and it runs even when git itself exited non-zero — the refs on disk are the ground truth. Repacking housekeeping is detached and never blocks the response.\n\nA Content-Type other than `application/x-git-receive-pack-request` is 400. Addressed under the API prefix, so `git clone https://\u003chost\u003e/v1/git/\u003corg\u003e/\u003crepo\u003e.git` works on any host the binary serves. This is git's own wire protocol, not an API call to make by hand: point a git client at the clone URL and it makes this request itself.","tags":["git"],"parameters":[{"name":"org","in":"path","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/octet-stream":{"schema":{"format":"binary","type":"string"}}}},"x-app":"git","x-public":true}},"/v1/git/{org}/{repo}/git-upload-pack":{"post":{"operationId":"post_git_by_org_by_repo_git-upload-pack","summary":"Serve a clone or fetch","description":"The pack-transfer phase of a clone or fetch: the request and the response are git's binary pack protocol, streamed straight through git itself — request body to git's stdin, git's stdout to the response — so a multi-gigabyte clone never lands in this process's memory.\n\nA PUBLIC repository is fetched anonymously; a private one requires its own org, and a wrong or absent org is 404 rather than a hint that the repository exists. A Content-Type other than `application/x-git-upload-pack-request` is 400. Addressed under the API prefix, so `git clone https://\u003chost\u003e/v1/git/\u003corg\u003e/\u003crepo\u003e.git` works on any host the binary serves. This is git's own wire protocol, not an API call to make by hand: point a git client at the clone URL and it makes this request itself.","tags":["git"],"parameters":[{"name":"org","in":"path","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/octet-stream":{"schema":{"format":"binary","type":"string"}}}},"x-app":"git","x-public":true}},"/v1/git/{org}/{repo}/info/refs":{"get":{"operationId":"get_git_by_org_by_repo_info_refs","summary":"Advertise a repository's refs to a git client","description":"The ref-advertisement phase of git's smart-HTTP protocol — the first request a clone, a fetch and a push all make. `?service=` selects which: `git-upload-pack` advertises for a fetch, `git-receive-pack` for a push, and any other value is 400.\n\nANONYMOUS ONLY FOR FETCH, AND ONLY ON A PUBLIC REPOSITORY. The push advertisement always requires an authenticated org, and where a path org is present it must equal the authenticated one. A private repository reached without its org is 404, indistinguishable from one that does not exist. Addressed under the API prefix, so `git clone https://\u003chost\u003e/v1/git/\u003corg\u003e/\u003crepo\u003e.git` works on any host the binary serves. This is git's own wire protocol, not an API call to make by hand: point a git client at the clone URL and it makes this request itself.","tags":["git"],"parameters":[{"name":"org","in":"path","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"git","x-public":true}},"/v1/graph":{"get":{"operationId":"graphRead","summary":"Lists the assertions recorded, every version, oldest first.","description":"Lists the assertions recorded, every version, oldest first.\n\nIt resolves nothing: a superseded claim and the one that superseded it both\nappear.\n\nTime: as_of keeps statements begun by that instant of the world and as_known\nkeeps what this plane had heard by then; either absent is no bound.","tags":["graph"],"parameters":[{"name":"entity","in":"query","required":false,"description":"Entity narrows to what was asserted ABOUT one entity. Absent matches every\nentity.","schema":{"type":"string"},"example":"acme/svc/api"},{"name":"relation","in":"query","required":false,"description":"Relation narrows to one relation. Absent matches every relation.","schema":{"type":"string"}},{"name":"value","in":"query","required":false,"description":"Value narrows to assertions pointing AT one value, which is how the edges\ninto an entity are read. A property's scalar is matched byte for byte and\nan edge's value by its key, folded as every key is.","schema":{"type":"string"}},{"name":"as_of","in":"query","required":false,"description":"AsOf bounds the read to statements begun by an instant of the world, RFC\n3339. Absent reads every instant.","schema":{"type":"string"}},{"name":"as_known","in":"query","required":false,"description":"AsKnown bounds the read to what this plane had heard by an instant, RFC\n3339. Absent reads everything it holds.","schema":{"type":"string"},"example":"2026-09-01T00:00:00Z"},{"name":"limit","in":"query","required":false,"description":"Limit caps how many assertions come back. Absent, zero, or anything above\nthe walk ceiling is the ceiling.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/graph.graphReadOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"graph","x-public":true,"x-tool":true},"post":{"operationId":"graphAssert","summary":"Records a batch of assertions and counts what became of each.","description":"Records a batch of assertions and counts what became of each.\n\nEach member is judged alone: one refusal does not discard the rest, and a\nmember this plane already holds is a duplicate, not a refusal. A batch with\nnothing admitted answers 400.\n\nTime: at and until are when the statement was so, which an as_of read is\nbounded by; the server stamps knowable, the later of seen and its own clock,\nwhich an as_known read is bounded by. Nothing is overwritten: a correction is\nthe statement filed again, and the version known latest speaks for it.","tags":["graph"],"requestBody":{"content":{"application/json":{"example":{"assertions":[{"at":"2026-09-01T00:00:00Z","confidence":0.9,"entity":"acme/svc/api","evidence":"wiki/api#1","names":true,"relation":"owner","source":"wiki/api","value":"acme/team/core"}]},"schema":{"$ref":"#/components/schemas/graph.graphAssertIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/graph.graphAssertOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"graph","x-public":true,"x-tool":true}},"/v1/graph/answer":{"post":{"operationId":"graphAnswer","summary":"Answers a question from the whole graph and cites the assertions it rests on.","description":"Answers a question from the whole graph and cites the assertions it\nrests on.\n\nIt asks a model what each community's in-force facts say about the question,\nthen asks once more for one answer from those findings. Every cited ID is\nchecked to be a row of this graph, a failed model call fails the answer, and\nthe calls are billed to the calling organization.\n\nTime: as_of and as_known place the graph that is read; either absent is now.","tags":["graph"],"requestBody":{"content":{"application/json":{"example":{"question":"Which teams own the billing services?"},"schema":{"$ref":"#/components/schemas/graph.graphAnswerIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/graph.graphAnswerOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"graph","x-public":true,"x-tool":true}},"/v1/graph/communities":{"post":{"operationId":"graphCommunities","summary":"Partitions the edge graph into sets of entities more densely connected to each other than to the rest.","description":"Partitions the edge graph into sets of entities more densely\nconnected to each other than to the rest.\n\nThe graph is the one a walk reads, direction dropped, and the partition is\ndeterministic: the same graph at the same point numbers the same communities.\n\nTime: as_of and as_known place the graph that is partitioned; either absent is\nnow.","tags":["graph"],"requestBody":{"content":{"application/json":{"example":{"as_of":"2026-09-01T00:00:00Z"},"schema":{"$ref":"#/components/schemas/graph.graphCommunitiesIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/graph.graphCommunitiesOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"graph","x-public":true,"x-tool":true}},"/v1/graph/derive":{"post":{"operationId":"graphDerive","summary":"Concludes what the organization's rules derive from the graph, with a proof for every conclusion: the rule, and each support as the assertion in force it rests on or as the derived atom it is.","description":"Concludes what the organization's rules derive from the graph, with a\nproof for every conclusion: the rule, and each support as the assertion in\nforce it rests on or as the derived atom it is.\n\nThe rules are assertions — (`rule:\u003cname\u003e`, `rule`, `\u003ctext\u003e`), Datalog over\nthe organization's relations, with recursion, stratified negation and the\nbuiltins = and != — and the graph is read the way resolve reads it, so a\nretraction, an until and a declared cardinality all apply. Nothing derived is\nstored unless an admin asks to file it. Without names assertions to derive\nwithout, and the answer then says what would be lost, and what gained, if\nthey had never been filed.\n\nTime: as_of and as_known place the graph and the rules it is read with, as\nthey place a resolve; either absent is now. Filing takes neither: a filed\nconclusion holds from the instant it was derived.","tags":["graph"],"requestBody":{"content":{"application/json":{"example":{"as_of":"2026-09-01T00:00:00Z","predicates":["ancestor"]},"schema":{"$ref":"#/components/schemas/graph.graphDeriveIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/graph.graphDeriveOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"graph","x-public":true,"x-tool":true}},"/v1/graph/diff":{"post":{"operationId":"graphDiff","summary":"Reports what came into force, was superseded and was retracted between two points.","description":"Reports what came into force, was superseded and was retracted between\ntwo points.\n\nEach point is resolved as resolve would, never read off the rows in between.\nA version that loses the order is invisible here as it is there, and one that\nrepeats what held is agreement, not change.\n\nTime: a point is an as_of and an as_known instant, from and from_known against\nto and to_known. Hold the known instants equal for what happened in the world;\nhold the valid instants equal for what the record learned. to and to_known\ndefault to now, from to to and from_known to to_known, and the two points must\ndiffer.","tags":["graph"],"requestBody":{"content":{"application/json":{"example":{"entity":"acme/svc/api","from":"2026-08-01T00:00:00Z","to":"2026-09-01T00:00:00Z"},"schema":{"$ref":"#/components/schemas/graph.graphDiffIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/graph.graphDiffOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"graph","x-public":true,"x-tool":true}},"/v1/graph/erase":{"post":{"operationId":"graphErase","summary":"Removes every assertion that names an entity and returns a receipt.","description":"Removes every assertion that names an entity and returns a receipt.\n\nIt requires an admin of the organization it acts in; platform sudo is not\nenough, so erasure is never cross-tenant. Nothing is removed while a matching\nassertion is under litigation hold (409) or where the erasure cannot be\nrecorded (503). The audit trail keeps who, when, why, how many and the\nreceipt's digest, never the entity, and holds it before the erasure commits.\n\nTime: erasure is the one act outside the two times. The rows go at every\nas_of and as_known, so no past read recovers them.","tags":["graph"],"requestBody":{"content":{"application/json":{"example":{"entity":"acme/person/42","reason":"DSR-1187, GDPR Art. 17"},"schema":{"$ref":"#/components/schemas/graph.graphEraseIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/graph.graphEraseOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"graph","x-public":true,"x-tool":true}},"/v1/graph/extract":{"post":{"operationId":"graphExtract","summary":"Reads the relations a source states and returns them, recording nothing.","description":"Reads the relations a source states and returns them, recording\nnothing.\n\nA line `relation:: value` states one; a value written `[[key]]` names an\nentity and makes the relation an edge. The subject is the nearest heading\nabove the line, or the request's subject until a heading names one.\n\nWhat filing would refuse is returned apart, in refused: a declaration from a\ncaller who is not an admin of the organization, and what the declared schema\nrefuses, checked against the store and against the types and declarations the\ndocument itself states that the caller may file.\n\nTime: it records nothing and takes no as_of or as_known; the schema is checked\nas of now.","tags":["graph"],"requestBody":{"content":{"application/json":{"example":{"at":"2026-09-01T00:00:00Z","source":"wiki/api","text":"# acme/svc/api\nowner:: [[acme/team/core]]\ntier:: 1"},"schema":{"$ref":"#/components/schemas/graph.graphSourceIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/graph.graphExtractOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"graph","x-public":true,"x-tool":true}},"/v1/graph/graphql":{"get":{"operationId":"get_graph_graphql","summary":"Read the graph's GraphQL schema.","description":"Returns the schema POST at this address runs queries against, as GraphQL SDL: the five types the store models and the fields askable of each. It is what a code generator or an editor reads, and it is the same for every organization; what a query answers is scoped to the caller's.","tags":["graph"],"responses":{"2XX":{"content":{"text/plain; charset=utf-8":{"schema":{"format":"binary","type":"string"}}},"description":"Success"}},"x-app":"graph","x-public":true},"post":{"operationId":"post_graph_graphql","summary":"Ask the graph in one request, traversing.","description":"Runs a GraphQL query against this organization's assertions.\n\nIt is the one endpoint here a caller can TRAVERSE: the REST ops each answer a single question, so composing them — the entities this one points at, and what each of those resolves to — costs a request per hop with the intermediate keys held by the caller. Here that is one query and the nesting is the answer's shape.\n\nIt adds no way to ask anything new. Every field runs the SAME operation the matching REST route runs, so the tenancy, the as-of bound, the traversal bounds and the conflict rule are the ones already in force; the schema is served by GET at this same address, and introspection is not.\n\nA query that ran answers 200 with each failure in an `errors` list beside the data, which is the wire every GraphQL client parses; one that could not begin — it does not parse, or names a fragment it does not define — answers 400 with the reason and no data. `edges` nest at most three deep, refused before any operation runs, and one root field's edges answer at most 1000 entities.","tags":["graph"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/graphQLIn"}}}},"responses":{"2XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/graphQLOut"}}},"description":"Success"}},"x-app":"graph","x-public":true}},"/v1/graph/ingest":{"post":{"operationId":"graphIngest","summary":"Reads a source and records what it states, through the same admission as assert.","description":"Reads a source and records what it states, through the same\nadmission as assert.\n\nEach assertion's evidence is the section that stated it, `\u003csource\u003e#\u003csection\u003e`,\nso the same source at the same at records one set of rows however often it is\ndelivered. What extract reports refused is not recorded; it is counted as\nrefused, with its reason, in the order the document states it. A source\nstating no relation is refused whole.\n\nTime: at is the valid time of every assertion recorded, which an as_of read is\nbounded by; each becomes knowable at the write, so a read with an earlier\nas_known does not see it.","tags":["graph"],"requestBody":{"content":{"application/json":{"example":{"at":"2026-09-01T00:00:00Z","source":"wiki/api","text":"# acme/svc/api\nowner:: [[acme/team/core]]\ntier:: 1"},"schema":{"$ref":"#/components/schemas/graph.graphSourceIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/graph.graphAssertOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"graph","x-public":true,"x-tool":true}},"/v1/graph/neighbors":{"post":{"operationId":"graphNeighbors","summary":"Walks the in-force edges from a set of seeds and lists every entity reached, bounded.","description":"Walks the in-force edges from a set of seeds and lists every\nentity reached, bounded.\n\nOnly the edge that holds at the point is a hop: a superseded or retracted\nedge is not, and neither is a property.\n\nTime: as_of walks the graph as it stood at that instant and as_known as this\nplane knew it then; either absent is now.","tags":["graph"],"requestBody":{"content":{"application/json":{"example":{"depth":2,"relation":"depends","seeds":["acme/svc/api"]},"schema":{"$ref":"#/components/schemas/graph.graphNeighborsIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/graph.graphNeighborsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"graph","x-public":true,"x-tool":true}},"/v1/graph/path":{"post":{"operationId":"graphPath","summary":"Finds the shortest chain of in-force edges from one entity to another.","description":"Finds the shortest chain of in-force edges from one entity to another.\n\nIt is the walk behind neighbors stopped at a goal: the same bound and the same\nrule for which edge is in force. A causal chain is this op with relations\nnaming the relations that mean cause, such as caused_by and influenced.\n\nTime: as_of and as_known place the graph the path is found in; either absent\nis now.","tags":["graph"],"requestBody":{"content":{"application/json":{"example":{"direction":"both","from":"acme/svc/api","to":"acme/team/core"},"schema":{"$ref":"#/components/schemas/graph.graphPathIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/graph.graphPathOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"graph","x-public":true,"x-tool":true}},"/v1/graph/resolve":{"post":{"operationId":"graphResolve","summary":"Answers what holds for one entity and relation at a point, winner first, with every weaker account that disagreed.","description":"Answers what holds for one entity and relation at a point, winner\nfirst, with every weaker account that disagreed.\n\nThe winner is the holding statement begun most recently, then the strongest\nunder the rule vocabulary names. A relation that holds many values answers\neach; a disagreement is reported as contested, never resolved into silence.\n\nTime: as_of is the instant of the world asked about and as_known how much this\nplane had heard; either absent is now.","tags":["graph"],"requestBody":{"content":{"application/json":{"example":{"as_of":"2026-09-01T00:00:00Z","entity":"acme/svc/api","relation":"owner"},"schema":{"$ref":"#/components/schemas/graph.graphResolveIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/graph.graphResolveOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"graph","x-public":true,"x-tool":true}},"/v1/graph/search":{"get":{"operationId":"graphSearch","summary":"Finds assertions by their words, where read finds them by their keys, best match first.","description":"Finds assertions by their words, where read finds them by their keys,\nbest match first.\n\nEvery word must match, as a prefix. The answer is ordered by bm25, which\nweighs a word by how rare it is and a row by how much of it the words are, so\na limit keeps the best matches rather than the oldest. It resolves nothing, so\na match may be a claim later corrected; ask resolve about what it finds.\n\nTime: as_of and as_known bound it exactly as they bound read; either absent is\nno bound.","tags":["graph"],"parameters":[{"name":"q","in":"query","required":true,"description":"Q is what to look for: words, matched as prefixes, all of them required.\nPunctuation is text here rather than syntax, so an entity key searches as\nitself.","schema":{"type":"string"},"example":"billing owner"},{"name":"relation","in":"query","required":false,"description":"Relation narrows to one relation. Absent matches every relation.","schema":{"type":"string"}},{"name":"as_of","in":"query","required":false,"description":"AsOf bounds the search to statements begun by an instant of the world,\nRFC 3339. Absent searches every instant.","schema":{"type":"string"}},{"name":"as_known","in":"query","required":false,"description":"AsKnown bounds the search to what this plane had heard by an instant, RFC\n3339. Absent searches everything it holds.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many assertions come back. Absent, zero, or anything above\nthe walk ceiling is the ceiling.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/graph.graphReadOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"graph","x-public":true,"x-tool":true}},"/v1/graph/vocabulary":{"get":{"operationId":"graphVocabulary","summary":"Lists the relations in use, the schema declared for them and the rule that settles a conflict.","description":"Lists the relations in use, the schema declared for them and the\nrule that settles a conflict.\n\nTime: it takes no as_of or as_known; the schema is the one in force now.","tags":["graph"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/graph.graphVocabularyOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"graph","x-public":true,"x-tool":true}},"/v1/guide":{"get":{"operationId":"get_guide","summary":"Returns the caller org's launch journey: the active curriculum's version and title, every step with its state, whether it is available, what blocks it and whether the Business AI can run it, the done/total/percent progress with the next step to take, and the org's analytics funnel folded in.","description":"Returns the caller org's launch journey: the active curriculum's\nversion and title, every step with its state, whether it is available, what\nblocks it and whether the Business AI can run it, the done/total/percent\nprogress with the next step to take, and the org's analytics funnel folded in.\nAuto-detect runs first, so a step the org has already completed elsewhere reads\ndone without anyone marking it.","tags":["guide"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/guide.overviewView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"guide","x-public":true,"x-tool":true}},"/v1/guide/actions":{"get":{"operationId":"get_guide_actions","summary":"Returns the caller org's Business AI action ledger, most recent first: every \"do it for me\" tool call, the arguments it ran with, its result and whether it succeeded.","description":"Returns the caller org's Business AI action ledger, most recent\nfirst: every \"do it for me\" tool call, the arguments it ran with, its result and\nwhether it succeeded. It is the audit-visible record of what the agent did on\nthe org's behalf, and the backing state for the \"acted\" auto-detect signal.","tags":["guide"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/guide.actionsView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"guide","x-public":true,"x-tool":true}},"/v1/guide/analytics":{"get":{"operationId":"get_guide_analytics","summary":"Returns the caller org's funnel from the analytics lens plus the GTM recommendations derived from it.","description":"Returns the caller org's funnel from the analytics lens plus the GTM\nrecommendations derived from it. It is the Business AI's data-grounded read —\nwhat the funnel is doing, and the next-best action to move its weakest stage. An\nunreachable or silent warehouse answers available=false, never a fabricated\nnumber.","tags":["guide"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/guide.analyticsView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"guide","x-public":true,"x-tool":true}},"/v1/guide/chat":{"post":{"operationId":"post_guide_chat","summary":"Answers a founder's question about their launch journey as the Business AI coach: it grounds the reply in the org's REAL progress, its ranked available quests and its analytics funnel, and returns those candidate quests alongside so the caller can act on one.","description":"Answers a founder's question about their launch journey as the Business AI\ncoach: it grounds the reply in the org's REAL progress, its ranked available\nquests and its analytics funnel, and returns those candidate quests alongside so\nthe caller can act on one. READ-ONLY — it advises and never runs a step, so it\ncannot be talked into performing an action; the only executing path is POST\n/v1/guide/steps/{id}/do. One AI completion per call, billed to the caller's own\npayer.","tags":["guide"],"requestBody":{"content":{"application/json":{"example":{"message":"what should I do next to get my first customers?"},"schema":{"$ref":"#/components/schemas/guide.chatRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/guide.chatResponse"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"guide","x-public":true,"x-tool":true}},"/v1/guide/curriculum":{"delete":{"operationId":"delete_guide_curriculum","summary":"Clears the caller org's curriculum override and returns the journey it falls back to — the brand blueprint, else the embedded fixture.","description":"Clears the caller org's curriculum override and returns the\njourney it falls back to — the brand blueprint, else the embedded fixture.\nClearing an org that never set one is a no-op that answers the same default.","tags":["guide"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/guide.curriculumView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"guide","x-public":true,"x-tool":true},"get":{"operationId":"get_guide_curriculum","summary":"Returns the journey the caller's org is actually running, and whether it comes from the org's OWN override (custom) or from the platform default — the brand blueprint, else the embedded fixture.","description":"Returns the journey the caller's org is actually running, and\nwhether it comes from the org's OWN override (custom) or from the platform\ndefault — the brand blueprint, else the embedded fixture.","tags":["guide"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/guide.curriculumView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"guide","x-public":true,"x-tool":true},"put":{"operationId":"put_guide_curriculum","summary":"Replace your org's journey with a curriculum you author","description":"Sets the caller org's OWN curriculum — the per-customer override — and answers the journey now in force with `custom: true`. The body is a curriculum document, and it is accepted as YAML **or** JSON: that is the caller-visible reason this takes a raw body rather than a declared shape. Whatever the syntax, the CANONICAL parsed form is what is stored, so the document the engine runs never depends on how it was written.\n\nFail-closed: a body that does not parse, or parses but is not a valid journey (unique step ids, no dangling or cyclic dependencies), is 422 and NEVER becomes active — the org keeps the journey it had. Requires a validated org: 401 without a principal, 403 without an org. An empty body is 400 and one over 256 KiB is 413.\n\nThis is tier one only. It overrides nothing but this org's own journey; the shared brand blueprint is a different surface with a different gate. DELETE the same path to drop the override and fall back to it.","tags":["guide"],"x-app":"guide","x-public":true}},"/v1/guide/profile":{"get":{"operationId":"get_guide_profile","summary":"Returns the caller org's OBSERVED growth profile — the signal set, the classified growth stage, and the org's own key metrics.","description":"Returns the caller org's OBSERVED growth profile — the signal set, the\nclassified growth stage, and the org's own key metrics. It is a pure READ,\nrecomputed from the org's CURRENT state each request (real-time by pull): it\nreuses the reconcile path (snapshotFor runs the detectors) for launch progress\nand runs the growth probes (observe) for the signals — it never caches, never\nruns a billable effect, never targets another org. Org-scoped on the validated\nprincipal; fail-closed without one. It PRODUCES the profile and classifies the\nstage; it decides NO recommendation (that is a later surface).","tags":["guide"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/guide.profileResponse"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"guide","x-public":true,"x-tool":true}},"/v1/guide/steps/{id}/do":{"post":{"operationId":"post_guide_steps_by_id_do","summary":"Have the Business AI actually do the step for you","description":"Executes one step of the caller org's journey through that principal's OWN tool plane and answers the action log — `{step, events, state}` — so the caller sees every tool call the agent made and where the step ended up. This is the ONE executing path in guide: suggest and chat advise, this acts, and the work is charged to the calling principal's ledger.\n\nAsk for it live and the same actions arrive as Server-Sent Events instead, on either of two triggers — `Accept: text/event-stream` or `?stream=1`. The stream opens with a comment, emits one frame per action as it happens, and closes with an `end` frame carrying `ok` and the final state. The streamed run is detached and bounded at 120 seconds, so it finishes on its own clock once the response has begun.\n\nAn agent that FAILS is not a failed request: the JSON answer still comes back 200 with `error` beside the events it did manage, and the stream still ends with `ok:false`. The refusals are the ones before the agent runs — 409 with `{error, step, blockedBy}` for a step whose dependencies are unfinished, 404 for an id the journey does not contain, 401 without a principal and 403 without an org.","tags":["guide"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"guide","x-public":true}},"/v1/guide/steps/{id}/done":{"post":{"operationId":"post_guide_steps_by_id_done","summary":"Marks one step of the caller org's journey complete and returns the refreshed journey.","description":"Marks one step of the caller org's journey complete and returns the\nrefreshed journey.\n\nDependency-GATED, exactly as start is: a step whose prerequisites are unfinished\nis refused 409 carrying {error, step, blockedBy} naming what is in the way.","tags":["guide"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the step's id, as it appears in the journey (e.g. \"gsuite\").","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/guide.overviewView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"guide","x-public":true,"x-tool":true}},"/v1/guide/steps/{id}/reset":{"post":{"operationId":"post_guide_steps_by_id_reset","summary":"Returns one step of the caller org's journey to todo — clearing a manual mark or a skip — and returns the refreshed journey.","description":"Returns one step of the caller org's journey to todo — clearing a\nmanual mark or a skip — and returns the refreshed journey. Reset is never\ndependency-gated. Auto-detect runs on the next read, so a step the org has in\nfact completed elsewhere goes straight back to done.","tags":["guide"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the step's id, as it appears in the journey (e.g. \"gsuite\").","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/guide.overviewView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"guide","x-public":true,"x-tool":true}},"/v1/guide/steps/{id}/skip":{"post":{"operationId":"post_guide_steps_by_id_skip","summary":"Marks one step of the caller org's journey skipped and returns the refreshed journey.","description":"Marks one step of the caller org's journey skipped and returns the\nrefreshed journey. Skipping is never dependency-gated — the founder is\ndeclaring the step does not apply to them — so a step whose dependencies are\nunfinished can still be skipped, and a skipped step counts as terminal for\neverything downstream of it.","tags":["guide"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the step's id, as it appears in the journey (e.g. \"gsuite\").","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/guide.overviewView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"guide","x-public":true,"x-tool":true}},"/v1/guide/steps/{id}/start":{"post":{"operationId":"post_guide_steps_by_id_start","summary":"Marks one step of the caller org's journey in progress and returns the refreshed journey.","description":"Marks one step of the caller org's journey in progress and returns the\nrefreshed journey.\n\nDependency-GATED: a step whose prerequisites are unfinished is refused 409\ncarrying {error, step, blockedBy}, where blockedBy names the exact steps in the\nway — enough to render the reason without asking again.","tags":["guide"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the step's id, as it appears in the journey (e.g. \"gsuite\").","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/guide.overviewView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"guide","x-public":true,"x-tool":true}},"/v1/guide/strategies":{"get":{"operationId":"get_guide_strategies","summary":"Returns the ENABLED tactics corpus for the caller's org: the tactics library narrowed by the explicit category/workload filters AND by the org's OBSERVED growth stage and capability signals (a tactic's tags are preconditions, so it surfaces only once the org can act on it).","description":"Returns the ENABLED tactics corpus for the caller's org: the tactics\nlibrary narrowed by the explicit category/workload filters AND by the org's\nOBSERVED growth stage and capability signals (a tactic's tags are\npreconditions, so it surfaces only once the org can act on it). Passing stage\nPREVIEWS the corpus at that stage instead of the observed one. The content is\nshared platform data — no org's records — and the read is never a billable\neffect.","tags":["guide"],"parameters":[{"name":"category","in":"query","required":false,"description":"Category filters to tactics in exactly this category.","schema":{"type":"string"},"example":"viral-coefficient"},{"name":"stage","in":"query","required":false,"description":"Stage previews the corpus at a chosen growth stage\n(research|formed|launched|activated|scaling), overriding the org's observed\none. An unknown value is ignored and the observed stage stands.","schema":{"type":"string"},"example":"scaling"},{"name":"workload","in":"query","required":false,"description":"Workload filters to tactics with exactly this workload.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/guide.corpusView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"guide","x-public":true,"x-tool":true}},"/v1/guide/suggest":{"get":{"operationId":"get_guide_suggest","summary":"Returns the caller org's next-best quests: the available, non-terminal steps of its journey ranked by how much downstream work each unblocks, each with the grounded reason it is a good next move and whether the Business AI can run it, plus the org's funnel and the GTM recommendations derived from it.","description":"Returns the caller org's next-best quests: the available, non-terminal\nsteps of its journey ranked by how much downstream work each unblocks, each with\nthe grounded reason it is a good next move and whether the Business AI can run\nit, plus the org's funnel and the GTM recommendations derived from it. A\nbest-effort AI narrative over exactly those quests and numbers is included when\nan AI plane is wired. READ-ONLY: it advises and never runs a step — the only\nexecuting path is POST /v1/guide/steps/{id}/do.","tags":["guide"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/guide.suggestResponse"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"guide","x-public":true,"x-tool":true}},"/v1/help/articles":{"get":{"operationId":"get_help_articles","summary":"Returns the public knowledge base: the help center's Published, publicly-visible articles as cards.","description":"Returns the public knowledge base: the help center's Published,\npublicly-visible articles as cards. The org is server-fixed and the\nstatus/is_public filter is server-set, so neither the tenant nor the visibility\ncan be widened by the caller. A deployment with no help center answers 404, and\none whose center has not installed the Help model answers an empty list.","tags":["help"],"parameters":[{"name":"category","in":"query","required":false,"description":"Category narrows the list to one knowledge-base section, matched against\nthe article's category by exact name. Empty lists every section.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many articles are returned. Anything that is not a positive\ninteger uses 50, and values above 200 are clamped to 200.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/help.helpArticleList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"help","x-public":true,"x-tool":true}},"/v1/help/articles/{slug}":{"get":{"operationId":"get_help_articles_by_slug","summary":"Returns one public article by slug, with its body.","description":"Returns one public article by slug, with its body. A missing, Draft,\nor internal (non-public) article is 404 — fail-closed, so this route is no\nexistence oracle for anything beyond \"published and public\".","tags":["help"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the article's public identifier, from the path. It IS the document\nname in the help center's store.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/help.helpArticle"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"help","x-public":true,"x-tool":true}},"/v1/help/categories":{"get":{"operationId":"get_help_categories","summary":"Returns the knowledge-base sections for the public center's navigation — but ONLY the sections that front at least one Published, public article, so an internal (agent-only) category name or description never leaks.","description":"Returns the knowledge-base sections for the public center's\nnavigation — but ONLY the sections that front at least one Published, public\narticle, so an internal (agent-only) category name or description never leaks. A\nsection with no public article is invisible; a center with no public articles has\nno sections, which is an empty list rather than an error — as is a center that\nhas not installed the Help model.","tags":["help"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/help.helpCategoryList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"help","x-public":true,"x-tool":true}},"/v1/help/tickets":{"post":{"operationId":"post_help_tickets","summary":"Files a customer support ticket into the public help center.","description":"Files a customer support ticket into the public help center. It\ncreates the ticket (status Open, source portal) with the customer's message on\nthe description, then records that same message as the opening entry of the\nticket's conversation thread; the description carries it regardless, so failing\nto write that entry loses nothing. Answers 201 with an opaque reference.\n\nA deployment with no help center answers 404, one whose center has not installed\nthe Help model answers 503, and a body over 64 KiB answers 413 — in that order,\nwhich is the order the route has always decided them in.","tags":["help"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/help.helpTicketIntake"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/help.helpTicketFiled"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"help","x-public":true,"x-tool":true}},"/v1/iam/.well-known/jwks":{"get":{"operationId":"get_iam_.well-known_jwks","summary":"Publishes the public keys that verify the tokens issued here — the one URL you point a service at so it can check a token itself, offline, without calling back and without holding any secret of ours.","description":"Publishes the public keys that verify the tokens issued here — the\none URL you point a service at so it can check a token itself, offline, without\ncalling back and without holding any secret of ours.\n\nKeys appear here before they start signing and stay after they stop, so a\nrotation never leaves a live token unverifiable. Nothing private is ever\npublished.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/.well-known/oauth-authorization-server":{"get":{"operationId":"get_iam_.well-known_oauth-authorization-server","summary":"Returns the OpenID Connect discovery document — the one URL you point a standards-compliant client at so it can find every other endpoint on its own, instead of you configuring them by hand.","description":"Returns the OpenID Connect discovery document — the one URL you\npoint a standards-compliant client at so it can find every other endpoint on\nits own, instead of you configuring them by hand.\n\nIt advertises only what is actually implemented, so a client that reads it\ncannot ask for a flow that will fail: the authorization-code flow, PKCE with\nS256, the supported grants, and the signing algorithms whose public keys the\nJWKS really publishes.\n\nThe issuer is derived from the host you asked on and is the same value the\ntokens carry, so a client that pins the issuer never sees it change.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/.well-known/openid-configuration":{"get":{"operationId":"get_iam_.well-known_openid-configuration","summary":"Returns the OpenID Connect discovery document — the one URL you point a standards-compliant client at so it can find every other endpoint on its own, instead of you configuring them by hand.","description":"Returns the OpenID Connect discovery document — the one URL you\npoint a standards-compliant client at so it can find every other endpoint on\nits own, instead of you configuring them by hand.\n\nIt advertises only what is actually implemented, so a client that reads it\ncannot ask for a flow that will fail: the authorization-code flow, PKCE with\nS256, the supported grants, and the signing algorithms whose public keys the\nJWKS really publishes.\n\nThe issuer is derived from the host you asked on and is the same value the\ntokens carry, so a client that pins the issuer never sees it change.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/account":{"get":{"operationId":"get_iam_account","summary":"Returns the signed-in person's own account and the organization they belong to — what a console reads to draw the account menu.","description":"Returns the signed-in person's own account and the organization\nthey belong to — what a console reads to draw the account menu.\n\nPasswords, API secrets and MFA material are stripped. It answers for a session\ncookie or a bearer token alike.","tags":["iam"],"x-app":"iam","x-public":true},"put":{"operationId":"put_iam_account","summary":"Saves the calling person's own profile — the name they are shown by, their picture, a line about themselves and a link.","description":"Saves the calling person's own profile — the name they are\nshown by, their picture, a line about themselves and a link.\n\nOnly their own: the request names nobody, so it cannot reach another account.\nSend only what you are changing; a field you leave out keeps the value it had,\nand a field you send empty is cleared.\n\nA picture is an https link or an inline image up to 96 KiB, the same value an\norganization's mark is (schema.AvatarRef) — one rule for how a subject appears,\nwhether the subject is a person or an organization.","tags":["iam"],"parameters":[{"name":"Cookie","in":"header","required":false,"schema":{"type":"string"}},{"name":"Authorization","in":"header","required":false,"schema":{"type":"string"}},{"name":"Sec-Fetch-Site","in":"header","required":false,"schema":{"type":"string"}},{"name":"Origin","in":"header","required":false,"schema":{"type":"string"}},{"name":"Host","in":"header","required":false,"schema":{"type":"string"}},{"name":"Content-Type","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.accountBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"ok"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"bad request"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"forbidden"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/accounts":{"get":{"operationId":"get_iam_accounts","summary":"Returns the people signed in on this browser, the most recent sign-in first — what the sign-in page lists when an application asks the person to choose an account.","description":"Returns the people signed in on this browser, the most recent\nsign-in first — what the sign-in page lists when an application asks the person\nto choose an account.\n\nIt reads the session cookie and nothing else, so it only ever answers the\nbrowser holding the sessions. An account forbidden or deleted since it signed\nin is left out. A browser with nobody signed in gets an empty list.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/admin/applications/upsert":{"post":{"operationId":"upsertApplication","summary":"Creates an application or updates it in place, so a deployment can declare the applications it needs and run the same declaration on every environment and on every redeploy.","description":"Creates an application or updates it in place, so a\ndeployment can declare the applications it needs and run the same declaration\non every environment and on every redeploy.\n\nIt says which of the two it did. Leave the client secret out and the existing\none is kept — so re-running your deployment does not rotate a credential your\nrunning services are holding.","tags":["iam"],"parameters":[{"name":"Authorization","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.registration"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.reply"}}},"description":"ok"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.reply"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.reply"}}},"description":"unauthorized"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.reply"}}},"description":"conflict"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.reply"}}},"description":"internal server error"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/admin/provision":{"post":{"operationId":"post_iam_admin_provision","summary":"Founds an org on someone's behalf — the same onboarding a person gets themselves, driven by one of your own services instead of by them.","description":"Founds an org on someone's behalf — the same onboarding\na person gets themselves, driven by one of your own services instead of by\nthem. The person keeps their account and owns the org by membership.\n\nIt authenticates as your service rather than as a person, which is why the\nperson to provision is named in the request. The setup it performs is\nidentical to self-service onboarding; there is one provisioning path, not\ntwo that can drift.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/admin/users/upsert":{"post":{"operationId":"upsertUser","summary":"Creates a person or updates them in place, so a deployment can declare the accounts it needs and re-run that declaration safely.","description":"Creates a person or updates them in place, so a deployment can\ndeclare the accounts it needs and re-run that declaration safely.\n\nIt DESCRIBES an account it meets and GRANTS only to one it creates: org-admin is\nnever raised on a row that already exists, and a machine identity is answered by\nname rather than adopted. Both are properties of the update itself, so a\nsteady-state reconcile — which changes neither — is unaffected.\n\nPasswords are hashed before they are stored. Leave the password out and their\ncurrent one is kept, so a redeploy never locks somebody out; send the same one\nagain and it is kept too, so a steady-state re-run is not a rotation.\n\nA SuperAdmin's password, email and phone are set when the account is created\nand kept on every run after.","tags":["iam"],"parameters":[{"name":"Authorization","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.person"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.reply"}}},"description":"ok"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.reply"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.reply"}}},"description":"unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.reply"}}},"description":"internal server error"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/applications":{"get":{"operationId":"get_iam_applications","summary":"Returns the applications in one organization, newest first — each product or site your people sign in to, with the sign-in methods and redirect URIs it allows.","description":"Returns the applications in one organization, newest first —\neach product or site your people sign in to, with the sign-in methods and\nredirect URIs it allows.","tags":["iam"],"parameters":[{"name":"owner","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.ApplicationListResult"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"post":{"operationId":"post_iam_applications","summary":"Registers an application in your organization — one product or site your people sign in to, with its own client credentials, sign-in methods and allowed redirect URIs.","description":"Registers an application in your organization — one product or site\nyour people sign in to, with its own client credentials, sign-in methods and\nallowed redirect URIs. A name already used in the organization is refused\nrather than overwritten. An application that serves other organizations —\nisShared, or any orgChoiceMode but \"\" and \"None\" — is created by a SuperAdmin\nonly.\n\nExported so the legacy add-application alias reuses this exact path — one\ncreate, two spellings.","tags":["iam"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Application"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Application"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/applications/{owner}/{name}":{"delete":{"operationId":"delete_iam_applications_by_owner_by_name","summary":"Removes an application.","description":"Removes an application. Anyone mid-sign-in through it is\nturned away and its client credentials stop working, so retire the integration\nbefore deleting it.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.DeleteResult"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"get":{"operationId":"get_iam_applications_by_owner_by_name","summary":"Returns one application: its sign-in methods, its allowed redirect URIs and the client credentials your integration authenticates with.","description":"Returns one application: its sign-in methods, its allowed\nredirect URIs and the client credentials your integration authenticates with.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Application"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"put":{"operationId":"put_iam_applications_by_owner_by_name","summary":"Changes an application's display, its sign-in methods and the redirect URIs it may return to — the call that makes login work from a new host.","description":"Changes an application's display, its sign-in methods and the redirect\nURIs it may return to — the call that makes login work from a new host. Which\norganization it belongs to and what it is named are fixed when it is created\nand are not editable here. An application that serves other organizations —\nisShared, or any orgChoiceMode but \"\" and \"None\" — is written by a SuperAdmin\nonly, before and after the change.\n\nExported so the legacy update-application alias reuses this exact path — one\nupdate, two spellings.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Application"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Application"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/audit-logs":{"get":{"operationId":"get_iam_audit-logs","summary":"Returns your organization's audit trail, newest first — who did what, when, and from where.","description":"Returns your organization's audit trail, newest first — who did\nwhat, when, and from where. It is the record you reach for during a security\nreview or an incident.\n\nYou see your own organization's audit trail and no one else's; which organization that\nis comes from your credentials, not from the request.","tags":["iam"],"parameters":[{"name":"owner","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.auditlogs.ListOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"post":{"operationId":"post_iam_audit-logs","summary":"Records an audit entry, so activity from your own systems lands in the same trail as everything the Hanzo Cloud records for you.","description":"Records an audit entry, so activity from your own systems lands in the\nsame trail as everything the Hanzo Cloud records for you.","tags":["iam"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.auditlogs.Input"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.AuditLog"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/audit-logs/{owner}/{name}":{"delete":{"operationId":"delete_iam_audit-logs_by_owner_by_name","summary":"Removes an audit entry.","description":"Removes an audit entry. Retention policy is normally what should expire\na trail; deleting by hand leaves a gap a reviewer will notice.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.auditlogs.DeleteOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"get":{"operationId":"get_iam_audit-logs_by_owner_by_name","summary":"Returns one audit entry in full: the action, the person or key behind it, and the request it came in on.","description":"Returns one audit entry in full: the action, the person or key behind it,\nand the request it came in on.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.AuditLog"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"put":{"operationId":"put_iam_audit-logs_by_owner_by_name","summary":"Corrects an audit entry.","description":"Corrects an audit entry. The trail is append-only in normal operation\nand nothing in the Hanzo Cloud rewrites it — this exists for an administrator\nto correct an entry their own systems recorded wrongly.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.auditlogs.Input"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.AuditLog"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/auth/application":{"get":{"operationId":"get_iam_auth_application","summary":"Returns everything a login screen needs to draw itself for one application: its branding, and each sign-in method it offers with the provider details that method needs.","description":"Returns everything a login screen needs to draw itself for one\napplication: its branding, and each sign-in method it offers with the provider\ndetails that method needs.\n\nThe client secret is masked. Read before anyone has signed in, so it carries\nonly what is safe for a browser to see.","tags":["iam"],"parameters":[{"name":"clientId","in":"query","required":false,"description":"ClientId is the application's OAuth client id — the one field that selects\nwhich login screen this is.","schema":{"type":"string"}},{"name":"responseType","in":"query","required":false,"description":"ResponseType is the OAuth response type the screen will ask for. Only \"code\"\nis served; anything else is refused here rather than at the authorize leg,\nwhere the person has already typed a password.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"ok"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"bad request"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/auth/identifier":{"post":{"operationId":"post_iam_auth_identifier","summary":"Answers whether an account holds an email address at an application, and whether that account signs in with a password.","description":"Answers whether an account holds an email address at an\napplication, and whether that account signs in with a password. Only an\napplication that registers strangers answers, since its signup says as much\nalready. The address is resolved exactly as sign-in resolves it, so the screen\nand the sign-in cannot disagree. A client asking faster than a person types is\nrefused with 429.","tags":["iam"],"parameters":[{"name":"CF-Connecting-IP","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-Forwarded-For","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.identifierBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"ok"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"bad request"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"too many requests"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/auth/methods":{"get":{"operationId":"get_iam_auth_methods","summary":"Returns the sign-in methods one application actually has switched on, so a login screen can render the right buttons for it without you hard-coding a list that drifts the moment you add a provider.","description":"Returns the sign-in methods one application actually has switched\non, so a login screen can render the right buttons for it without you\nhard-coding a list that drifts the moment you add a provider.\n\nPublic by design: it is read before anyone has signed in, and it exposes only\nwhich methods exist, never their credentials.","tags":["iam"],"parameters":[{"name":"clientId","in":"query","required":false,"description":"ClientId is the application's OAuth client id.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"ok"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"bad request"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/certs":{"get":{"operationId":"get_iam_certs","summary":"Returns your organization's signing certificates, newest first — the keys the tokens your applications verify are signed with.","description":"Returns your organization's signing certificates, newest first — the keys\nthe tokens your applications verify are signed with. Private key material is\nmasked.\n\nYou see your own organization's certificates and no one else's; which\norganization that is comes from your credentials, not from the request, so a\nquery parameter can never widen the listing.","tags":["iam"],"parameters":[{"name":"owner","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.certs.ListOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"post":{"operationId":"post_iam_certs","summary":"Adds a signing certificate your applications can verify tokens against — the call you make to stage the next one before a rotation.","description":"Adds a signing certificate your applications can verify tokens against\n— the call you make to stage the next one before a rotation. A name already\nused in your organization is refused.\n\nIt registers the certificate's IDENTITY: its name (which is the JWKS `kid`),\nits algorithm, its expiry. Key material does not travel this way and cannot:\nthe private key is not part of the Cert's JSON, so it is neither served here\nnor accepted here. It is supplied to the process by the deployment, under the\nname registered here (internal/keyring). Staging a rotation is therefore two\nhalves — this call names the key, and the deployment provides it.","tags":["iam"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Cert"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Cert"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/certs/{owner}/{name}":{"delete":{"operationId":"delete_iam_certs_by_owner_by_name","summary":"Removes a signing certificate.","description":"Removes a signing certificate. Tokens signed with it can no longer be\nverified, so retire it only once nothing is still presenting them.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.certs.DeleteOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"get":{"operationId":"get_iam_certs_by_owner_by_name","summary":"Returns one signing certificate — its algorithm, its validity window and its public half.","description":"Returns one signing certificate — its algorithm, its validity window and\nits public half. The private key is masked.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Cert"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"put":{"operationId":"put_iam_certs_by_owner_by_name","summary":"Changes a signing certificate's settings.","description":"Changes a signing certificate's settings. What it is called does not\nchange, and neither does when it was added.\n\nA PUT here is a METADATA edit — display name, expiry, provider. It overlays\nonly the fields the request actually SET onto the loaded row: a field the JSON\nomits (or leaves at its zero value) keeps what the row holds, rather than\nblanking it. That is load-bearing, not a nicety. A read serves the public\nCertificate (Mask hides only PrivateKey and AccessSecret), so a client that\nreads a cert, changes one field, and writes it back sends the masked halves\nempty and every other field it did not touch at its zero value — and the old\nfull-struct overlay wrote all of those blanks back. Blanking CryptoAlgorithm\nalone drops the cert from the JWKS (oidc.Publishes turns false), so every\ntoken under its `kid` stops verifying; blanking Provider/Account/ExpireTime\nbreaks ACME renewal and expiry — all from a request that only meant to rename\nit. Absent-or-zero means \"unchanged\", so the deployment (key) and a rotation\n(cert) remain the only way key or published material changes; the metadata API\ncannot clear it.\n\nThe overlay is generic — it copies every set field, so a field nobody has added\nyet is carried without a line here — and leaves three things the request may\nnot move: the bound Model (id, createdAt, key, snapshot), the natural key\n(owner/name address the row, they do not mutate it), and the creation stamp.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Cert"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Cert"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/consent":{"get":{"operationId":"get_iam_consent","summary":"Returns the calling person's own privacy and communication choices.","description":"Returns the calling person's own privacy and communication\nchoices. Somebody who has never set them gets the defaults rather than\nnothing, so a consent screen always has something to show — insights on, and\ntraining UNANSWERED, which is the state that means the screen still has to ask.","tags":["iam"],"x-app":"iam","x-public":true},"put":{"operationId":"put_iam_consent","summary":"Records the calling person's privacy and communication choices.","description":"Records the calling person's privacy and communication\nchoices. Only their own — there is no way to set consent for somebody else.\n\nSend only the answers you are changing. A question you leave out keeps the\nanswer it already had, so a screen that saves one switch never revokes the\nother, and two screens saving at once do not undo each other.\n\nAn answer this version does not recognize is refused here rather than stored,\nso nothing is ever persisted for a later reader to have to interpret.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/delete-membership":{"post":{"operationId":"post_iam_delete-membership","summary":"Takes away a person's or an application's right to act in an organization.","description":"Takes away a person's or an application's right to act in an\norganization. Their account survives; what ends is their access to that\norganization. Revoking a membership that is already gone reports that nothing\nwas removed rather than failing, so a retry is safe. It is the mirror of ensure and takes the SAME gate:\nrevoking membership is the org's authority to give or take, so a SuperAdmin, an\nadmin of the org itself, or an org-admin-capable confidential client. Idempotent\nthrough the store — deleting an absent membership reports removed=false, never an\nerror — so a retried revoke is safe.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/invitations":{"get":{"operationId":"get_iam_invitations","summary":"Returns your organization's invitations, newest first — who has been asked to join, on what terms, and how many seats each invitation still has left.","description":"Returns your organization's invitations, newest first — who has\nbeen asked to join, on what terms, and how many seats each invitation still\nhas left.\n\nYou see the invitations of the organization your credentials run, and no one\nelse's: your own, or one you own or administer.","tags":["iam"],"parameters":[{"name":"owner","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.invitations.ListOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"post":{"operationId":"post_iam_invitations","summary":"Issues an invitation to join your organization — the code or link a new member redeems, with the role they arrive holding and the date it stops working.","description":"Issues an invitation to join your organization — the code or link a new\nmember redeems, with the role they arrive holding and the date it stops\nworking. A name already used in the organization is refused.","tags":["iam"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.invitations.Input"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Invitation"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/invitations/accept":{"post":{"operationId":"post_iam_invitations_accept","summary":"Joins the caller to an organization through an invitation, for a person who already has an account.","description":"Joins the caller to an organization through an invitation, for\na person who already has an account. Signing up through the invitation is the\nother way in (signupHandler); this one spends the same seat under the same rules.\n\nOnly the caller joins, as a member and never more; the request names nobody\nelse. An invitation pinned to an address admits only the account holding that\naddress, and only with a code IAM sent to it for this join — the account's own\nverified flag is not enough, because a tenant's identity provider can set it. An\ninvitation pinned to a phone number or a username admits no other org's account\nthis way. Joining an org the caller already belongs to succeeds and spends\nnothing. Every refusal is recorded, and an account refused acceptLimit times in\nacceptWindow is refused before anything is looked at.","tags":["iam"],"parameters":[{"name":"Cookie","in":"header","required":false,"schema":{"type":"string"}},{"name":"Authorization","in":"header","required":false,"schema":{"type":"string"}},{"name":"Sec-Fetch-Site","in":"header","required":false,"schema":{"type":"string"}},{"name":"Origin","in":"header","required":false,"schema":{"type":"string"}},{"name":"Host","in":"header","required":false,"schema":{"type":"string"}},{"name":"Content-Type","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.acceptBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"ok"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"bad request"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"forbidden"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"too many requests"},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"bad gateway"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"service unavailable"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/invitations/{owner}/{name}":{"delete":{"operationId":"delete_iam_invitations_by_owner_by_name","summary":"Withdraws an invitation.","description":"Withdraws an invitation. It stops being redeemable at once; anyone who\nalready joined through it keeps their account.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.invitations.DeleteOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"get":{"operationId":"get_iam_invitations_by_owner_by_name","summary":"Returns one invitation: who it is for, what it grants on acceptance, and when it expires.","description":"Returns one invitation: who it is for, what it grants on acceptance, and\nwhen it expires.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Invitation"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"put":{"operationId":"put_iam_invitations_by_owner_by_name","summary":"Changes an invitation's terms — the role it grants, how many may redeem it, or when it expires.","description":"Changes an invitation's terms — the role it grants, how many may redeem\nit, or when it expires. What it is called does not change.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.invitations.Input"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Invitation"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/invitations/{owner}/{name}/send":{"post":{"operationId":"post_iam_invitations_by_owner_by_name_send","summary":"Emails an invitation to the address it is pinned to: who invited them, to which organization, and the link that joins them.","description":"Emails an invitation to the address it is pinned to: who invited them, to\nwhich organization, and the link that joins them.\n\nThe caller chooses nothing about how it goes out. It is sent through the\nplatform application the caller's access token was issued to, from that\napplication's org's email account, with a link on the identity host that issued\nthe token — the way the inviter came in. Only the pinned address receives it.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.SendOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/keys":{"get":{"operationId":"get_iam_keys","summary":"Returns the API keys of an organization that you may see, newest first — what each is called, what it may reach, its publishable half, and when it was last used.","description":"Returns the API keys of an organization that you may see, newest first —\nwhat each is called, what it may reach, its publishable half, and when it was\nlast used. Secret halves are never listed.\n\nWhich keys come from your credentials, not from the request. You may name an\norganization you belong to: its admin sees every key it holds, and a member sees\nthe keys they hold there. Naming any other organization is refused.","tags":["iam"],"parameters":[{"name":"owner","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.keys.ListResponse"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"post":{"operationId":"post_iam_keys","summary":"Issues an API key.","description":"Issues an API key. A standard key comes back as a publishable half you\nmay ship in client code and a secret half you must not — the secret is shown\nonce, at creation, and cannot be retrieved afterwards. A publish-scoped key is\nissued with the publishable half only, so there is no secret to leak.\n\nA name already used in your organization is refused rather than reissued, so\ncreating twice never silently invalidates a key that is in production.\n\nA key you create is yours: it names you as its holder and speaks for you in the\norganization it is filed in. Naming anyone else as its holder is refused; a\nSuperAdmin names the person a key is for.","tags":["iam"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Key"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Key"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/keys/org":{"get":{"operationId":"get_iam_keys_org","summary":"Resolve a PUBLISHABLE key to the organization that owns it","description":"Answers which organization a publishable key belongs to — what a service calls to attribute a request that arrived carrying a key shipped in a browser. This is the noun spelling of `/v1/iam/resolve-key`, the same handler at the address that replaces it; both answer while callers migrate.\n\nIt names an ORGANIZATION and never a person. No path through it loads or returns a user, so a key placed in client code cannot become a way to learn who anyone is — which is the whole reason this is a separate endpoint from the one below.\n\nA key that is expired, secret rather than publishable, or simply unknown all answer with the same sentence and a `code` saying which it was. Only a confidential service that has already proved it may resolve keys reads that code — there is no anonymous caller here to probe which keys exist — and telling those apart is what lets a holder be told to re-mint an expired key instead of hunting a configuration error.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/keys/principal":{"get":{"operationId":"get_iam_keys_principal","summary":"Resolve a SECRET key to the principal it authenticates","description":"Answers who a secret key belongs to — the owner and name a gateway needs to attribute and bill a request that arrived carrying an `sk-`. This is the noun spelling of `/v1/iam/get-user?accessKey=`, the same handler at the address that replaces it; both answer while callers migrate.\n\nIt resolves a KEY and nothing else. The verb it replaces also reads a user by `?id=`, and carrying that here would make this a second address for the user read — the exact thing being retired. Ask for a person by name at the user read; ask here only what a credential resolves to.\n\nRequires a confidential caller: the resolver authenticates as an app, so a request without that credential resolves nothing rather than falling back to an anonymous lookup. An unresolvable key answers with a `code` distinguishing expired from wrong-endpoint from unknown, so the holder can be told which one cure applies.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/keys/{owner}/{name}":{"delete":{"operationId":"delete_iam_keys_by_owner_by_name","summary":"Revokes an API key.","description":"Revokes an API key. Anything still presenting it stops being authorized at\nonce, so roll the replacement out before you revoke.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.keys.DeleteResponse"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"get":{"operationId":"get_iam_keys_by_owner_by_name","summary":"Returns one API key: what it is called, what it may reach, and when it was issued.","description":"Returns one API key: what it is called, what it may reach, and when it was\nissued.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Key"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"put":{"operationId":"put_iam_keys_by_owner_by_name","summary":"Changes what a key is called, what it may reach, when it expires, or revokes it.","description":"Changes what a key is called, what it may reach, when it expires, or\nrevokes it. The credential itself is not reissued — the key in your deployment\nkeeps working until it expires or is revoked.\n\nAn update writes the whole set of editable fields, so send the key as you read\nit with your changes made. The class in its scope (publishable or secret) is\nfixed at creation and an update naming the other is refused. Setting state to\n\"Revoked\" revokes the key: the row stays, records who revoked it and when, and\nis never updated again.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"description":"Owner is the tenant that holds the key; Name is unique within Owner.","schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Key"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Key"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/link":{"get":{"operationId":"get_iam_link","summary":"Continues a link in the browser of the person it is for: the browser opens the address POST /v1/iam/link answered, as a top-level navigation, signed in here as that person, and is sent on to the provider.","description":"Continues a link in the browser of the person it is for: the browser\nopens the address POST /v1/iam/link answered, as a top-level navigation, signed\nin here as that person, and is sent on to the provider.\n\nThe address works once. The provider leg runs on a fresh transaction, bound to\nthis browser by a cookie set on this navigation, so that transaction and its\nbinding exist only here.","tags":["iam"],"x-app":"iam","x-public":true},"post":{"operationId":"post_iam_link","summary":"Starts connecting another sign-in identity to the account you are already signed in as.","description":"Starts connecting another sign-in identity to the account you are already\nsigned in as. It answers with an address for your browser to open; from there\nyou go to the provider, and when it returns, that identity is attached and you\ncome back to returnUri. Only the browser where you are signed in here can carry\na link through.\n\nYour account is fixed here, from the credential you are already holding, and is\ncarried server-side for the rest of the round-trip — so nothing that happens at\nthe provider can point the link at somebody else.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/linked-accounts":{"get":{"operationId":"get_iam_linked-accounts","summary":"Returns the sign-in identities linked to the calling person's account — every provider they can currently sign in with.","description":"Returns the sign-in identities linked to the calling\nperson's account — every provider they can currently sign in with. It is what\na security page lists next to the option to disconnect one.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/login":{"post":{"operationId":"post_iam_login","summary":"Signs a person in with the credential they typed, and — when the request is part of an OAuth flow — hands back the one-time code that finishes it.","description":"Signs a person in with the credential they typed, and — when the\nrequest is part of an OAuth flow — hands back the one-time code that finishes\nit. A second factor, if the account has one, is asked for and required here.\n\nThe password is compared against a stored one-way hash and is never logged,\nechoed or stored as typed.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/memberships":{"get":{"operationId":"get_iam_memberships","summary":"Answers either question about who belongs where: which organizations one person can act in, or who can act in one organization.","description":"Answers either question about who belongs where: which organizations one\nperson can act in, or who can act in one organization.\n\nBoth are org-scoped: a non-SuperAdmin may read the roster of an org it belongs\nto, or the tenancy of a person whose account it administers, and nothing else.\nThe bound comes from the verified credential via principal.ScopeRead, so a\nrequest parameter can never widen it — a membership row names who may act and\nspend in an org, so a roster read by a stranger is a customer roster leak.","tags":["iam"],"parameters":[{"name":"user","in":"query","required":false,"description":"User is \"\u003chomeOrg\u003e/\u003cusername\u003e\" — which organizations that identity may act in.","schema":{"type":"string"}},{"name":"org","in":"query","required":false,"description":"Org is an organization — who may act in it.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"bad request"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"post":{"operationId":"post_iam_memberships","summary":"Lets a person or an application act in an organization.","description":"Lets a person or an application act in an organization. It is the grant\nbehind \"add someone to the team\", and it is safe to repeat — granting a\nmembership that already exists changes nothing. Granting membership IS the org's authority to give, so it takes the\nsame gate a write to that org's own registry row takes: a SuperAdmin, an admin\nof the org itself, or an org-admin-capable confidential client. One rule, one\nplace (internal/authz).","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/mfa":{"delete":{"operationId":"delete_iam_mfa","summary":"Turns a factor off, so sign-in stops asking for it.","description":"Turns a factor off, so sign-in stops asking for it. Naming no factor turns\noff ALL of them — the reset path. People may do this for themselves; doing it for\nsomebody else takes an administrator, which is what makes it the way back in when a\nphone is lost.\n\nThe recovery codes go with the last factor: they are the way past a challenge, so\nkeeping them alive for an account with nothing to challenge would leave a standing\ncredential behind.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/mfa/preferred":{"post":{"operationId":"post_iam_mfa_preferred","summary":"Picks which second factor an account is asked for first when it has more than one.","description":"Picks which second factor an account is asked for first when it has\nmore than one. Only a factor the account actually holds: storing an unheld one told\nthe login gate \"MFA is on\" — factor.Enabled reads that column — while leaving it\nnothing to ask for, so the sign-in required the password alone.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/mfa/setup/enable":{"post":{"operationId":"post_iam_mfa_setup_enable","summary":"Finishes the enrolment: from here the account's sign-ins ask for this factor.","description":"Finishes the enrolment: from here the account's sign-ins ask for this factor.\nIt requires the proof initiate handed out — a passcode from the authenticator, or the\ncode that was sent — and verifies it BEFORE writing anything.\n\nVerifying BEFORE writing is what keeps a client that never completed the proof —\na skipped verify step, a QR scanned into the wrong app, a bug — from switching on\na factor no code can satisfy. That would lock the account out with no\nself-service way back: the gate holds the sign-in before minting, so the person\ncould not obtain the bearer that disable requires.\n\nThe recovery codes are minted here and returned ONCE, on the first factor the\naccount adds. Answering with them is the way back in when no factor can be\nproduced, so they are the same value the row's digests were made from — by\nconstruction, not by a client echoing them back.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/mfa/setup/initiate":{"post":{"operationId":"post_iam_mfa_setup_initiate","summary":"Starts enrolling a factor and hands over whatever the person needs to prove they hold it: app a fresh secret and the otpauth:// URL to render as a QR code sms a code texted to the number on the account email a code mailed to the address on the account Nothing is switched on yet, so abandoning this step leaves the account exactly as it was.","description":"Starts enrolling a factor and hands over whatever the person needs to prove\nthey hold it:\n\n\tapp   a fresh secret and the otpauth:// URL to render as a QR code\n\tsms   a code texted to the number on the account\n\temail a code mailed to the address on the account\n\nNothing is switched on yet, so abandoning this step leaves the account exactly as\nit was. Response: {status:\"ok\", data:{mfaType, secret, url}} — secret and url only\nfor the authenticator.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/oauth/authorize":{"get":{"operationId":"get_iam_oauth_authorize","summary":"Starts a sign-in — the address you send a browser to, and the beginning of every OAuth and OpenID Connect flow.","description":"Starts a sign-in — the address you send a browser to, and the\nbeginning of every OAuth and OpenID Connect flow.\n\nIf the person is ALREADY signed in here, it does not ask them again: it\nreturns them to the application with a one-time code and they never see this\npage. Otherwise it shows the right way to sign in for the application they are\nsigning in to, or hands off to another identity provider if that is what they\npick.\n\nA client can say what it wants with `prompt`: `none` means answer without any\nscreen at all — with the code if a session exists, with an error if not, but\nnever with a page; `login` means ask for the password again even if a session\nexists; `select_account` means let the person choose among the accounts signed\nin on this browser, or sign in to another. `login_hint` names which of those\naccounts the request is for.\n\nIt returns only to an address the application has registered. That check\nhappens before anything else, so a request naming an unregistered address is\nrefused where the person can see it rather than being bounced onwards.","tags":["iam"],"x-app":"iam","x-public":true},"post":{"operationId":"post_iam_oauth_authorize","summary":"Starts a sign-in — the address you send a browser to, and the beginning of every OAuth and OpenID Connect flow.","description":"Starts a sign-in — the address you send a browser to, and the\nbeginning of every OAuth and OpenID Connect flow.\n\nIf the person is ALREADY signed in here, it does not ask them again: it\nreturns them to the application with a one-time code and they never see this\npage. Otherwise it shows the right way to sign in for the application they are\nsigning in to, or hands off to another identity provider if that is what they\npick.\n\nA client can say what it wants with `prompt`: `none` means answer without any\nscreen at all — with the code if a session exists, with an error if not, but\nnever with a page; `login` means ask for the password again even if a session\nexists; `select_account` means let the person choose among the accounts signed\nin on this browser, or sign in to another. `login_hint` names which of those\naccounts the request is for.\n\nIt returns only to an address the application has registered. That check\nhappens before anything else, so a request naming an unregistered address is\nrefused where the person can see it rather than being bounced onwards.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/oauth/callback":{"get":{"operationId":"get_iam_oauth_callback","summary":"Completes the round-trip: it resolves and burns the single-use transaction (checking expiry + browser binding), exchanges and verifies the IdP response, links or provisions the local user, and mints the iam authorization code the relying party expects — then redirects to the original redirect_uri with code + state.","description":"Completes the round-trip: it resolves and burns the\nsingle-use transaction (checking expiry + browser binding), exchanges and\nverifies the IdP response, links or provisions the local user, and mints the\niam authorization code the relying party expects — then redirects to the\noriginal redirect_uri with code + state. A redirect provider's reply is read\nfrom the query of its GET. A form_post provider's POST is answered with a 303\nto a GET of this address naming a single-use handoff that holds the reply, and\nthat GET finishes the sign-in.","tags":["iam"],"x-app":"iam","x-public":true},"post":{"operationId":"post_iam_oauth_callback","summary":"Completes the round-trip: it resolves and burns the single-use transaction (checking expiry + browser binding), exchanges and verifies the IdP response, links or provisions the local user, and mints the iam authorization code the relying party expects — then redirects to the original redirect_uri with code + state.","description":"Completes the round-trip: it resolves and burns the\nsingle-use transaction (checking expiry + browser binding), exchanges and\nverifies the IdP response, links or provisions the local user, and mints the\niam authorization code the relying party expects — then redirects to the\noriginal redirect_uri with code + state. A redirect provider's reply is read\nfrom the query of its GET. A form_post provider's POST is answered with a 303\nto a GET of this address naming a single-use handoff that holds the reply, and\nthat GET finishes the sign-in.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/oauth/delegation/keys":{"get":{"operationId":"get_iam_oauth_delegation_keys","summary":"Serves the public half of every delegation key, as a JWKS, to a confidential client allowed to delegate — the one resource server that verifies what it is handed, reading with the credential it delegates with.","description":"Serves the public half of every delegation key, as a\nJWKS, to a confidential client allowed to delegate — the one resource server\nthat verifies what it is handed, reading with the credential it delegates with.\nTo anyone else it answers as the token endpoint does: who are you, or not you.\n\nThe key is not a secret; publishing it is the hazard. A verifier that fetches\nthe public JWKS and trusts what verifies would admit a delegated token as the\nperson. So it is not in that document, and this one is not an address a relying\nparty is ever pointed at.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/oauth/device":{"post":{"operationId":"post_iam_oauth_device","summary":"Starts a sign-in on a device with no browser and no keyboard — a TV, a CLI, a headless box.","description":"Starts a sign-in on a device with no browser and no keyboard —\na TV, a CLI, a headless box. It returns a short code to show the person and\nthe address to send them to on a phone or laptop.\n\nNothing is granted until a human approves it there; until then the code is\njust a pending request.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/oauth/device/info":{"post":{"operationId":"post_iam_oauth_device_info","summary":"Answers \"what am I approving?\" for a pending device code.","description":"Answers \"what am I approving?\" for a pending device code.\n\nThe approval page exists to tell a human WHICH application they are authorizing;\na page that names any other one defeats the control it implements. The client is\na property of the CODE, not of the page or of whatever app the browser happens\nto be signed in to, so it is read from the code's row here and nowhere else.\n\nRequires a signed-in session, and answers with the same ONE opaque refusal\napproveDevice uses. That is deliberate: the user_code is only 40 bits and is the\none secret in this flow, so an unauthenticated lookup — or one that\ndistinguished unknown from expired from already-approved — would be an oracle\nfor hunting live codes. Gated and opaque, it reveals strictly less than the\napproval the same caller could already attempt.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/oauth/federation/mfa":{"post":{"operationId":"post_iam_oauth_federation_mfa","summary":"Completes a sign-in that came in through another identity provider and still owes a second factor.","description":"Completes a sign-in that came in through another identity\nprovider and still owes a second factor. The person supplies the factor here\nand the login finishes.\n\nThe account is fixed when the challenge is issued, not by the request, so no\none can redirect a half-finished login onto somebody else's account. A wrong\nfactor uses the challenge up: retrying means starting the sign-in again, the\nsame as a mistyped password.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/oauth/introspect":{"post":{"operationId":"post_iam_oauth_introspect","summary":"Answers whether an access token is still good, and what it is good for — the check a resource server of yours makes before honouring a token it did not mint.","description":"Answers whether an access token is still good, and what it\nis good for — the check a resource server of yours makes before honouring a\ntoken it did not mint.\n\nA token counts as active only if it verifies AND has not been revoked, so a\nrevoked token reads as dead here immediately rather than until it expires. A\ntoken that is unknown, expired or revoked answers simply that it is not\nactive, and nothing more — the endpoint is not a way to learn about tokens you\nwere not given.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/oauth/logout":{"get":{"operationId":"get_iam_oauth_logout","summary":"Ends a sign-in and sends the browser somewhere sensible.","description":"Ends a sign-in and sends the browser somewhere sensible. Accepts\nGET or POST, so it works as a plain link.\n\nIt ACTUALLY signs you out — worth stating, because a logout that computes a\nredirect and answers {\"status\":\"ok\"} while ending no session and revoking no\ntoken is worse than none: the person on the shared machine believes it worked.\nThree things happen here, in this order:\n\n 1. The browser session dies — sid revoked server-side AND the cookie expired\n    (sessions.Clear). Server-side revocation is the load-bearing half: a copy\n    of the cookie taken before logout must not still resolve.\n 2. The relying party's tokens are revoked when an id_token_hint names it, so\n    the refresh token cannot mint a fresh access token after the human left.\n    Revocation state is authoritative — a JWT's `exp` still reads valid for\n    days, so expiry is necessary but never sufficient.\n 3. Only then is a redirect considered, and only to a REGISTERED uri.\n\nThe open-redirect guard: a redirect happens only when a VERIFIED\nid_token_hint (or client_id) identifies the application and that application\nhas registered the target. Nobody can turn your logout link into a redirect to\na site of their choosing.\n\nA GET is the end-session navigation (OIDC RP-Initiated Logout 1.0 §2), so it\nalways ends on a page: the registered address when one was asked for, else\nthis issuer's sign-in page for the application being signed out of. A relying\nparty therefore needs no configuration to sign someone out. A POST is also how\na program signs out, so it keeps the JSON answer unless it asks for HTML.","tags":["iam"],"x-app":"iam","x-public":true},"post":{"operationId":"post_iam_oauth_logout","summary":"Ends a sign-in and sends the browser somewhere sensible.","description":"Ends a sign-in and sends the browser somewhere sensible. Accepts\nGET or POST, so it works as a plain link.\n\nIt ACTUALLY signs you out — worth stating, because a logout that computes a\nredirect and answers {\"status\":\"ok\"} while ending no session and revoking no\ntoken is worse than none: the person on the shared machine believes it worked.\nThree things happen here, in this order:\n\n 1. The browser session dies — sid revoked server-side AND the cookie expired\n    (sessions.Clear). Server-side revocation is the load-bearing half: a copy\n    of the cookie taken before logout must not still resolve.\n 2. The relying party's tokens are revoked when an id_token_hint names it, so\n    the refresh token cannot mint a fresh access token after the human left.\n    Revocation state is authoritative — a JWT's `exp` still reads valid for\n    days, so expiry is necessary but never sufficient.\n 3. Only then is a redirect considered, and only to a REGISTERED uri.\n\nThe open-redirect guard: a redirect happens only when a VERIFIED\nid_token_hint (or client_id) identifies the application and that application\nhas registered the target. Nobody can turn your logout link into a redirect to\na site of their choosing.\n\nA GET is the end-session navigation (OIDC RP-Initiated Logout 1.0 §2), so it\nalways ends on a page: the registered address when one was asked for, else\nthis issuer's sign-in page for the application being signed out of. A relying\nparty therefore needs no configuration to sign someone out. A POST is also how\na program signs out, so it keeps the JSON answer unless it asks for HTML.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/oauth/refresh_token":{"post":{"operationId":"post_iam_oauth_refresh_token","summary":"Exchanges what your application is holding for the tokens it needs — the one-time code from a finished sign-in, a refresh token, or your own client credentials when the caller is a program rather than a person.","description":"Exchanges what your application is holding for the tokens it\nneeds — the one-time code from a finished sign-in, a refresh token, or your\nown client credentials when the caller is a program rather than a person.\n\nA refresh returns a NEW refresh token and retires the one you sent. If a\nretired one is ever presented again the whole chain is revoked, on the\nassumption that a token which came back from the dead was copied — so a stolen\nrefresh token buys an attacker one use and costs them the session.\n\nResponses are never cached, by any hop.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/oauth/revoke":{"post":{"operationId":"post_iam_oauth_revoke","summary":"Retires a token before it expires — what you call when someone signs out or a credential may have leaked.","description":"Retires a token before it expires — what you call when someone\nsigns out or a credential may have leaked.\n\nRevoking an access token kills that token. Revoking a REFRESH token kills the\nwhole chain it belongs to, so no further access tokens can be minted from it\nand every token already minted from it dies with it.\n\nA token that is not yours, or that never existed, answers success and does\nnothing — so the endpoint cannot be used to discover which tokens are real.\n\nPUBLIC clients revoke too, and must: sign-out is the only control a long-lived\nrefresh token has (RFC 7009 §2.1 — a public client identifies itself with\nclient_id). A browser app or CLI is a public PKCE client and holds no secret,\nand that includes the public half of a registration that keeps a secret for a\nbackend path, so requiring one here would leave signing out as a local delete —\nforgetting a credential that stays spendable for the rest of its lifetime.\n\nWidening authentication does not widen authority. The caller must still POSSESS\nthe token — and possession already permits USE, of which revocation is the\nstrict opposite — and the row must belong to the client that presents it. A\ncaller that did not prove the registration's secret revokes only a grant that\nwas itself established without it, so a public client_id buys the ability to\ndestroy exactly what its holder could otherwise spend.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/oauth/token":{"post":{"operationId":"post_iam_oauth_token","summary":"Exchanges what your application is holding for the tokens it needs — the one-time code from a finished sign-in, a refresh token, or your own client credentials when the caller is a program rather than a person.","description":"Exchanges what your application is holding for the tokens it\nneeds — the one-time code from a finished sign-in, a refresh token, or your\nown client credentials when the caller is a program rather than a person.\n\nA refresh returns a NEW refresh token and retires the one you sent. If a\nretired one is ever presented again the whole chain is revoked, on the\nassumption that a token which came back from the dead was copied — so a stolen\nrefresh token buys an attacker one use and costs them the session.\n\nResponses are never cached, by any hop.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/oauth/userinfo":{"get":{"operationId":"get_iam_oauth_userinfo","summary":"Returns the profile claims for whoever the access token belongs to — the standard OpenID Connect way to find out who is calling you without your application storing anything itself.","description":"Returns the profile claims for whoever the access token\nbelongs to — the standard OpenID Connect way to find out who is calling you\nwithout your application storing anything itself.\n\nThe token must still be live: revoke it and this stops answering.","tags":["iam"],"x-app":"iam","x-public":true},"post":{"operationId":"post_iam_oauth_userinfo","summary":"Returns the profile claims for whoever the access token belongs to — the standard OpenID Connect way to find out who is calling you without your application storing anything itself.","description":"Returns the profile claims for whoever the access token\nbelongs to — the standard OpenID Connect way to find out who is calling you\nwithout your application storing anything itself.\n\nThe token must still be live: revoke it and this stops answering.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/onboard":{"post":{"operationId":"post_iam_onboard","summary":"Finishes setting up the account of whoever is calling — it creates their organization if they have none and puts them in it, so a person who has just signed up lands somewhere they can work.","description":"Finishes setting up the account of whoever is calling — it\ncreates their organization if they have none and puts them in it, so a person\nwho has just signed up lands somewhere they can work.\n\nIt always acts on the caller and never on somebody named in the request, so\nthere is no way to onboard another person's account through it.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/organizations":{"get":{"operationId":"listOrganizations","summary":"Returns the organizations you can act in, the ones you belong to first and the rest after, newest first, narrowed by an optional query against the name or the display name.","description":"Returns the organizations you can act in, the ones you belong to first\nand the rest after, newest first, narrowed by an optional query against the\nname or the display name.\n\nPlatform operators see every organization; everyone else sees their own. Pass\nthe cursor from the previous page to continue; an empty cursor in the answer\nmeans there is nothing more.\n\nTHE SCOPE IS THE HANDLER'S OWN, so it holds at every endpoint. The Guard refuses\na bearerless request before this runs, but the MCP server carries a typed op to\nits handler with no middleware in front of it — a handler that read no\nprincipal would answer such a caller with the whole registry. Reading the\nprincipal here is what makes the answer the same one over both.","tags":["iam"],"parameters":[{"name":"X-Forwarded-For","in":"header","required":false,"schema":{"type":"string"}},{"name":"q","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"format":"int64","type":"integer"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.ListOrganizationsOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"post":{"operationId":"createOrganization","summary":"Makes a new organization — the account your users, applications, roles, projects and workspaces are all named inside.","description":"Makes a new organization — the account your users, applications, roles,\nprojects and workspaces are all named inside. It is the first write in a new\ntenant, and a name already in use is refused rather than taken over.","tags":["iam"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.CreateOrganizationInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Organization"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/organizations/avatar":{"post":{"operationId":"setOrganizationAvatar","summary":"Changes how an organization appears across Hanzo: the square mark beside its name, as an uploaded image or as a single emoji.","description":"Changes how an organization appears across Hanzo: the square mark\nbeside its name, as an uploaded image or as a single emoji. Sending an image\nclears the emoji and sending an emoji clears the image — an organization has\none mark, not a preference order — and sending neither clears both, which is\nhow it goes back to being drawn as its initial.\n\nAn image is an https link or the bytes inline as a data URL, up to 96 KiB.\nAnyone who administers the organization may set this; it is not reserved to\nthe platform.\n\nIt writes the two fields onto the stored row and touches nothing else, which\nupdate cannot do: update replaces the whole record, and a record read back\nfirst arrives masked, so a read-modify-write through it would persist the mask\nover the organization's own credential settings.","tags":["iam"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.SetAvatarInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Organization"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/organizations/profile":{"post":{"operationId":"setOrganizationProfile","summary":"Changes how an organization reads: its display name, its website and its favicon.","description":"Changes how an organization reads: its display name, its website\nand its favicon.\n\nIT EXISTS FOR THE REASON SetAvatar DOES, and the reason is worth stating\nbecause the obvious alternative is a trap. Update REPLACES the whole record,\nso a caller that wants to change one field has to send every other field\nback — and a record read back first arrives MASKED, so the read half of that\nread-modify-write hands you \"***\" for the master password and the salt, and\nthe write half stores it. Renaming an organization through Update therefore\ncosts it its credential settings; sending only the new name costs it\neverything else. Neither is a rename.\n\nSo this writes the fields it names and touches nothing else. A nil pointer is\nnot sent and not changed; an empty string is sent and clears the field.","tags":["iam"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.SetProfileInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Organization"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/organizations/tombstones/{owner}/{name}":{"delete":{"operationId":"releaseOrganizationName","summary":"Frees the name of a deleted organization so it can be founded again.","description":"Frees the name of a deleted organization so it can be founded again.\nDeleting an organization leaves its name held, because every service keys a\ntenant by that name; releasing it is a SuperAdmin's decision, recorded on the\naudit trail, and it is refused while anything IAM keeps is still keyed by the\nname. Everything else keyed by it across the estate must be purged first.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.ReleaseOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"get":{"operationId":"getOrganizationTombstone","summary":"Returns what holds a deleted organization's name: when it was deleted and who founded it.","description":"Returns what holds a deleted organization's name: when it was deleted\nand who founded it. A SuperAdmin reads it before deciding to release the name.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Tombstone"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/organizations/{owner}/{name}":{"delete":{"operationId":"deleteOrganization","summary":"Removes an organization and everything named inside it.","description":"Removes an organization and everything named inside it. There is no\nundo, and every session issued under it stops working.\n\nThe built-in admin organization cannot be deleted — losing it would leave the\naccount with no way back in.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.DeleteOrganizationOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"get":{"operationId":"getOrganization","summary":"Returns one organization: its display, its defaults and the sign-in rules everyone in it inherits.","description":"Returns one organization: its display, its defaults and the sign-in rules\neveryone in it inherits.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Organization"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"put":{"operationId":"updateOrganization","summary":"Changes an organization's display, its defaults and the sign-in rules everyone in it inherits.","description":"Changes an organization's display, its defaults and the sign-in rules\neveryone in it inherits. Which organization it is does not change, and neither\ndoes when it was created.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.UpdateOrganizationInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Organization"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/password":{"put":{"operationId":"put_iam_password","summary":"Replaces the calling person's password.","description":"Replaces the calling person's password. Only their own —\nthere is no shape of this request that writes somebody else's.\n\nProve who you are with the password you are replacing, or — when you cannot\nsign in at all — with a code sent to the address the account already holds.\nExactly one of the two: a request carrying both proves nothing more than\neither, and answering it would mean deciding which one mattered.\n\nA reset also clears the account lockout, in the SAME transaction as the\ndigest. Replacing a credential retires the run of guesses against the old one,\nand without this a person who reset a forgotten password was still refused for\nup to fifteen more minutes — with the brand-new password they had just chosen.","tags":["iam"],"parameters":[{"name":"Cookie","in":"header","required":false,"schema":{"type":"string"}},{"name":"Authorization","in":"header","required":false,"schema":{"type":"string"}},{"name":"Sec-Fetch-Site","in":"header","required":false,"schema":{"type":"string"}},{"name":"Origin","in":"header","required":false,"schema":{"type":"string"}},{"name":"Host","in":"header","required":false,"schema":{"type":"string"}},{"name":"Content-Type","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.passwordBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"ok"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"bad request"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"forbidden"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/permissions":{"get":{"operationId":"get_iam_permissions","summary":"Returns the permissions in one organization, newest first — each one a grant saying which people or roles may do what, and to which resources.","description":"Returns the permissions in one organization, newest first — each one a\ngrant saying which people or roles may do what, and to which resources.","tags":["iam"],"parameters":[{"name":"owner","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.ListResponse"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"post":{"operationId":"post_iam_permissions","summary":"Grants a permission — the call that gives a person or a role the ability to do something.","description":"Grants a permission — the call that gives a person or a role the ability to\ndo something. Adding refuses to overwrite a grant that already exists, so\nwidening an existing one is an update, never an accident.","tags":["iam"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Permission"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Permission"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/permissions/{owner}/{name}":{"delete":{"operationId":"delete_iam_permissions_by_owner_by_name","summary":"Revokes a permission.","description":"Revokes a permission. Everyone who held access only through it loses\nthat access immediately; grants they hold by another route are untouched.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.DeleteResponse"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"get":{"operationId":"get_iam_permissions_by_owner_by_name","summary":"Returns one permission: who it grants to, what it allows, and the resources it covers.","description":"Returns one permission: who it grants to, what it allows, and the\nresources it covers.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Permission"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"put":{"operationId":"put_iam_permissions_by_owner_by_name","summary":"Changes who a permission grants to, what it allows, or the resources it covers.","description":"Changes who a permission grants to, what it allows, or the resources it\ncovers. Access changes as soon as the write lands. What the permission is\ncalled does not change, and neither does when it was created.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"description":"Identity — the (owner, name) natural key.","schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Permission"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Permission"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/preferences":{"post":{"operationId":"post_iam_preferences","summary":"Saves the calling person's own settings and returns the full set afterwards.","description":"Saves the calling person's own settings and returns\nthe full set afterwards. Send only the settings you are changing — the rest\nare kept, so two screens can save at once without one undoing the other.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/projects":{"get":{"operationId":"get_iam_projects","summary":"Returns your organization's projects, newest first — the scope people pick between when their work is separated by product or client rather than by team.","description":"Returns your organization's projects, newest first — the scope\npeople pick between when their work is separated by product or client rather\nthan by team.\n\nYou see your own organization's projects and no one else's; which organization that\nis comes from your credentials, not from the request.","tags":["iam"],"parameters":[{"name":"owner","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.projects.ListOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"post":{"operationId":"post_iam_projects","summary":"Makes a project inside your organization — the scope people pick between when their work is separated by product or client rather than by team.","description":"Makes a project inside your organization — the scope people pick\nbetween when their work is separated by product or client rather than by team.\nA name already used in the organization is refused.","tags":["iam"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.projects.Input"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Project"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/projects/{owner}/{name}":{"delete":{"operationId":"delete_iam_projects_by_owner_by_name","summary":"Removes a project.","description":"Removes a project. The people and roles in your organization are\nunchanged; what goes is the scope itself, so move anything addressed by it\nfirst.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.projects.DeleteOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"get":{"operationId":"get_iam_projects_by_owner_by_name","summary":"Returns one project: what it is called and how it is set up.","description":"Returns one project: what it is called and how it is set up.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Project"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"put":{"operationId":"put_iam_projects_by_owner_by_name","summary":"Changes a project's settings.","description":"Changes a project's settings. What it is called does not change, and\nneither does when it was created.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.projects.Input"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Project"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/providers":{"get":{"operationId":"listProviders","summary":"Returns your organization's providers, newest first — the identity providers your people sign in with, and the senders and connectors your applications go through.","description":"Returns your organization's providers, newest first — the\nidentity providers your people sign in with, and the senders and connectors\nyour applications go through.\n\nYou see your own organization's providers and no one else's; which organization\nthat is comes from your credentials, not from the request.","tags":["iam"],"parameters":[{"name":"owner","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.listProvidersOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"post":{"operationId":"addProvider","summary":"Adds an identity provider your people can sign in with, or a service your applications send through — a social or enterprise login, an email or SMS sender, a storage or payment connector.","description":"Adds an identity provider your people can sign in with, or a\nservice your applications send through — a social or enterprise login, an email\nor SMS sender, a storage or payment connector.\n\nA provider is configured once and then switched on per application, so several\napplications can share one set of credentials.","tags":["iam"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Provider"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.providerResult"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/providers/{owner}/{name}":{"delete":{"operationId":"deleteProvider","summary":"Removes a provider.","description":"Removes a provider. Sign-in through it stops for every\napplication that used it, so give those applications another method first.\n\nA provider that is already gone answers \"nothing changed\" rather than an\nerror, so the call is safe to repeat.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.mutationResult"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"get":{"operationId":"getProvider","summary":"Returns one provider: what it connects to and how it is configured.","description":"Returns one provider: what it connects to and how it is\nconfigured. Its credentials come back masked.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.providerResult"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"put":{"operationId":"updateProvider","summary":"Changes a provider's settings or rotates the credentials it holds.","description":"Changes a provider's settings or rotates the credentials it\nholds. The change takes effect on the next sign-in through it — sessions\nalready issued are unaffected.\n\nA provider that is not there answers \"nothing changed\" rather than an error, so\nthe call is safe to repeat.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Provider"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.mutationResult"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/registry/jwks":{"get":{"operationId":"get_iam_registry_jwks","summary":"Publishes the public key your registry uses to verify the tokens issued above — the one URL to configure so the registry trusts logins without holding any secret of its own.","description":"Publishes the public key your registry uses to verify the tokens issued\nabove — the one URL to configure so the registry trusts logins without holding\nany secret of its own.\n\nIf no signing key is available it refuses rather than publishing an empty set,\nbecause a registry that trusts nothing looks identical to one that trusts\neverything until somebody tries to push.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/registry/token":{"get":{"operationId":"get_iam_registry_token","summary":"Signs a container client in to your registry.","description":"Signs a container client in to your registry. `docker login`, and every\nbuild tool that pushes or pulls images, lands here: it exchanges the\ncredential for a short-lived token scoped to exactly the repositories that\ncredential may touch.\n\nBoth of the shapes container tooling uses are accepted, so the same login works\nwhichever client your pipeline runs.","tags":["iam"],"x-app":"iam","x-public":true},"post":{"operationId":"post_iam_registry_token","summary":"Signs a container client in to your registry.","description":"Signs a container client in to your registry. `docker login`, and every\nbuild tool that pushes or pulls images, lands here: it exchanges the\ncredential for a short-lived token scoped to exactly the repositories that\ncredential may touch.\n\nBoth of the shapes container tooling uses are accepted, so the same login works\nwhichever client your pipeline runs.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/roles":{"get":{"operationId":"get_iam_roles","summary":"Returns your organization's roles, newest first — each a named group of people that permissions are granted to.","description":"Returns your organization's roles, newest first — each a named group of\npeople that permissions are granted to.\n\nYou see your own organization's roles and no one else's; which organization\nthat is comes from your credentials, not from the request.","tags":["iam"],"parameters":[{"name":"owner","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.roles.ListOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"post":{"operationId":"post_iam_roles","summary":"Makes a role — a named group of people that permissions are granted to.","description":"Makes a role — a named group of people that permissions are granted to.\nGranting to a role rather than to each person is what keeps access correct as\nyour team changes: add someone to the role and they inherit everything it can\ndo. A name already used in your organization is refused.","tags":["iam"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Input"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Role"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/roles/{owner}/{name}":{"delete":{"operationId":"delete_iam_roles_by_owner_by_name","summary":"Removes a role.","description":"Removes a role. Everyone in it loses the access it carried; their\naccounts, and any other role they hold, are untouched.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.roles.DeleteOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"get":{"operationId":"get_iam_roles_by_owner_by_name","summary":"Returns one role: who is in it, and the roles it includes.","description":"Returns one role: who is in it, and the roles it includes.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Role"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"put":{"operationId":"put_iam_roles_by_owner_by_name","summary":"Changes who is in a role, or which roles it includes.","description":"Changes who is in a role, or which roles it includes. Access changes for\neveryone in it as soon as the write lands. What the role is called does not\nchange, and neither does when it was created.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"description":"Name addresses the team on update and names it on create; every other\nfield is content and binds from the BODY, never the URL.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Input"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Role"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/scim/v2/ResourceTypes":{"get":{"operationId":"get_iam_scim_v2_resourcetypes","summary":"Returns the kinds of record this directory provisions and the address of each, so your identity provider discovers them rather than having them configured by hand.","description":"Returns the kinds of record this directory provisions and\nthe address of each, so your identity provider discovers them rather than\nhaving them configured by hand.","tags":["iam"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.listResponse"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/scim/v2/ResourceTypes/{name}":{"get":{"operationId":"get_iam_scim_v2_resourcetypes_by_name","summary":"Returns one provisionable record kind in full.","description":"Returns one provisionable record kind in full.","tags":["iam"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"404":{"content":{"application/json":{"schema":{}}},"description":"not found"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/scim/v2/Schemas":{"get":{"operationId":"get_iam_scim_v2_schemas","summary":"Returns the attribute definitions this directory understands, so your identity provider knows which fields it may send and what they mean before it sends any.","description":"Returns the attribute definitions this directory understands, so\nyour identity provider knows which fields it may send and what they mean\nbefore it sends any.","tags":["iam"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.listResponse"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/scim/v2/Schemas/{id}":{"get":{"operationId":"get_iam_scim_v2_schemas_by_id","summary":"Returns one attribute definition in full.","description":"Returns one attribute definition in full.","tags":["iam"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"404":{"content":{"application/json":{"schema":{}}},"description":"not found"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/scim/v2/ServiceProviderConfig":{"get":{"operationId":"get_iam_scim_v2_serviceproviderconfig","summary":"Tells your identity provider which parts of SCIM this directory supports, so it configures itself instead of you filling in a form.","description":"Tells your identity provider which parts of SCIM this\ndirectory supports, so it configures itself instead of you filling in a form.\n\nFiltering and partial updates are supported. Bulk operations, sorting and\nentity tags are not — an IdP that reads this will not attempt them.","tags":["iam"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.config"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/scim/v2/Users":{"get":{"operationId":"get_iam_scim_v2_users","summary":"Returns the people in your organization to your identity provider, in the standard SCIM shape, so an IdP can reconcile its directory against ours.","description":"Returns the people in your organization to your identity provider,\nin the standard SCIM shape, so an IdP can reconcile its directory against\nours. Searchable by username or email address, and paged.\n\nReading the whole list takes an administrator; an ordinary person is refused.","tags":["iam"],"x-app":"iam","x-public":true},"post":{"operationId":"post_iam_scim_v2_users","summary":"Provisions a person from your identity provider — how a new hire gets an account here automatically when they are added over there.","description":"Provisions a person from your identity provider — how a new hire\ngets an account here automatically when they are added over there.\n\nTakes an administrator. Making someone an administrator takes more than that,\nso an IdP integration cannot escalate anyone by setting a flag.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/scim/v2/Users/{owner}/{name}":{"delete":{"operationId":"delete_iam_scim_v2_users_by_owner_by_name","summary":"Deprovisions a person — how removing someone in your identity provider removes their access here.","description":"Deprovisions a person — how removing someone in your identity\nprovider removes their access here. Their sessions stop working immediately.\nTakes an administrator.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"iam","x-public":true},"get":{"operationId":"get_iam_scim_v2_users_by_owner_by_name","summary":"Returns one person in the standard SCIM shape.","description":"Returns one person in the standard SCIM shape. An administrator may\nread anyone in the organization; everyone else may read only themselves.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"iam","x-public":true},"patch":{"operationId":"patch_iam_scim_v2_users_by_owner_by_name","summary":"Applies a partial change from your identity provider — one attribute moved, not the whole record resent.","description":"Applies a partial change from your identity provider — one attribute\nmoved, not the whole record resent.\n\nThe change is applied onto the person as they currently are, so everything you\ndid not mention keeps its value, including the parts SCIM does not describe.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"iam","x-public":true},"put":{"operationId":"put_iam_scim_v2_users_by_owner_by_name","summary":"Overwrites a person's SCIM attributes with what your identity provider sends — how a change made there lands here.","description":"Overwrites a person's SCIM attributes with what your identity\nprovider sends — how a change made there lands here.\n\nOnly the attributes SCIM describes are replaced. Anything the standard does not\ncover — their multi-factor enrolment above all — survives untouched, so a\nroutine sync from your IdP can never quietly strip someone's second factor or\nbring a deleted account back.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"iam","x-public":true}},"/v1/iam/service-accounts":{"get":{"operationId":"get_iam_service-accounts","summary":"Returns your organization's service accounts — what each is called and when it was created.","description":"Returns your organization's service accounts — what each is called and\nwhen it was created. Never their secrets: a key's secret half exists in a\nresponse exactly once, when it is minted. Paginated in memory over the already org-scoped\nslice — the set per org is small, so a dedicated count query is overkill\n(v1 service_account.go:296-307).","tags":["iam"],"parameters":[{"name":"organization","in":"query","required":false,"description":"Organization is the organization whose service accounts to list. Required.","schema":{"type":"string"}},{"name":"p","in":"query","required":false,"description":"P is the 1-indexed page to return. Paging takes both p and pageSize —\nleave either out, or send something that is not a number, and the whole\nlist comes back.","schema":{"format":"int64","type":"integer"}},{"name":"pageSize","in":"query","required":false,"description":"Size is how many accounts a page holds.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"bad request"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"post":{"operationId":"post_iam_service-accounts","summary":"Makes a service account — an identity for a program rather than a person, for a script, a bot or a deployment that has to authenticate on its own.","description":"Makes a service account — an identity for a program rather than a\nperson, for a script, a bot or a deployment that has to authenticate on its\nown.\n\nIt comes back with its first key, and the secret half is shown ONCE, here.\nThere is no way to read it again; if you lose it, rotate.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/service-accounts/{name}":{"delete":{"operationId":"delete_iam_service-accounts_by_name","summary":"Serves DELETE /v1/iam/service-accounts/:name.","description":"Serves DELETE /v1/iam/service-accounts/:name.","tags":["iam"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"iam","x-public":true}},"/v1/iam/service-accounts/{name}/keys":{"post":{"operationId":"post_iam_service-accounts_by_name_keys","summary":"Serves POST /v1/iam/service-accounts/:name/keys: mint a fresh key, invalidating the prior one, and return the new raw secret exactly once.","description":"Serves POST /v1/iam/service-accounts/:name/keys: mint a fresh key,\ninvalidating the prior one, and return the new raw secret exactly once.","tags":["iam"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"iam","x-public":true}},"/v1/iam/sessions":{"get":{"operationId":"listSessions","summary":"Returns who is currently signed in to an organization, newest first, and can be narrowed to one person or one application.","description":"Returns who is currently signed in to an organization, newest first, and\ncan be narrowed to one person or one application. It is what you read before\nsigning someone out.\n\nWhich organization comes from your credentials, not from the request: you read\nyour own and no one else's. A session row names a live account and the\napplications it is signed in to, so the tenant is decided here rather than\ntaken from the query.","tags":["iam"],"parameters":[{"name":"owner","in":"query","required":false,"schema":{"type":"string"}},{"name":"name","in":"query","required":false,"schema":{"type":"string"}},{"name":"application","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.ListSessionsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"post":{"operationId":"createSession","summary":"Records a sign-in and answers with the cookie id it minted.","description":"Records a sign-in and answers with the cookie id it minted. Signing in\nagain from another browser adds to the session rather than replacing it, so one\nperson can be signed in from a laptop and a phone at once.\n\nAsk for an exclusive sign-in and the opposite holds: the new sign-in is the only\none left and every other browser is signed out. That is the setting to use when\none person may hold only one live session at a time.","tags":["iam"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.CreateSessionIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Session"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/sessions/{owner}/{name}/{application}":{"delete":{"operationId":"deleteSession","summary":"Signs a person out of one application — the session ends and every browser carrying it stops being authenticated.","description":"Signs a person out of one application — the session ends and every\nbrowser carrying it stops being authenticated.\n\nA session that is already gone reports that nothing was deleted rather than an\nerror, so the call is safe to repeat.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"application","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.DeleteSessionOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"get":{"operationId":"getSession","summary":"Returns one person's session in one application — when it began and which browsers or devices are still carrying it.","description":"Returns one person's session in one application — when it began and which\nbrowsers or devices are still carrying it.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"application","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Session"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"put":{"operationId":"updateSession","summary":"Names the browsers a session keeps — signing out the ones you leave off while the session itself stays live.","description":"Names the browsers a session keeps — signing out the ones you leave off\nwhile the session itself stays live. A session that does not exist is reported\nas missing rather than created.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"application","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.UpdateSessionIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Session"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/signin":{"post":{"operationId":"post_iam_signin","summary":"Completes a sign-in: it exchanges the one-time code your application was handed at the end of the login flow for a live session, and returns the signed-in account.","description":"Completes a sign-in: it exchanges the one-time code your\napplication was handed at the end of the login flow for a live session, and\nreturns the signed-in account.\n\nThe code works once. This is the call that turns a finished login into\nsomething your application can act on.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/signup":{"post":{"operationId":"post_iam_signup","summary":"Creates an account from the sign-up form and applies the application's own sign-up rules — whether self-service registration is open at all, and which fields it requires.","description":"Creates an account from the sign-up form and applies the\napplication's own sign-up rules — whether self-service registration is open at\nall, and which fields it requires.\n\nThe password is hashed before it is stored and is never returned.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/teams":{"get":{"operationId":"get_iam_teams","summary":"Returns your organization's teams, newest first — each a named set of people that roles and permissions are granted to.","description":"Returns your organization's teams, newest first — each a named set of\npeople that roles and permissions are granted to.\n\nYou see your own organization's teams and no one else's; which organization\nthat is comes from your credentials, not from the request.","tags":["iam"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.teams.ListOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"post":{"operationId":"post_iam_teams","summary":"Makes a team — a named set of people that roles and permissions grant to.","description":"Makes a team — a named set of people that roles and permissions grant\nto. Granting to a team rather than to each person keeps access correct as\npeople come and go: add someone and they inherit what the team can do. A name\nalready used in your organization is refused.","tags":["iam"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.teams.Input"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Team"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/teams/{name}":{"delete":{"operationId":"delete_iam_teams_by_name","summary":"Removes a team.","description":"Removes a team. Everyone in it loses the access it carried; their\naccounts, and any other team they are in, are untouched.","tags":["iam"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.teams.DeleteOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"get":{"operationId":"get_iam_teams_by_name","summary":"Returns one team: who is in it.","description":"Returns one team: who is in it.","tags":["iam"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Team"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"put":{"operationId":"put_iam_teams_by_name","summary":"Changes who is in a team.","description":"Changes who is in a team. Access changes for\neveryone in it as soon as the write lands. The name and the created stamp do\nnot change.","tags":["iam"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name addresses the team on update and names it on create; every other\nfield is content and binds from the BODY, never the URL.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.teams.Input"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Team"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/terms":{"put":{"operationId":"put_iam_terms","summary":"Records that the signed-in caller accepted the terms and the acceptable use policy, at the versions named.","description":"Records that the signed-in caller accepted the terms and the\nacceptable use policy, at the versions named. It is how a person who arrived by\na social provider, whose account the callback already made, records the same\nacceptance a code sign-up records at creation. Only the caller's own row is\nreachable.","tags":["iam"],"parameters":[{"name":"Cookie","in":"header","required":false,"schema":{"type":"string"}},{"name":"Authorization","in":"header","required":false,"schema":{"type":"string"}},{"name":"Sec-Fetch-Site","in":"header","required":false,"schema":{"type":"string"}},{"name":"Origin","in":"header","required":false,"schema":{"type":"string"}},{"name":"Host","in":"header","required":false,"schema":{"type":"string"}},{"name":"Content-Type","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-Forwarded-For","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.termsBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"ok"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"bad request"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Answer"}}},"description":"forbidden"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/tokens":{"get":{"operationId":"listTokens","summary":"Returns the access tokens issued in your organization, newest first, and can be narrowed to one organization.","description":"Returns the access tokens issued in your organization, newest\nfirst, and can be narrowed to one organization. Use it to see what is currently\nauthorized before revoking anything.","tags":["iam"],"parameters":[{"name":"owner","in":"query","required":false,"schema":{"type":"string"}},{"name":"organization","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.listTokensOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"post":{"operationId":"addToken","summary":"Records an access token — the credential an application or integration presents on a caller's behalf.","description":"Records an access token — the credential an application or integration\npresents on a caller's behalf.","tags":["iam"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Token"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.tokenResult"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/tokens/issue":{"post":{"operationId":"post_iam_tokens_issue","summary":"Mints an access token for the `?id=\u003cowner\u003e/\u003cname\u003e` target user (optional `?aud=` resource, RFC 8707), issued by the authenticated + allow-listed confidential client.","description":"Mints an access token for the `?id=\u003cowner\u003e/\u003cname\u003e` target\nuser (optional `?aud=` resource, RFC 8707), issued by the authenticated +\nallow-listed confidential client. The token's subject + owner are the TARGET\nUSER's, so a resource server scopes on the validated owner claim to the user's\ntenant — indistinguishable from a token the user obtained directly. Response is\nthe camelCase `{accessToken, expiresIn}` body identity.ts consumes. Equivalent to\nthe RFC 8693 token-exchange grant, minus the subject_token proof (the console has\nthe user's id, not a token) — the reason this compat shim exists.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/tokens/{owner}/{name}":{"delete":{"operationId":"deleteToken","summary":"Revokes an access token.","description":"Revokes an access token. Whatever was using it stops being\nauthorized at once.\n\nA token that is already gone answers \"nothing changed\" rather than an error, so\nthe call is safe to repeat.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.tokenMutation"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"get":{"operationId":"getToken","summary":"Returns one access token: who and what it was issued to, and when it expires.","description":"Returns one access token: who and what it was issued to, and when it\nexpires.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.tokenResult"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"put":{"operationId":"updateToken","summary":"Changes an access token's scope or expiry.","description":"Changes an access token's scope or expiry.\n\nA token that is not there answers \"nothing changed\" rather than an error, so\nthe call is safe to repeat.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Token"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.tokenMutation"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/unlink":{"post":{"operationId":"post_iam_unlink","summary":"Disconnects one sign-in identity from an account, so that provider can no longer be used to sign in as that person.","description":"Disconnects one sign-in identity from an account, so that provider can\nno longer be used to sign in as that person. Their account and every other way\nthey sign in are untouched. Two principals may do it, and\nonly two: the account holder itself, and a SuperAdmin (schema.User.SuperAdmin,\nasked of the caller's own row). An ORG ADMIN deliberately may NOT — unlinking\nis not tenant administration, it is unpicking someone's own sign-in method, so\nthe generic org-admin rule is the wrong answer here. A SuperAdmin unlinking\nsomeone else's method is recorded on the SuperAdmin trail.\n\nA holder unlinking itself must also be permitted by the application — the\nprovider link's CanUnlink flag — so an organization that mandates federated\nsign-in cannot have its users strand themselves. A SuperAdmin is not bound by\nthat flag; it is the platform's own recovery path. Fail-closed throughout.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/users":{"get":{"operationId":"get_iam_users","summary":"Returns a page of the people in an organization, with the total so you can page through the rest.","description":"Returns a page of the people in an organization, with the total so you\ncan page through the rest. Passwords, API secrets and MFA material are stripped\nfrom every entry.\n\nWhich organization comes from your credentials, not from the request: you read\nyour own and no one else's, and a credential whose scope spans tenants reads\nthe tenant it names — or, naming none, every one of them.","tags":["iam"],"parameters":[{"name":"owner","in":"query","required":false,"schema":{"type":"string"}},{"name":"email","in":"query","required":false,"description":"Email narrows the page to the accounts carrying one address. Looking a\nperson up by their address is a QUERY over the collection, not an item\nread: an address is not the natural key, two rows in one org can carry\none, and a caller that gets a page SEES both — where a single-item read\nwould have to choose, and choosing is how somebody joins a team under a\ncolleague's identity.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"format":"int64","type":"integer"}},{"name":"offset","in":"query","required":false,"schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.ListOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"post":{"operationId":"post_iam_users","summary":"Adds a person to your organization.","description":"Adds a person to your organization. Send a password and it becomes the\none they sign in with; it is hashed before it is stored and never comes back\nin any response.\n\nThe username is checked against the same rule every account in the Hanzo Cloud\nis held to, whichever way it was created — this call, password signup, a social\nsign-in, or SCIM — so a name accepted here works everywhere.\n\nA name already taken in your organization is refused rather than overwritten.","tags":["iam"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.CreateInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.User"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/users/{owner}/{name}":{"delete":{"operationId":"delete_iam_users_by_owner_by_name","summary":"Removes a person from your organization.","description":"Removes a person from your organization. Their sessions stop working\nimmediately and the account is gone rather than suspended — to keep the record\nand only stop sign-in, update the user instead.\n\nA SuperAdmin's account is removed only by a SuperAdmin.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.DeleteOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"get":{"operationId":"get_iam_users_by_owner_by_name","summary":"Returns one person in your organization, addressed by their username or by their email address.","description":"Returns one person in your organization, addressed by their username or by\ntheir email address. Passwords, API secrets and MFA material are stripped from\nthe response.\n\nAn address that names two accounts names none: the read refuses rather than\npicking one, and says so instead of reporting \"no such user\". Handing back an\narbitrary one of two rows is how somebody gets added to a team under a\ncolleague's identity.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"email","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.User"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"put":{"operationId":"put_iam_users_by_owner_by_name","summary":"Changes a person's profile, their roles, or the credentials they sign in with.","description":"Changes a person's profile, their roles, or the credentials they sign\nin with. Send a password to reset it; leave it out and their current one keeps\nworking.\n\nWho they are does not change: their organization, username and the identifier\ntheir existing sessions are keyed on all survive the write, so an update never\nsigns anyone out.\n\nA SuperAdmin's account is changed only by a SuperAdmin.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.UpdateInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.User"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/users/{owner}/{name}/keys":{"delete":{"operationId":"delete_iam_users_by_owner_by_name_keys","summary":"Clears the target user's key of the requested TYPE (immediate revoke).","description":"Clears the target user's key of the requested TYPE (immediate\nrevoke). Scoped by the same `?type` field mint takes, so revoking the browser key\nleaves the server key working. A secret key's stored value is the sk- in its\nschema.Key row.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"iam","x-public":true},"post":{"operationId":"post_iam_users_by_owner_by_name_keys","summary":"(re)generates the target user's key of the requested TYPE and returns it once, over the shared authorizeMinter + mintTarget seam.","description":"(re)generates the target user's key of the requested TYPE and\nreturns it once, over the shared authorizeMinter + mintTarget seam. `?type=secret`\n(the default) yields the confidential sk-; `?type=publishable` yields the pk- that\nis safe to ship in client JS and resolves to an org, never a principal.\n\nIt writes the schema.Key row that the resolvers actually read. schema.User.AccessKey\nis not a credential and nothing resolves it, so a key stamped there would\nauthenticate nobody.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"iam","x-public":true}},"/v1/iam/verification-codes":{"post":{"operationId":"post_iam_verification-codes","summary":"Validates the request and asks otp to get a code to the person.","description":"Validates the request and asks otp to get a code to the\nperson. The request fields are read via fiber's FormValue — the escape hatch zip\nexposes for form bodies (multipart or urlencoded) — since the typed JSON Bind does\nnot apply here. v1 also accepts countryCode/method/checkUser/captchaType; iam\nignores them (the captcha/forget/MFA flows those drive are not ported), and\nCAPTCHA verification is likewise not enforced — iam models no captcha provider —\nso the code is issued once the destination and application validate.\n\nAn email is the designed sign-in mail, a link beside the code and from the\napplication's org as its reader knows it (otp.IssueLink), when the request's\nOrigin is the origin of one of the application's redirect URIs ([landing]);\notherwise it is the code alone.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/web3/nonce":{"get":{"operationId":"get_iam_web3_nonce","summary":"Starts a wallet sign-in: it returns a one-time challenge for the wallet to sign.","description":"Starts a wallet sign-in: it returns a one-time challenge for the wallet\nto sign. The challenge is good once and is tied to the site that asked for it,\nso a signature collected elsewhere cannot be replayed here. Pass your\napplication's clientId and, from a page at one of its registered redirect\norigins, the challenge names that page's site, which is what the wallet shows\nthe person.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/web3/verify":{"post":{"operationId":"post_iam_web3_verify","summary":"Completes a wallet sign-in: it verifies the signed challenge and, if it holds, signs the wallet's owner in.","description":"Completes a wallet sign-in: it verifies the signed challenge and, if it\nholds, signs the wallet's owner in.\n\nThis IS the login — it answers exactly as a password sign-in does, so the rest\nof your flow does not branch on how somebody arrived.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/webauthn-credentials":{"get":{"operationId":"listWebauthnCredentials","summary":"Returns the passkeys and security keys registered to one person, newest first — which device each lives on and when it was registered.","description":"Returns the passkeys and security keys registered to\none person, newest first — which device each lives on and when it was\nregistered.\n\nYours by default. Name somebody else and you get them only if you already\nadminister their account, which is the same authority that governs reading\ntheir user record — so this list can never show more people than the surface\nbeside it already does.\n\nThere is no organization-wide list, by design. Scoping to the ORG would hand an\norg admin every member's credential rows in one answer and a SuperAdmin every\ntenant's, while a plain member could not read even their own (an unnamed target\nfails the Guard's tenant rule). One scope answers both halves cleanly: the\nanswer is a person's, and the caller is that person unless they say otherwise\nand may.","tags":["iam"],"parameters":[{"name":"user","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.listWebauthnCredentialsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"post":{"operationId":"addWebauthnCredential","summary":"Registers a passkey or security key for a person, so they can sign in with their device instead of a password.","description":"Registers a passkey or security key for a person, so they\ncan sign in with their device instead of a password.","tags":["iam"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.WebauthnCredential"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.webauthnCredentialResult"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/webauthn-credentials/{owner}/{name}":{"delete":{"operationId":"deleteWebauthnCredential","summary":"Removes a passkey or security key — what you call when a device is lost.","description":"Removes a passkey or security key — what you call when\na device is lost. Make sure the person has another way to sign in first.\n\nA credential that is already gone answers \"nothing changed\" rather than an\nerror, so the call is safe to repeat.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.webauthnCredentialMutationResult"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"get":{"operationId":"getWebauthnCredential","summary":"Returns one passkey or security key: whose it is, what device it lives on, and when it was registered.","description":"Returns one passkey or security key: whose it is, what\ndevice it lives on, and when it was registered.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.webauthnCredentialResult"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"put":{"operationId":"updateWebauthnCredential","summary":"Renames a registered passkey or security key, so a person can tell their devices apart.","description":"Renames a registered passkey or security key, so a\nperson can tell their devices apart.\n\nA credential that is not there answers \"nothing changed\" rather than an error,\nso the call is safe to repeat.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.WebauthnCredential"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.webauthnCredentialMutationResult"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/webauthn/signin/begin":{"get":{"operationId":"get_iam_webauthn_signin_begin","summary":"Starts a passkey sign-in: it returns the challenge the person's authenticator signs.","description":"Starts a passkey sign-in: it returns the challenge the person's\nauthenticator signs.\n\nThe account is named in the query, and the challenge is bound to it, so what may\nanswer is decided here — by the server, from the row — and the finish checks the\nanswer against that decision rather than recomputing it.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/webauthn/signin/finish":{"post":{"operationId":"post_iam_webauthn_signin_finish","summary":"Verifies the signed challenge and signs the person in.","description":"Verifies the signed challenge and signs the person in.\n\nIt answers exactly as a password sign-in does — the same envelope, through the\nsame grant — so nothing downstream branches on how somebody arrived.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/webauthn/signup/begin":{"get":{"operationId":"get_iam_webauthn_signup_begin","summary":"Starts enrolling a passkey for the signed-in person: it returns the options their browser hands to the authenticator.","description":"Starts enrolling a passkey for the signed-in person: it returns the\noptions their browser hands to the authenticator.\n\nPasskeys already on the account are EXCLUDED, so a second enrollment on a device\nthat already holds one is refused by the authenticator itself rather than\nsilently producing a duplicate the person cannot tell apart.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/webauthn/signup/finish":{"post":{"operationId":"post_iam_webauthn_signup_finish","summary":"Verifies the newly created passkey and stores it, so the person can sign in with their device from then on.","description":"Verifies the newly created passkey and stores it, so the person\ncan sign in with their device from then on.\n\nOnly this site's own pages may finish an enrollment, and only as JSON.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/whoami":{"get":{"operationId":"get_iam_whoami","summary":"Tells you who the current caller is — the lightweight check a page makes on load to decide whether to render signed-in or signed-out.","description":"Tells you who the current caller is — the lightweight check a\npage makes on load to decide whether to render signed-in or signed-out.\n\nIt answers for a session cookie or a bearer token alike, and says plainly when\nnobody is signed in rather than failing.","tags":["iam"],"x-app":"iam","x-public":true}},"/v1/iam/workspaces":{"get":{"operationId":"get_iam_workspaces","summary":"Returns your organization's workspaces, newest first — the scope a team works in, alongside projects rather than instead of them.","description":"Returns your organization's workspaces, newest first — the scope a\nteam works in, alongside projects rather than instead of them.\n\nYou see your own organization's workspaces and no one else's; which organization that\nis comes from your credentials, not from the request.","tags":["iam"],"parameters":[{"name":"owner","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.workspaces.ListOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"post":{"operationId":"post_iam_workspaces","summary":"Makes a workspace inside your organization — the scope a team works in, alongside projects rather than instead of them.","description":"Makes a workspace inside your organization — the scope a team works in,\nalongside projects rather than instead of them. A name already used in the\norganization is refused.","tags":["iam"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.workspaces.Input"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Workspace"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/iam/workspaces/{owner}/{name}":{"delete":{"operationId":"delete_iam_workspaces_by_owner_by_name","summary":"Removes a workspace.","description":"Removes a workspace. The people and roles in your organization are\nunchanged; what goes is the scope itself.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.workspaces.DeleteOutput"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"get":{"operationId":"get_iam_workspaces_by_owner_by_name","summary":"Returns one workspace: what it is called and how it is set up.","description":"Returns one workspace: what it is called and how it is set up.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Workspace"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true},"put":{"operationId":"put_iam_workspaces_by_owner_by_name","summary":"Changes a workspace's settings.","description":"Changes a workspace's settings. What it is called does not change, and\nneither does when it was created.","tags":["iam"],"parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.workspaces.Input"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/iam.Workspace"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"iam","x-public":true,"x-tool":true}},"/v1/images/generations":{"post":{"operationId":"post_images_generations","summary":"Implements POST /v1/images/generations (OpenAI-compatible).","description":"Implements POST /v1/images/generations (OpenAI-compatible).\n\nBody: {\"model\": \"...\", \"prompt\": \"...\", \"n\"?: int, \"size\"?: \"1024x1024\",\n\n\t\"response_format\"?: \"url\"|\"b64_json\"}\n\nIt authenticates the caller, resolves the model to its upstream provider via\nthe shared routing table (zen3-image* → do-ai fal diffusion), reserves the\nper-image budget, generates the image(s) through the do-ai async image\nclient, records usage for billing, and returns the OpenAI images response.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/openai.ImageResponse"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/index/health":{"get":{"operationId":"get_index_health","summary":"Reports whether the search plane can serve.","description":"Reports whether the search plane can serve.\n\nAnswers the dialect's `{\"status\":\"available\"}` when the index store is\nreadable. It FAILS CLOSED — an unreadable store answers 503 with\n`{\"status\":\"unavailable\"}` rather than an empty result set, because a\nMeilisearch client probes this before it will use a server at all and a\ncheerful 200 over a broken volume turns \"search is down\" into \"nothing\nmatched\". It requires no principal and reads no tenant data.","tags":["index"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/index.indexHealth"}}},"description":"ok"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/index.indexHealth"}}},"description":"service unavailable"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"index","x-public":true,"x-tool":true}},"/v1/index/indexes":{"get":{"operationId":"get_index_indexes","summary":"Lists the indexes your org holds.","description":"Lists the indexes your org holds.\n\nAnswers every index in the caller's own org with its primary key and\ntimestamps. Without it an index whose uid a caller has forgotten is\nunreachable — there is no other way to enumerate what an org holds. The page\nis the whole set: an org's index count is small by construction, so `limit`\nand `total` both report it.\n\nThe tenant is the org minted from the VALIDATED bearer's owner claim, never a\nclient-supplied header, and two orgs may both hold an index named \"messages\"\nwithout either seeing the other. Without a validated principal the answer is\n403 carrying the dialect's `invalid_api_key` body.","tags":["index"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/index.indexList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"index","x-public":true,"x-tool":true},"post":{"operationId":"post_index_indexes","summary":"Creates an index.","description":"Creates an index.\n\nRegisters a named index in the caller's own org and answers the dialect's\nEnqueuedTask. It is idempotent: creating an index that already exists returns\nthe same receipt and changes nothing, which is what lets a client create on\nstartup without checking first.\n\n`primaryKey` is optional — the first write establishes one when it is omitted.\nAn index is a ROW here rather than a table, so an unusual uid is stored\nverbatim instead of being sanitised into a schema name.\n\nThe 202 and its `enqueued` task are DIALECT COMPATIBILITY, not a promise of\nlater work: the write is already applied when this answers. A client that\npolls waitForTask resolves immediately.","tags":["index"],"requestBody":{"content":{"application/json":{"example":{"primaryKey":"id","uid":"messages"},"schema":{"$ref":"#/components/schemas/index.indexNew"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/index.indexEnqueued"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"index","x-public":true,"x-tool":true}},"/v1/index/indexes/{uid}":{"delete":{"operationId":"delete_index_indexes_by_uid","summary":"Deletes an index and everything in it.","description":"Deletes an index and everything in it.\n\nDrops the index and every document in it from the caller's own org, and\nanswers the dialect's EnqueuedTask. This is the only way to retire an index;\nwithout it a mistaken uid is permanent. Deleting an index that is not there\nsucceeds, so a cleanup pass is safe to re-run.\n\nThe 202 and its `enqueued` task are DIALECT COMPATIBILITY, not a promise of\nlater work: the documents are already gone when this answers.","tags":["index"],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/index.indexEnqueued"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"index","x-public":true,"x-tool":true},"get":{"operationId":"get_index_indexes_by_uid","summary":"Reads one index's definition.","description":"Reads one index's definition.\n\nAnswers the index's uid, primary key and timestamps. An index this org does\nnot hold answers 404 carrying the dialect's `index_not_found` — the code a\nMeilisearch client reads as permission to create it, which is why this is a\nrefusal rather than an empty object.\n\nThe uid is scoped to the caller's own org, so another tenant's index is\nindistinguishable from one that never existed: this surface is not an\nexistence oracle.","tags":["index"],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/index.indexView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"index","x-public":true,"x-tool":true}},"/v1/index/indexes/{uid}/documents":{"get":{"operationId":"get_index_indexes_by_uid_documents","summary":"Pages through the documents in an index.","description":"Pages through the documents in an index.\n\nAnswers the org's stored documents in insertion order, whole, with the page's\nbounds and the index's total. It is the enumeration surface — search ranks by\nrelevance and cannot walk a corpus — so a caller reconciling what it has\nwritten reads it here.\n\nAn index this org does not hold answers 404 carrying the dialect's\n`index_not_found`.","tags":["index"],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/index.indexDocuments"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"index","x-public":true,"x-tool":true},"post":{"operationId":"post_index_indexes_by_uid_documents","summary":"Add or replace documents in an index","description":"Writes documents into the caller's own index, keyed by the index's primary key: a document whose key is already present is REPLACED whole. The body is the dialect's own — an array of documents, or a single document — and each is stored verbatim, so a read gives back exactly what was written.\n\nThe index is CREATED when it is missing rather than refused, because a Meilisearch client writes before it configures.\n\nThe tenant is the org minted from the VALIDATED bearer's owner claim, never a client-supplied header, so two orgs may both hold an index named \"messages\" and neither can see the other's documents. Without a validated principal the answer is 403 carrying the dialect's `invalid_api_key` body.\n\nThe 202 and its `enqueued` task are DIALECT COMPATIBILITY, not a promise of later work: the documents are searchable when this answers, and a client that polls waitForTask resolves immediately.","tags":["index"],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"items":{},"type":"array"},{}]}}}},"responses":{"2XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/indexEnqueued"}}},"description":"Success"}},"x-app":"index","x-public":true},"put":{"operationId":"put_index_indexes_by_uid_documents","summary":"Add or update documents in an index","description":"The dialect's update spelling of the write above, and the same act: an upsert keyed by the index's primary key. The JS client's addDocuments and updateDocuments both reduce to this for whole documents, so both spellings are served and both behave identically.\n\nThe tenant is the org minted from the VALIDATED bearer's owner claim, never a client-supplied header. Without a validated principal the answer is 403 carrying the dialect's `invalid_api_key` body.\n\nThe 202 and its `enqueued` task are DIALECT COMPATIBILITY, not a promise of later work: the write is already applied when this answers.","tags":["index"],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"items":{},"type":"array"},{}]}}}},"responses":{"2XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/indexEnqueued"}}},"description":"Success"}},"x-app":"index","x-public":true}},"/v1/index/indexes/{uid}/documents/delete-batch":{"post":{"operationId":"post_index_indexes_by_uid_documents_delete-batch","summary":"Delete many documents by primary key in one call","description":"Removes every named document from the caller's own index. The body is the dialect's own: a bare array of primary keys, which may be strings or numbers. A key that is not there is not an error, so a client reconciling its own corpus can send one list rather than checking each key first.\n\nThe tenant is the org minted from the VALIDATED bearer's owner claim, never a client-supplied header. Without a validated principal the answer is 403 carrying the dialect's `invalid_api_key` body.\n\nThe 202 and its `enqueued` task are DIALECT COMPATIBILITY, not a promise of later work: the documents are already gone when this answers.","tags":["index"],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"items":{},"type":"array"}}}},"responses":{"2XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/indexEnqueued"}}},"description":"Success"}},"x-app":"index","x-public":true}},"/v1/index/indexes/{uid}/documents/{id}":{"delete":{"operationId":"delete_index_indexes_by_uid_documents_by_id","summary":"Deletes one document by its primary key.","description":"Deletes one document by its primary key.\n\nRemoves the document from the caller's own org and answers the dialect's\nEnqueuedTask. Deleting a key that is not there succeeds, so a client\nreconciling its own corpus can delete without checking first.\n\nThe 202 and its `enqueued` task are DIALECT COMPATIBILITY, not a promise of\nlater work: the document is already gone when this answers.","tags":["index"],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/index.indexEnqueued"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"index","x-public":true,"x-tool":true},"get":{"operationId":"get_index_indexes_by_uid_documents_by_id","summary":"Reads one document by its primary key.","description":"Reads one document by its primary key.\n\nAnswers the stored document exactly as it was written — this surface keeps\ndocuments whole rather than projecting them, so what comes back is what went\nin. A primary key this index does not hold answers 404 carrying the dialect's\n`document_not_found`; an index this org does not hold answers\n`index_not_found`, and the two are different facts a client acts on\ndifferently.","tags":["index"],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"index","x-public":true,"x-tool":true}},"/v1/index/indexes/{uid}/search":{"post":{"operationId":"post_index_indexes_by_uid_search","summary":"Searches an index, forgiving typos.","description":"Searches an index, forgiving typos.\n\nRanks the org's documents in one index against `q` and answers the matching\ndocuments whole, most relevant first. A prefix matches, so a partial word\nfinds the documents containing it, and `filter` narrows the result to\ndocuments whose filterable attributes match — which is how a caller scopes\nresults to one end user within its own org.\n\n`estimatedTotalHits` is the dialect's name for the count; every hit is\nmaterialised here, so for this page it is exact. An index this org does not\nhold answers 404 carrying the dialect's `index_not_found`.","tags":["index"],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"filter":"user = alice","limit":20,"q":"roadmap"},"schema":{"$ref":"#/components/schemas/index.indexQuery"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/index.indexHits"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"index","x-public":true,"x-tool":true}},"/v1/index/indexes/{uid}/settings":{"get":{"operationId":"get_index_indexes_by_uid_settings","summary":"Reads an index's filterable attributes.","description":"Reads an index's filterable attributes.\n\nAnswers the settings subset this surface implements: the attributes a search\n`filter` may constrain. An index this org does not hold answers 404 carrying\nthe dialect's `index_not_found`.","tags":["index"],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/index.indexSettings"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"index","x-public":true,"x-tool":true},"patch":{"operationId":"patch_index_indexes_by_uid_settings","summary":"Sets which attributes an index can be filtered on.","description":"Sets which attributes an index can be filtered on.\n\nReplaces the whole filterable set. An attribute not listed here cannot be\nused in a search `filter`, so this is what makes a per-user or per-tag\nnarrowing possible at all.\n\nIt CREATES the index when it is missing rather than answering 404, because a\nMeilisearch client configures settings on an index it has just asked for and\na refusal there leaves the client with no index at all.\n\nThe 202 and its `enqueued` task are DIALECT COMPATIBILITY, not a promise of\nlater work: the setting is already applied when this answers.","tags":["index"],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"filterableAttributes":["user","conversationId"]},"schema":{"$ref":"#/components/schemas/index.indexFilter"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/index.indexEnqueued"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"index","x-public":true,"x-tool":true}},"/v1/index/stats":{"get":{"operationId":"get_index_stats","summary":"Counts the documents in each of your indexes.","description":"Counts the documents in each of your indexes.\n\nReports every index the caller's own org holds with its document count, plus\nthe org's total. `isIndexing` is always false because writes here are applied\nbefore their response — there is never a background pass to wait on.\n\nThe tenant is the org minted from the VALIDATED bearer's owner claim, never a\nclient-supplied header, so this counts the caller's own documents and no\nother tenant's. Without a validated principal the answer is 403 carrying the\ndialect's `invalid_api_key` body.","tags":["index"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/index.indexStats"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"index","x-public":true,"x-tool":true}},"/v1/index/tasks/{uid}":{"get":{"operationId":"get_index_tasks_by_uid","summary":"Checks a write task, which has already finished.","description":"Checks a write task, which has already finished.\n\nAlways reports `succeeded`. Writes here are applied to SQLite before their\nEnqueuedTask is returned, so a client polling waitForTask resolves on its\nfirst call rather than waiting for a queue that was never there. The three\ntimestamps are the same instant for the same reason.\n\nIt requires a validated principal but reads no tenant data: the task id it\nechoes was minted by this process and names nothing about any org.","tags":["index"],"parameters":[{"name":"uid","in":"path","required":true,"schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/index.indexTask"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"index","x-public":true,"x-tool":true}},"/v1/index/version":{"get":{"operationId":"get_index_version","summary":"Identifies the search implementation answering.","description":"Identifies the search implementation answering.\n\nReports the dialect's version shape with `commitSha` naming this\nimplementation rather than a Meilisearch build, so a client that logs the\nversion records which server answered instead of implying a release of\nsoftware this is not. It requires no principal and reads no tenant data.","tags":["index"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/index.indexVersion"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"index","x-public":true,"x-tool":true}},"/v1/ingress/middlewares":{"get":{"operationId":"get_ingress_middlewares","summary":"Returns every edge transform the caller's org has configured, ordered by id.","description":"Returns every edge transform the caller's org has configured,\nordered by id. A route names the ones it wants, in order.","tags":["ingress"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ingress.ingressMiddlewares"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ingress","x-public":true,"x-tool":true},"post":{"operationId":"post_ingress_middlewares","summary":"Creates or replaces one edge transform and hot-applies it.","description":"Creates or replaces one edge transform and hot-applies it. POST\nmints an id when the body omits one; PUT takes the id from the URL, which wins\nover any id in the body. type must be one of redirectScheme, stripPrefix,\naddPrefix or headers, and stripPrefix/addPrefix each require their config key.","tags":["ingress"],"requestBody":{"content":{"application/json":{"example":{"config":{"prefixes":"/api"},"id":"strip-api","type":"stripPrefix"},"schema":{"$ref":"#/components/schemas/ingress.Middleware"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ingress.Middleware"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ingress","x-public":true,"x-tool":true}},"/v1/ingress/middlewares/{id}":{"delete":{"operationId":"delete_ingress_middlewares_by_id","summary":"Removes one of the caller org's edge transforms and hot-applies the change.","description":"Removes one of the caller org's edge transforms and hot-applies\nthe change. Routes still naming it stop being served (they compile as skipped)\nuntil they name a transform that exists. Answers 204; an id this org does not\nhold is 404.","tags":["ingress"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the object to act on, from the path.","schema":{"type":"string"},"example":"strip-api"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ingress","x-public":true,"x-tool":true},"get":{"operationId":"get_ingress_middlewares_by_id","summary":"Returns one of the caller org's edge transforms by id.","description":"Returns one of the caller org's edge transforms by id.","tags":["ingress"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the object to act on, from the path.","schema":{"type":"string"},"example":"strip-api"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ingress.Middleware"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ingress","x-public":true,"x-tool":true},"put":{"operationId":"put_ingress_middlewares_by_id","summary":"Creates or replaces one edge transform and hot-applies it.","description":"Creates or replaces one edge transform and hot-applies it. POST\nmints an id when the body omits one; PUT takes the id from the URL, which wins\nover any id in the body. type must be one of redirectScheme, stripPrefix,\naddPrefix or headers, and stripPrefix/addPrefix each require their config key.","tags":["ingress"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID identifies the transform within the org: [A-Za-z0-9-_.], at most 128\nchars. A create that omits it gets a generated one. Routes reference it by\nthis id.","schema":{"type":"string"},"example":"strip-api"}],"requestBody":{"content":{"application/json":{"example":{"config":{"prefixes":"/api"},"id":"strip-api","type":"stripPrefix"},"schema":{"$ref":"#/components/schemas/ingress.Middleware"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ingress.Middleware"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ingress","x-public":true,"x-tool":true}},"/v1/ingress/routes":{"get":{"operationId":"get_ingress_routes","summary":"Returns every routing rule the caller's org has configured, ordered by id.","description":"Returns every routing rule the caller's org has configured, ordered\nby id. A route maps an exact Host (and optional path prefix) to a service.","tags":["ingress"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ingress.ingressRoutes"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ingress","x-public":true,"x-tool":true},"post":{"operationId":"post_ingress_routes","summary":"Creates or replaces one routing rule and hot-applies the new table — there is no config file and no restart.","description":"Creates or replaces one routing rule and hot-applies the new table —\nthere is no config file and no restart. POST mints an id when the body omits\none; PUT takes the id from the URL, which wins over any id in the body. A\nroute's host is a GLOBALLY unique DNS claim: a host another org's route already\nholds is refused 409, so no tenant can hijack another's hostname.","tags":["ingress"],"requestBody":{"content":{"application/json":{"example":{"host":"app.example.com","id":"web","service":"app-pool","tls":true},"schema":{"$ref":"#/components/schemas/ingress.Route"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ingress.Route"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ingress","x-public":true,"x-tool":true}},"/v1/ingress/routes/{id}":{"delete":{"operationId":"delete_ingress_routes_by_id","summary":"Removes one of the caller org's routing rules and hot-applies the shrunken table, freeing its host for another claim.","description":"Removes one of the caller org's routing rules and hot-applies the\nshrunken table, freeing its host for another claim. Answers 204; an id this org\ndoes not hold is 404.","tags":["ingress"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the object to act on, from the path.","schema":{"type":"string"},"example":"web"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ingress","x-public":true,"x-tool":true},"get":{"operationId":"get_ingress_routes_by_id","summary":"Returns one of the caller org's routing rules by id.","description":"Returns one of the caller org's routing rules by id.","tags":["ingress"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the object to act on, from the path.","schema":{"type":"string"},"example":"a1b2c3d4e5f60718"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ingress.Route"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ingress","x-public":true,"x-tool":true},"put":{"operationId":"put_ingress_routes_by_id","summary":"Creates or replaces one routing rule and hot-applies the new table — there is no config file and no restart.","description":"Creates or replaces one routing rule and hot-applies the new table —\nthere is no config file and no restart. POST mints an id when the body omits\none; PUT takes the id from the URL, which wins over any id in the body. A\nroute's host is a GLOBALLY unique DNS claim: a host another org's route already\nholds is refused 409, so no tenant can hijack another's hostname.","tags":["ingress"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID identifies the route within the org: [A-Za-z0-9-_.], at most 128 chars.\nA create that omits it gets a generated one.","schema":{"type":"string"},"example":"web"}],"requestBody":{"content":{"application/json":{"example":{"host":"app.example.com","id":"web","service":"app-pool","tls":true},"schema":{"$ref":"#/components/schemas/ingress.Route"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ingress.Route"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ingress","x-public":true,"x-tool":true}},"/v1/ingress/services":{"get":{"operationId":"get_ingress_services","summary":"Returns every backend pool the caller's org has configured, ordered by id.","description":"Returns every backend pool the caller's org has configured,\nordered by id. A service is the weighted round-robin target a route dispatches\nto.","tags":["ingress"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ingress.ingressServices"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ingress","x-public":true,"x-tool":true},"post":{"operationId":"post_ingress_services","summary":"Creates or replaces one backend pool and hot-applies it.","description":"Creates or replaces one backend pool and hot-applies it. POST mints\nan id when the body omits one; PUT takes the id from the URL, which wins over\nany id in the body. A pool needs at least one backend and every backend URL\nmust be http(s)://host[:port].","tags":["ingress"],"requestBody":{"content":{"application/json":{"example":{"backends":[{"url":"http://10.0.0.7:8000","weight":1}],"id":"app-pool"},"schema":{"$ref":"#/components/schemas/ingress.Upstream"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ingress.Upstream"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ingress","x-public":true,"x-tool":true}},"/v1/ingress/services/{id}":{"delete":{"operationId":"delete_ingress_services_by_id","summary":"Removes one of the caller org's backend pools and hot-applies the change.","description":"Removes one of the caller org's backend pools and hot-applies the\nchange. Routes still pointing at it stop being served (they compile as skipped)\nuntil they name a pool that exists. Answers 204; an id this org does not hold\nis 404.","tags":["ingress"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the object to act on, from the path.","schema":{"type":"string"},"example":"app-pool"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ingress","x-public":true,"x-tool":true},"get":{"operationId":"get_ingress_services_by_id","summary":"Returns one of the caller org's backend pools by id.","description":"Returns one of the caller org's backend pools by id.","tags":["ingress"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the object to act on, from the path.","schema":{"type":"string"},"example":"app-pool"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ingress.Upstream"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ingress","x-public":true,"x-tool":true},"put":{"operationId":"put_ingress_services_by_id","summary":"Creates or replaces one backend pool and hot-applies it.","description":"Creates or replaces one backend pool and hot-applies it. POST mints\nan id when the body omits one; PUT takes the id from the URL, which wins over\nany id in the body. A pool needs at least one backend and every backend URL\nmust be http(s)://host[:port].","tags":["ingress"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID identifies the pool within the org: [A-Za-z0-9-_.], at most 128 chars.\nA create that omits it gets a generated one. Routes reference it by this id.","schema":{"type":"string"},"example":"app-pool"}],"requestBody":{"content":{"application/json":{"example":{"backends":[{"url":"http://10.0.0.7:8000","weight":1}],"id":"app-pool"},"schema":{"$ref":"#/components/schemas/ingress.Upstream"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ingress.Upstream"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ingress","x-public":true,"x-tool":true}},"/v1/ingress/status":{"get":{"operationId":"get_ingress_status","summary":"Reports the ingress edge's live posture: the role this instance runs in (app or edge), whether its listeners are bound and on which addresses, the ACME posture (staging flag and certificate cache directory), how many hosts the compiled route table currently serves, and how many the ACME HostPolicy will issue a certificate for.","description":"Reports the ingress edge's live posture: the role this instance runs in\n(app or edge), whether its listeners are bound and on which addresses, the ACME\nposture (staging flag and certificate cache directory), how many hosts the\ncompiled route table currently serves, and how many the ACME HostPolicy will\nissue a certificate for.","tags":["ingress"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ingress.ingressStatus"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ingress","x-public":true,"x-tool":true}},"/v1/ingress/tls":{"get":{"operationId":"get_ingress_tls","summary":"Returns the caller org's ACME intent together with the edge-wide TLS facts it lands in: which role this instance runs in, whether its listeners are bound, every host the ACME HostPolicy will issue a certificate for (the union across ALL orgs of TLS-marked routes and configured extraHosts, because one process holds one certificate cache), and the ACME directory and account email the process was started with.","description":"Returns the caller org's ACME intent together with the edge-wide TLS\nfacts it lands in: which role this instance runs in, whether its listeners are\nbound, every host the ACME HostPolicy will issue a certificate for (the union\nacross ALL orgs of TLS-marked routes and configured extraHosts, because one\nprocess holds one certificate cache), and the ACME directory and account email\nthe process was started with.","tags":["ingress"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ingress.ingressTLS"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ingress","x-public":true,"x-tool":true},"put":{"operationId":"put_ingress_tls","summary":"Replaces the caller org's ACME intent and hot-applies what can be hot-applied.","description":"Replaces the caller org's ACME intent and hot-applies what can be\nhot-applied. extraHosts are normalized and validated, then feed the ACME\nHostPolicy on the reload this op performs, alongside the per-route tls flags.\nacmeEmail and staging bind an ACME account for the lifetime of an edge process,\nso they only take effect when the edge (re)starts — the returned note says so.","tags":["ingress"],"requestBody":{"content":{"application/json":{"example":{"extraHosts":["www.example.com"]},"schema":{"$ref":"#/components/schemas/ingress.TLSConfig"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ingress.TLSConfig"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ingress","x-public":true,"x-tool":true}},"/v1/kms/auth/login":{"post":{"operationId":"post_kms_auth_login","summary":"Exchanges a machine credential for an IAM bearer token.","description":"Exchanges a machine credential for an IAM bearer token.\n\nTakes a tenant's machine credential — a client id and client secret — and\nreturns an owner-scoped IAM access token with its lifetime, which is the\nbearer the caller then carries on the org-scoped secret operations.\n\nIt is deliberately public and unauthenticated, because it IS the credential\nexchange and runs before any principal exists. That makes it the one route in\nthis subsystem rate-limited PER SOURCE IP, keyed on the real TCP peer rather\nthan on any caller-supplied header, and body-capped in the same place.\n\nThe submitted secret is never logged and never echoed, and failures collapse\nto one clean status with no upstream detail: 401 when the credential does not\nauthenticate, 502 when the identity provider is unreachable, 503 when no\nissuer is configured. That is on purpose — a richer error would be a validity\noracle for guessed credentials.","tags":["kms"],"requestBody":{"content":{"application/json":{"example":{"clientId":"kms-operator","clientSecret":"…"},"schema":{"$ref":"#/components/schemas/kms.kmsLogin"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/kms.kmsToken"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"kms","x-public":true,"x-tool":true}},"/v1/kms/config":{"get":{"operationId":"get_kms_config","summary":"Returns the runtime configuration for the KMS console.","description":"Returns the runtime configuration for the KMS console.\n\nWhat the console needs before anyone has signed in: the brand, the OIDC issuer\nit authenticates against, the API base for this subsystem and the path of the\nlogin exchange.\n\nPublic on purpose, and it holds nothing sensitive — it is deliberately kept\nunder this subsystem's own namespace rather than under an admin prefix, so a\ngateway that admin-gates the admin routes cannot break the console's\nlegitimate pre-login fetch.","tags":["kms"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/kms.kmsConfig"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"kms","x-public":true,"x-tool":true}},"/v1/kms/health":{"get":{"operationId":"get_kms_health","summary":"Reports whether this broker can actually serve secrets.","description":"Reports whether this broker can actually serve secrets.\n\nA real readiness probe, not a liveness stub: 200 only when the store is open\nAND a master key is configured, with `signing` reporting whether signing keys\nare set up too. Anything less answers 503 with `ready:false` and the reason —\nno in-process store, or no master key — which are exactly the two states in\nwhich the secret operations refuse.\n\nNot token-gated, because the platform must be able to probe it without a\ncredential. It reports the broker's configuration state only; no secret, no\nkey material and no tenant name appears in it.","tags":["kms"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/kms.kmsHealth"}}},"description":"ok"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/kms.kmsHealth"}}},"description":"service unavailable"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"kms","x-public":true,"x-tool":true}},"/v1/kms/secrets":{"get":{"operationId":"get_kms_secrets","summary":"Lists the secrets your org holds, without their values.","description":"Lists the secrets your org holds, without their values.\n\nReturns the METADATA of the caller's own secrets: each one's name, path,\nenvironment and sealing scheme. No value and no ciphertext is included — this\noperation exists to enumerate what is held, and reading a value is a separate,\nper-secret call.\n\nScoped to the caller's own org and nothing else, structurally: there is no org\nin the path, the store root is derived from the validated org claim, and a\ncaller therefore has no way to name another tenant's namespace. `path` narrows\nto a subpath and `env` selects the environment; both are also accepted under\nthe operator's spellings, `secretPath` and `environment`. An omitted `env`\nmeans every environment and an omitted `path` means the whole org, because a\ndefault here reported a populated store as empty.\n\nWho sees what: a SuperAdmin holding an access token (audited) sees every name,\nand so does an admin of the org holding their own access token, outside the\nbrand and platform orgs, whose stores are the platform's. Any other caller sees\nonly the names a declared grant lets it read or write, and is refused with a 403\nwhen none of its grants lies inside the subtree asked about. Membership alone\nshows nothing.\n\nAdmission is fail-closed and in order: a validated member, an org that is a\nDNS-1123 label, a store holding a master key, well-formed input, then who may\nlist — 403, 400, 503, 400 and 403 respectively, all decided before any record\nis touched.","tags":["kms"],"parameters":[{"name":"env","in":"query","required":false,"description":"Env selects the environment, which is part of a secret's storage key.\nOMITTED means EVERY environment — this is the enumeration surface, so it\nmust be able to answer \"what is in here\" without being told where to look.","schema":{"type":"string"}},{"name":"environment","in":"query","required":false,"description":"Environment is the KMS operator's spelling of Env, accepted so one caller\nneed not learn the other's vocabulary. Env wins when both are sent.","schema":{"type":"string"}},{"name":"path","in":"query","required":false,"description":"Path narrows the listing to one subtree beneath the caller's org root, as\na `/`-separated path such as `/ci`. OMITTED means the whole org.","schema":{"type":"string"}},{"name":"secretPath","in":"query","required":false,"description":"SecretPath is the KMS operator's spelling of Path. Path wins when both are\nsent.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/kms.kmsSecrets"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"kms","x-public":true,"x-tool":true},"post":{"operationId":"post_kms_secrets","summary":"Stores or replaces one secret in your org.","description":"Stores or replaces one secret in your org.\n\nUpserts one secret under the caller's own org. The value is sealed before it\nis written — a fresh per-secret data key, itself wrapped by the master key —\nso plaintext never reaches disk. The receipt confirms the name and environment\nthat were written and does not echo the value.\n\n`env` is REQUIRED on a write and has no default, which is the rule most easily\ngot wrong here: reads and deletes still fall back to the default environment\nfor older callers, but a write must not, because the environment is part of\nthe storage key. A silently defaulted write lands in a bucket the readers that\nresolve project, environment and path never look in, and the stale value keeps\nbeing served — so the write fails loudly instead.\n\n`name` is required, `path` is an optional subpath beneath the org root, and\nthe org is taken from the validated claim rather than the body.\n\nOpens only for SuperAdmin holding an access token, audited, or for a holder\na declared WRITE grant covers at this exact path, key and environment. Org\nadmin confers nothing here. Fail-closed admission, in order: a validated\nmember, well-formed org, master key present, well-formed input, then the\ngrant — 401/403, 400, 503, 400 and 403, all decided before any record is\ntouched.\n\nA value this deployment seals on the org's behalf — an MCP server's\ncredential, a wallet's signing key, a delivery provider's token — is written\nby the app that holds it, through that app's own operation, and is never\nreplaced here for membership or org admin, whatever the grant declaration\nsays about enforcement.","tags":["kms"],"requestBody":{"content":{"application/json":{"example":{"env":"prod","name":"deploy-token","path":"/ci","value":"s3cr3t"},"schema":{"$ref":"#/components/schemas/kms.kmsPut"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/kms.kmsStored"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"kms","x-public":true,"x-tool":true}},"/v1/knowledge/connectors":{"get":{"operationId":"get_knowledge_connectors","summary":"Returns every supported knowledge connector with THIS org's connection state and the REAL number of documents each has ingested into the org's store.","description":"Returns every supported knowledge connector with THIS org's\nconnection state and the REAL number of documents each has ingested into the\norg's store. A provider that is configured for the deployment but not yet\nconnected appears as disconnected, so the console can offer a Connect button.\nNo secret is ever returned.","tags":["knowledge"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/knowledge.kbConnectorsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"knowledge","x-public":true,"x-tool":true}},"/v1/knowledge/connectors/catalog":{"get":{"operationId":"get_knowledge_connectors_catalog","summary":"Returns the ONE catalog of everything a caller can connect: every first-party connector and every long-tail one, in a single list sorted by provider.","description":"Returns the ONE catalog of everything a caller can\nconnect: every first-party connector and every long-tail one, in a single list\nsorted by provider. `configured` reports whether this deployment holds OAuth\ncredentials for a source, so the console can show Connect rather than a dead\nbutton, and `kind` is a badge only — the connect and sync lifecycle is\nidentical for both. The catalog itself is org-independent; a validated\nprincipal is still required. It is metadata only: no secret is ever returned.","tags":["knowledge"],"responses":{"200":{"content":{"application/json":{"example":{"connectors":[{"configured":true,"description":"Repositories, READMEs, and issues.","displayName":"GitHub","kind":"native","provider":"github"}]},"schema":{"$ref":"#/components/schemas/knowledge.catalogOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"knowledge","x-public":true,"x-tool":true}},"/v1/knowledge/connectors/{provider}":{"delete":{"operationId":"delete_knowledge_connectors_by_provider","summary":"Revokes a connection: it tombstones the stored credential so a later sync cannot reuse it, removes this provider's passages from the org's store, and marks the connector disconnected.","description":"Revokes a connection: it tombstones the stored credential\nso a later sync cannot reuse it, removes this provider's passages from the\norg's store, and marks the connector disconnected. The documents already\ningested stay in the org's store — they are the org's own data — but stop being\nretrievable by search; a caller deletes them through the document surface.","tags":["knowledge"],"parameters":[{"name":"provider","in":"path","required":true,"description":"Provider is the connector to act on: github, slack, google or notion.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/knowledge.connectionOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"knowledge","x-public":true,"x-tool":true}},"/v1/knowledge/connectors/{provider}/callback":{"get":{"operationId":"get_knowledge_connectors_by_provider_callback","summary":"CompleteConnectorOAuth finishes an OAuth connection: it exchanges the provider's code for a token, seals that token in KMS, and records the connection.","description":"CompleteConnectorOAuth finishes an OAuth connection: it exchanges the\nprovider's code for a token, seals that token in KMS, and records the\nconnection. THE ORG COMES FROM THE SIGNED STATE, not from a header and not from\nthe provider, so an attacker cannot bind their own account to someone else's\norg — a tampered, expired or foreign-provider state is refused outright. The\ntoken itself is never returned, never written into the document, and never\nlogged; the document holds only its KMS path.","tags":["knowledge"],"parameters":[{"name":"provider","in":"path","required":true,"description":"Provider is the connector completing its flow, from the path.","schema":{"type":"string"}},{"name":"code","in":"query","required":false,"description":"Code is the provider's authorization code, exchanged for a token.","schema":{"type":"string"}},{"name":"state","in":"query","required":false,"description":"State is the org-bound value this server signed at connect time.","schema":{"type":"string"}},{"name":"error","in":"query","required":false,"description":"Error is the provider's denial reason when the user refused consent.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/knowledge.connectionOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"knowledge","x-public":true,"x-tool":true}},"/v1/knowledge/connectors/{provider}/connect":{"get":{"operationId":"get_knowledge_connectors_by_provider_connect","summary":"StartConnectorOAuth returns the provider authorize URL the console opens to connect this org's account.","description":"StartConnectorOAuth returns the provider authorize URL the console opens to\nconnect this org's account. There is no server-side redirect — the console\nstays in control of the navigation. The URL carries a state this server SIGNED\nover the caller's validated org, so the connection the callback completes can\nonly ever land in that org.","tags":["knowledge"],"parameters":[{"name":"provider","in":"path","required":true,"description":"Provider is the connector to act on: github, slack, google or notion.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/knowledge.kbAuthorizeOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"knowledge","x-public":true,"x-tool":true}},"/v1/knowledge/connectors/{provider}/sync":{"post":{"operationId":"post_knowledge_connectors_by_provider_sync","summary":"Pulls the provider's documents for the caller's org and files them as knowledge sources, which the store's own hook then indexes — so a synced document is retrievable exactly like a hand-written page.","description":"Pulls the provider's documents for the caller's org and files\nthem as knowledge sources, which the store's own hook then indexes — so a\nsynced document is retrievable exactly like a hand-written page. The org is the\nvalidated tenant and the credential is read from KMS, so an org can only ever\nsync its own connection. A provider failure is reported honestly (502) and\nrecorded on the connector rather than silently swallowed.","tags":["knowledge"],"parameters":[{"name":"provider","in":"path","required":true,"description":"Provider is the connector to act on: github, slack, google or notion.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/knowledge.kbSyncOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"knowledge","x-public":true,"x-tool":true}},"/v1/knowledge/files":{"get":{"operationId":"get_knowledge_files","summary":"Answers the caller's org files, most recently changed first, each with its status and stage — optionally only those in one bucket, which is how Drive shows a folder's files with their index state.","description":"Answers the caller's org files, most recently changed first, each\nwith its status and stage — optionally only those in one bucket, which is how\nDrive shows a folder's files with their index state.","tags":["knowledge"],"parameters":[{"name":"bucket","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/knowledge.filesOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"knowledge","x-public":true,"x-tool":true},"post":{"operationId":"post_knowledge_files","summary":"Makes an object in one of the caller's org buckets a workspace file.","description":"Makes an object in one of the caller's org buckets a workspace\nfile. Upload the bytes first — POST /v1/s3/buckets/{bucket}/objects mints a\npresigned PUT, POST /v1/s3/buckets/{bucket}/uploads starts a multipart upload\nfor a large one — then register the key here. The object's name, type and\nsize are read from the store. The file is recorded as queued, a file_stored\nevent is stated on the org's event plane, and a durable ingest is queued that\nextracts its text and structure, summarizes its table of contents, cuts and\nembeds its passages and links it into the org's graph. An archive (.zip) is\nunpacked and every file inside becomes a workspace file of its own. Poll GET\n/v1/knowledge/files/{id} for status. Registering an object again answers the\nsame file, and re-indexes it only when the object changed or its last ingest\nfailed.\n\nRegistering a changed object again changes its file, which only the person\nwho registered it or an admin of the org may do: anyone else is refused 403\nand the file keeps its version. Registering an unchanged object is a read.","tags":["knowledge"],"requestBody":{"content":{"application/json":{"example":{"bucket":"hanzo","key":"chat/report.pdf"},"schema":{"$ref":"#/components/schemas/knowledge.fileIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/knowledge.File"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"knowledge","x-public":true,"x-tool":true}},"/v1/knowledge/files/retrieve":{"post":{"operationId":"post_knowledge_files_retrieve","summary":"Grounds an answer in the caller's org files, table of contents first: candidate documents are found by searching their passages; a model reads their tables of contents — titles and one-line summaries — and picks the sections the answer is in; hybrid search drills into the passages of those sections; and the graph expands to the sections they link to or name the same entities as, in any file of the workspace.","description":"Grounds an answer in the caller's org files, table of contents\nfirst: candidate documents are found by searching their passages; a model\nreads their tables of contents — titles and one-line summaries — and picks\nthe sections the answer is in; hybrid search drills into the passages of\nthose sections; and the graph expands to the sections they link to or name\nthe same entities as, in any file of the workspace. Every passage cites its\nfile › section › paragraph, so an answer can say exactly where it came from.\nThis is what a chat runs before it answers about an attached file, and what\nan agent runs before it answers about a workspace.","tags":["knowledge"],"requestBody":{"content":{"application/json":{"example":{"files":["f3a9c0d1e2b4f5a6b7c8"],"query":"how long are backups retained, and who audits that?"},"schema":{"$ref":"#/components/schemas/knowledge.retrieveIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/knowledge.retrieveOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"knowledge","x-public":true,"x-tool":true}},"/v1/knowledge/files/search":{"post":{"operationId":"post_knowledge_files_search","summary":"Answers the passages of the caller's org files that match a query, each citing its file › section › paragraph: the search behind Drive's box, and the first step an agent takes across a workspace.","description":"Answers the passages of the caller's org files that match a query,\neach citing its file › section › paragraph: the search behind Drive's box,\nand the first step an agent takes across a workspace. Name file ids to search\nonly those files; name none to search them all. A semantic leg compares the\nquery with every embedded passage and a full-text leg finds the passages\nholding its words; the two are fused, so a passage both found comes first.","tags":["knowledge"],"requestBody":{"content":{"application/json":{"example":{"limit":5,"query":"termination notice period"},"schema":{"$ref":"#/components/schemas/knowledge.fileSearchIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/knowledge.fileSearchOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"knowledge","x-public":true,"x-tool":true}},"/v1/knowledge/files/{id}":{"delete":{"operationId":"delete_knowledge_files_by_id","summary":"Removes one of the caller's org files from the index — its table of contents, passages, full-text rows, mentions and links — and its record.","description":"Removes one of the caller's org files from the index — its table of\ncontents, passages, full-text rows, mentions and links — and its record. The\nfile is gone from every read when this answers: its listing, its contents,\nsearch and retrieval. What the index held of it is removed after, a batch at\na time, so forgetting a file of any size answers at once. The object itself\nstays in its bucket; delete it there. Drive calls this when it deletes a file.\n\nOnly the person who registered the file or an admin of the org may forget it;\nanyone else in the org, who can still read it, is refused 403. A file\nregistered before uploaders were recorded is forgotten by an admin alone.","tags":["knowledge"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the file's id, as POST /v1/knowledge/files answered it.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/knowledge.forgotten"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"knowledge","x-public":true,"x-tool":true},"get":{"operationId":"get_knowledge_files_by_id","summary":"Answers one of the caller's org files: what it is, where its bytes are, and how far its ingest has got.","description":"Answers one of the caller's org files: what it is, where its bytes\nare, and how far its ingest has got. 404 for an id the org holds no file for.","tags":["knowledge"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the file's id, as POST /v1/knowledge/files answered it.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/knowledge.File"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"knowledge","x-public":true,"x-tool":true}},"/v1/knowledge/files/{id}/graph":{"get":{"operationId":"get_knowledge_files_by_id_graph","summary":"Answers one of the caller's org files' place in the org's graph: the files it links to and is linked from (a hyperlink, a citation by name), the files that name the same entities, and the entities it names.","description":"Answers one of the caller's org files' place in the org's graph:\nthe files it links to and is linked from (a hyperlink, a citation by name),\nthe files that name the same entities, and the entities it names. It is how\nan agent finds the other documents a question about this one needs.","tags":["knowledge"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the file's id, as POST /v1/knowledge/files answered it.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/knowledge.fileGraph"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"knowledge","x-public":true,"x-tool":true}},"/v1/knowledge/files/{id}/sections/{section}":{"get":{"operationId":"get_knowledge_files_by_id_sections_by_section","summary":"Answers one section of one of the caller's org files: its own text, its subsections, the sections it links to or shares entities with — in this file or another — and the entities it names.","description":"Answers one section of one of the caller's org files: its own\ntext, its subsections, the sections it links to or shares entities with —\nin this file or another — and the entities it names. Open the document\nitself with section 0.","tags":["knowledge"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the file's id.","schema":{"type":"string"}},{"name":"section","in":"path","required":true,"description":"Section is the section's number in the file's table of contents.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/knowledge.sectionOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"knowledge","x-public":true,"x-tool":true}},"/v1/knowledge/files/{id}/toc":{"get":{"operationId":"get_knowledge_files_by_id_toc","summary":"Answers one of the caller's org files' table of contents: every section in document order with its depth, its parent and a one-line summary.","description":"Answers one of the caller's org files' table of contents: every\nsection in document order with its depth, its parent and a one-line summary.\nIt is the map a reader — a person in Drive, or an agent deciding where to\nlook — reads before opening a section with GET\n/v1/knowledge/files/{id}/sections/{section}.","tags":["knowledge"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the file's id, as POST /v1/knowledge/files answered it.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/knowledge.tocOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"knowledge","x-public":true,"x-tool":true}},"/v1/knowledge/graph":{"get":{"operationId":"get_knowledge_graph","summary":"Returns the caller org's knowledge as a node/edge graph shaped for a force-directed renderer: pages, memories and synced sources as nodes; the page parent tree, the wikilinks between pages, and each source's connector provenance as edges.","description":"Returns the caller org's knowledge as a node/edge graph\nshaped for a force-directed renderer: pages, memories and synced sources as\nnodes; the page parent tree, the wikilinks between pages, and each source's\nconnector provenance as edges. Wikilink targets are resolved HERE by title or\nslug, so a rename never needs an edge rewrite and a link that matches no page\nrenders as its own \"unresolved\" node instead of vanishing. ?project= narrows\nit. A store outage degrades to an honest empty graph, never a 5xx.","tags":["knowledge"],"parameters":[{"name":"project","in":"query","required":false,"description":"Project narrows the graph to one project scope. Empty reads the whole org.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/knowledge.graphOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"knowledge","x-public":true,"x-tool":true}},"/v1/knowledge/import":{"post":{"operationId":"post_knowledge_import","summary":"Import an Obsidian, Notion, Roam or Evernote export into the org's knowledge base","description":"Ingests an uploaded export as a tree of kb.page documents with its link structure intact. `?format=` picks the normalizer — obsidian, notion, roam or evernote — and the export arrives as a multipart `file` part, or as the raw request body when there is no multipart part: an Obsidian or Notion vault zip, a Roam JSON (raw or inside the zip Roam downloads), or an Evernote .enex.\n\nThe pages are filed through the SAME ingest path a connector sync uses, so the kb.page hook indexes each one for retrieval AND extracts its `[[wikilinks]]` into kb.link edges — the imported vault is searchable and its graph is navigable without a second pass. Parents are filed before their children, and each page takes a slug unique within the org (suffixed -2, -3, … on collision), so a re-import adds pages rather than overwriting the ones already there.\n\nScoped to the caller's validated org; `?project=` narrows every imported page to one project. No validated principal is 403, and an org that has not installed the kb module is refused with the install call to make first. The bounds are 64 MB per upload, 5000 pages and 8 MB per archive entry: pages past the five-thousandth are dropped and a larger entry is truncated at its bound, and a page the store rejects is skipped — so the answer's `imported` count is what was actually filed, not what was sent.","tags":["knowledge"],"x-app":"knowledge","x-public":true}},"/v1/knowledge/reindex":{"post":{"operationId":"post_knowledge_reindex","summary":"Rebuilds the caller org's retrieval from its documents: every passage is removed, and every page, memory and source is cut into passages and embedded again with the configured model; the lexical index is reconciled to the same documents.","description":"Rebuilds the caller org's retrieval from its documents: every passage\nis removed, and every page, memory and source is cut into passages and\nembedded again with the configured model; the lexical index is reconciled to\nthe same documents. It is what an operator runs after the embedding model\nchanges — passages of another model are never compared with the query, so\nuntil then they are unread — and what puts an org's retrieval right after an\noutage of the ai plane. It requires ORG ADMIN and runs inline: an org's\nknowledge is a few thousand documents, and the answer is the count.\n\nThe request has no body. Response: {\"vectors\": 412, \"lexical\": 412, \"removed\": 3, \"failed\": 0}","tags":["knowledge"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/knowledge.reindexOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"knowledge","x-public":true,"x-tool":true}},"/v1/knowledge/search":{"post":{"operationId":"post_knowledge_search","summary":"Runs a hybrid search over the caller org's own knowledge — its wiki pages, its agent memories and everything its connectors have synced.","description":"Runs a hybrid search over the caller org's own knowledge —\nits wiki pages, its agent memories and everything its connectors have synced.\nThis is the RAG entry point: an agent asks \"what does this org know about X\"\nand the org's OWN knowledge answers. Two legs run and are fused by reciprocal\nrank: a semantic leg that embeds the query and compares it with every passage\nof every document in reach (a document is cut into passages of about 2000\nbytes, so a fact deep in a long page is found), and a keyword leg over the\norg's knowledge index. The org comes from the validated principal and its\npassages live in its own database, so cross-tenant retrieval is impossible. A\nfailed leg answers 200 with what the other leg found and degraded=true, never\na 5xx.","tags":["knowledge"],"requestBody":{"content":{"application/json":{"example":{"limit":5,"query":"how do we rotate the signing key"},"schema":{"$ref":"#/components/schemas/knowledge.searchIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/knowledge.searchOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"knowledge","x-public":true,"x-tool":true}},"/v1/kv/{bucket}":{"delete":{"operationId":"delete_kv_by_bucket","summary":"Removes one bucket of the caller's org — every key and every revision with it — and answers 204 with no body.","description":"Removes one bucket of the caller's org — every key and every\nrevision with it — and answers 204 with no body. 404 when the org has no\nbucket of that name.","tags":["kv"],"parameters":[{"name":"bucket","in":"path","required":true,"description":"Bucket is the bucket's name, from the path.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"kv","x-public":true,"x-tool":true},"post":{"operationId":"post_kv_by_bucket","summary":"Creates a KV bucket and returns it.","description":"Creates a KV bucket and returns it. A bucket is keyed state on\nthe same durable plane as the streams: each key holds up to History\nrevisions, entries can expire by TTL, and watchers on the NATS port see every\nwrite. 409 when the org already has a bucket of that name.","tags":["kv"],"parameters":[{"name":"bucket","in":"path","required":true,"description":"Bucket is the bucket's name within the org, from the path: 1–64 of\n[A-Za-z0-9_], no dash.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"history":5,"ttl":3600},"schema":{"$ref":"#/components/schemas/kv.bucketWrite"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/kv.bucketRecord"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"kv","x-public":true,"x-tool":true}},"/v1/kv/{bucket}/{key}":{"delete":{"operationId":"delete_kv_by_bucket_by_key","summary":"Delete removes one key — a delete marker in the key's history, so watchers see it and Get answers 404 — and answers 204 with no body.","description":"Delete removes one key — a delete marker in the key's history, so watchers\nsee it and Get answers 404 — and answers 204 with no body. 404 when the\nbucket does not exist.","tags":["kv"],"parameters":[{"name":"bucket","in":"path","required":true,"description":"Bucket is the bucket, from the path.","schema":{"type":"string"}},{"name":"key","in":"path","required":true,"description":"Key is the key, from the path.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"kv","x-public":true,"x-tool":true},"get":{"operationId":"get_kv_by_bucket_by_key","summary":"Returns one key's current value and revision.","description":"Returns one key's current value and revision. 404 when the bucket does\nnot exist, the key was never written, or its latest revision is a delete.","tags":["kv"],"parameters":[{"name":"bucket","in":"path","required":true,"description":"Bucket is the bucket, from the path.","schema":{"type":"string"}},{"name":"key","in":"path","required":true,"description":"Key is the key, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/kv.kvEntry"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"kv","x-public":true,"x-tool":true},"put":{"operationId":"put_kv_by_bucket_by_key","summary":"Sets one key to one value and returns the revision the write created.","description":"Sets one key to one value and returns the revision the write created.\nWrites are versioned: each put is a new revision and the bucket retains up to\nits History of them per key.","tags":["kv"],"parameters":[{"name":"bucket","in":"path","required":true,"description":"Bucket is the bucket, from the path.","schema":{"type":"string"}},{"name":"key","in":"path","required":true,"description":"Key is the key, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"value":"{\"theme\":\"dark\"}"},"schema":{"$ref":"#/components/schemas/kv.kvWrite"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/kv.kvAck"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"kv","x-public":true,"x-tool":true}},"/v1/kv/{bucket}/{key}/history":{"get":{"operationId":"get_kv_by_bucket_by_key_history","summary":"Returns one key's retained revisions, oldest first — every put and every delete marker up to the bucket's History depth.","description":"Returns one key's retained revisions, oldest first — every put and\nevery delete marker up to the bucket's History depth. 404 when the bucket\ndoes not exist or the key was never written.","tags":["kv"],"parameters":[{"name":"bucket","in":"path","required":true,"description":"Bucket is the bucket, from the path.","schema":{"type":"string"}},{"name":"key","in":"path","required":true,"description":"Key is the key, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/kv.kvPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"kv","x-public":true,"x-tool":true}},"/v1/label":{"get":{"operationId":"riskLabels","summary":"Read the assertions this tenant has recorded","description":"Reads the assertions this tenant has recorded, newest event first.\n\nIt reads the RECORD — the tenant's own store — and not the columnar copy, so\nwhat it returns is what would be produced in an audit. Narrow it by entity, by\nasserter, or by event window.","tags":["label"],"parameters":[{"name":"kind","in":"query","required":false,"description":"Kind and Subject narrow to one entity.","schema":{"type":"string"}},{"name":"subject","in":"query","required":false,"schema":{"type":"string"}},{"name":"source","in":"query","required":false,"description":"Source narrows to one asserter — the read that answers \"what has commerce\ntold us\", separately from \"what has an analyst told us\".","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"From and To bound the EVENT time, half-open, RFC 3339.","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps the page. Out of range takes the plane's own bound.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/label.riskLabelsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"label","x-public":true,"x-tool":true},"post":{"operationId":"riskLabel","summary":"Assert ground truth about events","description":"Records a batch of ground truth against the entities it judges.\n\nEach assertion carries TWO times — when the judged event happened, and when\nthe assertion became knowable — and both are required. The second is what\nkeeps a chargeback that landed in June out of a model that had to decide in\nFebruary.\n\nIt is idempotent on the CONTENT of an assertion, so a webhook that redelivers\nis safe. It never overwrites: a source that corrects itself later files a NEW\nassertion, which wins from the moment it became knowable and leaves every\nearlier observation instant seeing exactly what it saw.\n\nThe asserter is stamped from the validated credential and is not a body field.","tags":["label"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/label.riskLabelIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/label.riskLabelOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"label","x-public":true,"x-tool":true}},"/v1/label/coverage":{"get":{"operationId":"riskLabelCoverage","summary":"How much of the window has matured, and how much of that is judged","description":"Reports how much of a window has matured and how much of that is\njudged, per source.\n\nIt is the gate on training. A supervised fit over a window whose judged count\nis near zero produces a number, and the number is meaningless; this op is what\nlets that be stated before the fit rather than discovered after it.\n\nIt reads the RECORD plane and folds every assertion at that event's OWN as-of,\nso the counts obey exactly the leakage rule a materialisation would. It counts\nonly what was ASSERTED: what share of the whole event STREAM carries a label is\na question about the feature plane's denominator and is not answerable here.","tags":["label"],"parameters":[{"name":"from","in":"query","required":false,"description":"From and To bound the EVENT window, half-open, RFC 3339.\n\nUnstated, the window is the 90 days ENDING where maturity begins — `to` is\nthe horizon ago, not now. A default window running to now under a default\nhorizon could not contain one matured event, so every count below it would\nbe zero however much ground truth the tenant held.","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}},{"name":"horizon","in":"query","required":false,"description":"Horizon is the maturity horizon in days the coverage is measured under.\nUnstated takes 120. It also moves the default window, which ends where\nmaturity begins.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/label.riskLabelCoverage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"label","x-public":true,"x-tool":true}},"/v1/label/dispose":{"post":{"operationId":"riskDisposeLabels","summary":"Dispose of this tenant's expired assertions, whole records only","description":"Applies this tenant's retention, and only this tenant's.\n\nIt is bounded three ways, each a compliance property rather than a\nconvenience. It refuses a boundary younger than the platform floor, because a\nlabel can be the input to an adverse action and five years is what the\nretention ledger holds such a record for. It never touches a record under\nlitigation hold. And it disposes of whole records rather than redacting\nfields.\n\nIt removes the derived columnar copy BEFORE the record, and refuses the whole\ndisposal if the warehouse cannot be reached. The other order would leave rows\nin the warehouse that nothing can identify any more, which is a disposal that\ndid not happen and says it did.","tags":["label"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/label.riskDisposeIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/label.riskDisposeOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"label","x-public":true,"x-tool":true}},"/v1/label/hold":{"post":{"operationId":"riskHoldLabels","summary":"Place or release a litigation hold on named records","description":"Places or releases a litigation hold on named records.\n\nA hold is a fact about the RECORD, not about the world: it says retention may\nnot dispose of this row, and it asserts nothing about what happened. So it is\nnot a field on an assertion and it is not folded into the content digest —\ncarried there it was silently a no-op on any record that already existed, since\nre-filing the same assertion with a hold flag produced the same digest, the\ninsert was ignored, and the caller was answered `duplicate` while the hold it\nasked for was never placed. This op is the one way a hold moves, in either\ndirection, and the move is written to the audit log.\n\nEvery named id is this tenant's or is nothing. The statement runs against the\ntenant's own file, which holds no other tenant's rows and has no column that\ncould name one.","tags":["label"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/label.riskHoldIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/label.riskHoldOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"label","x-public":true,"x-tool":true}},"/v1/label/resolve":{"post":{"operationId":"riskResolveLabels","summary":"Resolve the label in force for named events, as of each event's own horizon","description":"Answers, for each named event, which assertion was in force AS OF that\nevent's own horizon — and what disagreed with it.\n\nThis is the join surface: the dataset materialiser calls it to attach ground\ntruth to training rows, and the evaluator calls it to score a past decision\nagainst what was knowable when the decision had to be made. One mechanism for\nboth, so a model can never be trained under one leakage rule and scored under\nanother.\n\nThree answers are distinct and all three are honest: a resolved label, an\nevent that has not matured, and a matured event nobody has judged. The last is\nnever reported as unproductive.","tags":["label"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/label.riskResolveIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/label.riskResolveOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"label","x-public":true,"x-tool":true}},"/v1/label/vocabulary":{"get":{"operationId":"riskLabelVocabulary","summary":"The closed vocabularies and the precedence rule that resolves a conflict","description":"Publishes the closed vocabularies and the precedence rule that\nresolves a conflict between two sources.\n\nA precedence rule nobody can read is a rule nobody can audit or dispute, and\nthe whole defensibility of a contested label rests on being able to say why\none assertion beat another. The order returned here is derived from the same\ndeclaration the resolver reads — it is not a description of it.","tags":["label"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/label.riskLabelVocabulary"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"label","x-public":true,"x-tool":true}},"/v1/leaderboard":{"get":{"operationId":"get_leaderboard","summary":"Ranks AI usage over a window, either the users of the caller's own org or organizations against each other, and always reports the caller's own standing even when it falls outside the returned page.","description":"Ranks AI usage over a window, either the users of the caller's own org\nor organizations against each other, and always reports the caller's own standing\neven when it falls outside the returned page. Identities are private by default: a\ncaller sees themselves, plus the peers or orgs that opted into public listing, and\nonly an admin sees their own org's members named. Cross-org spend is restricted to\nplatform admins. When the warehouse is not connected the board answers empty with\navailable=false rather than a fabricated rank.","tags":["leaderboard"],"parameters":[{"name":"scope","in":"query","required":false,"description":"Scope picks the board: \"personal\" (default) ranks the caller among their own\norg's users, \"org\" is that same org board named for an admin, \"global\" ranks\norganizations against each other.","schema":{"type":"string"},"example":"personal"},{"name":"metric","in":"query","required":false,"description":"Metric is the value ranked: tokens (default), requests, or cost.","schema":{"type":"string"},"example":"tokens"},{"name":"period","in":"query","required":false,"description":"Period is the window ranked: day, week, month (default) or all.","schema":{"type":"string"},"example":"week"},{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned, clamped to 100. Defaults to 10, which is also\nwhat a non-positive or unparseable value takes.","schema":{"format":"int64","type":"integer"},"example":10}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/leaderboard.LeaderboardView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"leaderboard","x-public":true,"x-tool":true}},"/v1/leaderboard/activity":{"get":{"operationId":"get_leaderboard_activity","summary":"Returns the per-day usage series for ONE authorized subject — the points a contribution heatmap and a timeline are drawn from, gap-filled so every day in the range is present.","description":"Returns the per-day usage series for ONE authorized subject — the points a\ncontribution heatmap and a timeline are drawn from, gap-filled so every day in the\nrange is present. Authorization is resolved server-side from the validated\nprincipal, so a caller can never widen the subject past what they are entitled to:\na non-admin reads only themselves and their own org. subject=project answers empty\nwith a note, because the usage ledger records no project column yet. When the\nwarehouse is not connected the series answers empty with available=false rather\nthan fabricated days.","tags":["leaderboard"],"parameters":[{"name":"subject","in":"query","required":false,"description":"Subject is what the series is about: \"user\" (default), \"org\" or \"project\".","schema":{"type":"string"},"example":"user"},{"name":"id","in":"query","required":false,"description":"ID names the subject within what the caller is entitled to see. Omitted (or\n\"me\") it is the caller themselves, or their own org. Another user requires org\nadmin and must belong to the caller's org; another org requires a SuperAdmin.","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"From is the first day of the range, \"2006-01-02\". Defaults to 90 days back.","schema":{"type":"string"},"example":"2026-01-01"},{"name":"to","in":"query","required":false,"description":"To is the last day of the range, \"2006-01-02\". Defaults to today; the span is\nclamped to 366 days.","schema":{"type":"string"},"example":"2026-03-31"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/leaderboard.ActivityView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"leaderboard","x-public":true,"x-tool":true}},"/v1/leaderboard/beta":{"get":{"operationId":"get_leaderboard_beta","summary":"Ranks everyone on the hanzo.ai/beta waitlist by one score: the record's verified-action points, plus 1 per org that signed up with its referral code, plus 20 per such org that has made metered spend, plus 1 per 100,000 tokens the person used, all time.","description":"Ranks everyone on the hanzo.ai/beta waitlist by one score: the\nrecord's verified-action points, plus 1 per org that signed up with its\nreferral code, plus 20 per such org that has made metered spend, plus 1 per\n100,000 tokens the person used, all time. Ties go to the earlier application.\nShare clicks count for nothing.\n\nEveryone who ever applied is on it. A form filed before the person had an\naccount is a row of its own (no name, score 0, the day it was filed) until their\naccount's record claims it, and the record then begins when the form did.\n\nA row is named only for a person who opted into the public board (PUT\n/v1/leaderboard/optin); the caller always sees their own row named. Tokens are a\nrange on every row and exact on a named row and the caller's. `tokens` and\n`referrals` say whether the warehouse and the referral service answered; a\nterm that did not is left out of every score alike.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["leaderboard"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit caps the rows, clamped to 1..100. Defaults to 25, which is also what a\nnon-positive value takes.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/leaderboard.BetaBoard"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"leaderboard","x-public":true,"x-tool":true}},"/v1/leaderboard/optin":{"get":{"operationId":"get_leaderboard_optin","summary":"Returns the caller's own public-listing preference and their org's, each with whether the caller may change it.","description":"Returns the caller's own public-listing preference and their org's,\neach with whether the caller may change it. Public listing is opt-in and private\nby default, so a fresh caller reads listed=false for both.","tags":["leaderboard"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/leaderboard.optinView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"leaderboard","x-public":true,"x-tool":true},"put":{"operationId":"put_leaderboard_optin","summary":"Sets the CALLER's own public-listing preference on the leaderboard.","description":"Sets the CALLER's own public-listing preference on the leaderboard.\nSelf only: the row written is keyed by the caller's validated ledger identity, so\nthis can never edit another member's visibility whatever the request says. A\ncaller opting in with no handle is given their username, so a listed row never\nrenders as \"Anonymous\" to its own owner.","tags":["leaderboard"],"requestBody":{"content":{"application/json":{"example":{"handle":"ada","listed":true},"schema":{"$ref":"#/components/schemas/leaderboard.userOptinReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/leaderboard.userOptinView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"leaderboard","x-public":true,"x-tool":true}},"/v1/leaderboard/optin/org":{"put":{"operationId":"put_leaderboard_optin_org","summary":"Sets the ORG's listing on the cross-org global board.","description":"Sets the ORG's listing on the cross-org global board. Only an admin of\nthe caller's own org — an org admin or a platform SuperAdmin — may change it, and\nthe org written is the caller's validated tenant, never a value from the request.\nListing consents to publishing the org's usage VOLUME; cross-org spend stays\nrestricted to platform admins regardless.","tags":["leaderboard"],"requestBody":{"content":{"application/json":{"example":{"display":"Acme","listed":true},"schema":{"$ref":"#/components/schemas/leaderboard.orgOptinReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/leaderboard.orgOptinView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"leaderboard","x-public":true,"x-tool":true}},"/v1/legal/documents":{"get":{"operationId":"get_legal_documents","summary":"Returns the org's generated documents, newest first, WITHOUT their rendered content — fetch one document to read its body.","description":"Returns the org's generated documents, newest first, WITHOUT\ntheir rendered content — fetch one document to read its body.\n\nThe response is marked no-store: these records name the counterparties an org is\ncontracting with, and must not sit in a shared cache.","tags":["legal"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit bounds the page. Absent or unparseable means the store's own default.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/legal.documentPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"legal","x-public":true,"x-tool":true},"post":{"operationId":"post_legal_documents","summary":"Renders a document from a template and the caller's own merge data, seals it in the org's store, and returns it with its rendered body.","description":"Renders a document from a template and the caller's own\nmerge data, seals it in the org's store, and returns it with its rendered body.\n\nThe render is PURE and deterministic — no clock, no I/O — so the same template\nversion and the same data always produce identical bytes, which is what makes a\ngenerated contract reproducible. It fails CLOSED on a missing merge field: there\nis no blank-filled contract, only a 400 naming the fields that were absent. When\nthe template is counsel-review the rendered body opens with the counsel notice,\nwhich no caller can suppress.\n\nThe document is a DRAFT. Hanzo Legal manages documents; it does not give legal\nadvice and does not determine that a document is valid or sufficient.","tags":["legal"],"requestBody":{"content":{"application/json":{"example":{"data":{"counterparty":"AgentCo, LLC","date":"2026-07-30"},"templateId":"nda"},"schema":{"$ref":"#/components/schemas/legal.generateRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/legal.documentReply"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"legal","x-public":true,"x-tool":true}},"/v1/legal/documents/{id}":{"get":{"operationId":"get_legal_documents_by_id","summary":"Returns one of the org's documents WITH its rendered body.","description":"Returns one of the org's documents WITH its rendered body. 404\nwhen the org has no document with that id — a document is never readable across\norgs.\n\nThe response is marked no-store: the body is contract text, sealed at rest and\nreturned only to the owning org, and must not sit in a shared cache.","tags":["legal"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the document's server-minted handle, \"doc_\"-prefixed.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/legal.documentReply"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"legal","x-public":true,"x-tool":true}},"/v1/legal/documents/{id}/sign":{"post":{"operationId":"post_legal_documents_by_id_sign","summary":"Opens an e-signature request over one document and moves it to out_for_signature, returning the provider's reference for the request.","description":"Opens an e-signature request over one document and moves it\nto out_for_signature, returning the provider's reference for the request.\n\nThe provider is whatever this deployment has wired. The honest default is\n\"manual\": the request is recorded and the org fulfils it out of band — nothing\nhere fabricates a signature, and the stub never reports itself complete.","tags":["legal"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the document to send for signature, from the path.","schema":{"type":"string"},"example":"doc_1f…"}],"requestBody":{"content":{"application/json":{"example":{"id":"doc_1f…","signers":[{"email":"ada@acme.com","name":"Ada"}]},"schema":{"$ref":"#/components/schemas/legal.signRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/legal.signReply"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"legal","x-public":true,"x-tool":true}},"/v1/legal/documents/{id}/sign/complete":{"post":{"operationId":"post_legal_documents_by_id_sign_complete","summary":"Record that a generated document's signature request completed","description":"Records completion of the signature request opened over a generated document and answers the document with a `signed` flag.\n\nThe e-sign provider's own status is consulted FIRST and is the default answer; an explicit `signed` field in the body overrides it. That override is the whole point: the default `manual` provider never self-completes, so a reviewer (or a real provider's webhook) is what moves the document. A completion flips the document to `signed`, stamps `signedAt`, and writes a `legal.document.signed` audit event; a provider still reporting incomplete answers 200 with the document unchanged, so the call is safe to repeat and never fabricates a signature.\n\nOrg-scoped and fails closed: a validated principal is required (401 without one), the document is read under the caller's OWN org so another tenant's id is a 404, a document with no open signature request is a 400, and a provider whose status call errors is a 502.","tags":["legal"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"legal","x-public":true}},"/v1/legal/filings":{"get":{"operationId":"get_legal_filings","summary":"Returns the org's filing records, newest first — which documents were filed where, through which provider, and what the filing's honest status is.","description":"Returns the org's filing records, newest first — which documents\nwere filed where, through which provider, and what the filing's honest status is.","tags":["legal"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit bounds the page. Absent or unparseable means the store's own default.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/legal.filingPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"legal","x-public":true,"x-tool":true},"post":{"operationId":"post_legal_filings","summary":"Records a filing of one or more of the org's documents with a state or agency, and returns the tracking record.","description":"Records a filing of one or more of the org's documents with a\nstate or agency, and returns the tracking record.\n\nIt is a TRACKING record, not an autonomous filing. With no filing partner wired\nthe honest status is \"manual\" and the note says so: the documents were generated\nfor signature, and the org files them through its registered agent. Nothing here\ninvents a filing id it does not have.\n\nEvery document id must belong to the caller's org; one that does not is a 404\nnaming it, so a filing can never reach across tenants.","tags":["legal"],"requestBody":{"content":{"application/json":{"example":{"documentIds":["doc_1f…"],"jurisdiction":"DE"},"schema":{"$ref":"#/components/schemas/legal.filingRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/legal.filingReply"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"legal","x-public":true,"x-tool":true}},"/v1/legal/health":{"get":{"operationId":"get_legal_health","summary":"Reports that the legal subsystem is serving and how many built-in templates its catalog carries.","description":"Reports that the legal subsystem is serving and how many built-in\ntemplates its catalog carries. It reads no tenant, so a liveness prober that\nsends no principal is answered rather than refused.","tags":["legal"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/legal.legalHealth"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"legal","x-public":true,"x-tool":true}},"/v1/legal/templates":{"get":{"operationId":"get_legal_templates","summary":"Returns the org's effective template catalog: every built-in template, with any the org has overridden replaced by its own latest version.","description":"Returns the org's effective template catalog: every built-in\ntemplate, with any the org has overridden replaced by its own latest version.\n\nThe listing carries each template's metadata and its declared MERGE FIELDS — the\nkeys a document generation must supply — but never the template bodies; fetch one\ntemplate to get its body. Templates in the formation and equity categories are\nmarked counselReview: every document rendered from them carries a counsel notice,\nand that posture cannot be dropped by an override.","tags":["legal"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/legal.templateCatalog"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"legal","x-public":true,"x-tool":true}},"/v1/legal/templates/{id}":{"get":{"operationId":"get_legal_templates_by_id","summary":"Returns one template resolved for the caller's org — the org's own override if it has saved one, else the built-in — with its full text/template body and its declared merge fields.","description":"Returns one template resolved for the caller's org — the org's\nown override if it has saved one, else the built-in — with its full text/template\nbody and its declared merge fields. 404 when neither exists.","tags":["legal"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the template's stable id, e.g. \"nda\" or \"safe\".","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/legal.templateReply"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"legal","x-public":true,"x-tool":true},"put":{"operationId":"put_legal_templates_by_id","summary":"Saves the org's own version of a template — a custom NDA, a house MSA — and returns it with its new version number.","description":"Saves the org's own version of a template — a custom\nNDA, a house MSA — and returns it with its new version number. It takes effect\nfor that org only; other orgs keep the built-in.\n\nTwo boundaries cannot be crossed here. Overriding a built-in INHERITS its\ncategory and its counsel-review posture, which can be raised but never dropped;\nand a formation or equity template is counsel-review whatever the caller sends,\nso no org can generate a securities-class document without the notice.\n\nThe body is validated on save, not at generation: a template that references an\nUNDECLARED merge field is refused with 400 rather than stored and rendered blank\ninto a contract months later.","tags":["legal"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the template to override, from the path. Overriding a built-in id\ninherits that built-in's category, title and counsel-review posture.","schema":{"type":"string"},"example":"nda"}],"requestBody":{"content":{"application/json":{"example":{"body":"…{{.counterparty}}…","fields":[{"key":"counterparty","label":"Counterparty"}],"id":"nda","title":"AgentCo Mutual NDA"},"schema":{"$ref":"#/components/schemas/legal.templateOverride"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/legal.templateReply"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"legal","x-public":true,"x-tool":true}},"/v1/library":{"get":{"operationId":"get_library","summary":"Lists what you made and what members of your organization shared with you, newest first.","description":"Lists what you made and what members of your organization shared\nwith you, newest first. Narrow it by kind, source, ref, project, a name search\nand a time range; `scope` mine keeps only yours and shared only what others\nshared. Each item carries signed URLs that work for an hour.","tags":["library"],"parameters":[{"name":"kind","in":"query","required":false,"description":"Kind keeps one kind: image, video, audio, document, slides, type, model, code or file.","schema":{"type":"string"},"example":"image"},{"name":"source","in":"query","required":false,"description":"Source keeps what one product made: chat, dev, studio or workflow.","schema":{"type":"string"},"example":"studio"},{"name":"ref","in":"query","required":false,"description":"Ref keeps what one conversation, run or Studio run made.","schema":{"type":"string"}},{"name":"project","in":"query","required":false,"description":"Project keeps one project's items.","schema":{"type":"string"}},{"name":"q","in":"query","required":false,"description":"Q keeps the items whose name contains it, ignoring case.","schema":{"type":"string"}},{"name":"since","in":"query","required":false,"description":"Since and Until bound when it was made: RFC 3339, or a date (YYYY-MM-DD).","schema":{"type":"string"}},{"name":"until","in":"query","required":false,"schema":{"type":"string"}},{"name":"scope","in":"query","required":false,"description":"Scope is all (yours and what your org shared, the default), mine, or shared.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit bounds the page: default 60, at most 200.","schema":{"format":"int64","type":"integer"},"example":24},{"name":"cursor","in":"query","required":false,"description":"Cursor continues a list from the page before's `next`.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/library.itemPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"library","x-public":true,"x-tool":true},"post":{"operationId":"post_library","summary":"Keeps one thing you made in your Library: its bytes go to your own prefix of the Library's store, and it is listed to you alone until you share it.","description":"Keeps one thing you made in your Library: its bytes go to your own\nprefix of the Library's store, and it is listed to you alone until you share\nit. A save with the `key` of one already kept answers that item.","tags":["library"],"requestBody":{"content":{"application/json":{"example":{"data":"iVBORw0…","mime":"image/png","name":"poster.png","origin":"/chat?thread=conv_1","ref":"conv_1","source":"chat"},"schema":{"$ref":"#/components/schemas/library.keepIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/library.LibraryItem"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"library","x-public":true,"x-tool":true}},"/v1/library/unowned":{"get":{"operationId":"get_library_unowned","summary":"ListUnowned reads, for a SuperAdmin alone, the organization's items that record no owner.","description":"ListUnowned reads, for a SuperAdmin alone, the organization's items that record\nno owner. Such an item is nobody's: no member lists it, reads it\nor changes it, and this view neither changes it nor signs its bytes. Every\nread of it is written to the audit trail.","tags":["library"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit bounds the page: default 60, at most 200.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/library.itemPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"library","x-public":true,"x-tool":true}},"/v1/library/{id}":{"delete":{"operationId":"delete_library_by_id","summary":"Deletes one of your items and its bytes.","description":"Deletes one of your items and its bytes. Only its owner deletes an\nitem.","tags":["library"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the item, from the path.","schema":{"type":"string"},"example":"lib_0f3c…"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"library","x-public":true,"x-tool":true},"get":{"operationId":"get_library_by_id","summary":"Reads one item with fresh signed URLs.","description":"Reads one item with fresh signed URLs. An item that is not yours and\nwas not shared with your organization answers 404, as one that does not exist.","tags":["library"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the item, from the path.","schema":{"type":"string"},"example":"lib_0f3c…"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/library.LibraryItem"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"library","x-public":true,"x-tool":true},"patch":{"operationId":"patch_library_by_id","summary":"Renames one of your items, shares it with your organization or stops sharing it, or moves it to a project.","description":"Renames one of your items, shares it with your organization or\nstops sharing it, or moves it to a project. Only its owner changes an item; a\nmember's shared item answers 404 here as one that does not exist.","tags":["library"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the item, from the path.","schema":{"type":"string"},"example":"lib_0f3c…"}],"requestBody":{"content":{"application/json":{"example":{"id":"lib_0f3c…","shared":true},"schema":{"$ref":"#/components/schemas/library.itemPatch"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/library.LibraryItem"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"library","x-public":true,"x-tool":true}},"/v1/licensing/download/{release}":{"get":{"operationId":"get_licensing_download_by_release","summary":"Download resolves a release to its artifact, gated on a valid license.","description":"Download resolves a release to its artifact, gated on a valid license.\n\nThe gate is the LICENSE token, not the IAM bearer: being signed in is not\npermission to download a paid binary — holding a good license for it is. The\ntoken must verify against this deployment's public key, be unrevoked, be\nscoped to the release's app, and carry every feature the release requires.\nPresent it as the `X-License-Token` header (preferred, since a header does not\nland in proxy logs) or as `?token=`.\n\nThe response pairs the artifact URL with its cosign signature so the client\nverifies the binary BEFORE trusting it: a signed URL alone proves where the\nbytes came from, not what they are. A yanked release is 410 Gone.","tags":["licensing"],"parameters":[{"name":"release","in":"path","required":true,"schema":{"type":"string"}},{"name":"X-License-Token","in":"header","required":false,"schema":{"type":"string"}},{"name":"token","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/licensing.ReleaseAsset"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"licensing","x-public":true,"x-tool":true}},"/v1/licensing/fingerprint":{"post":{"operationId":"post_licensing_fingerprint","summary":"Fingerprint turns raw device signals into the opaque value that binds a license to one machine.","description":"Fingerprint turns raw device signals into the opaque value that binds a license\nto one machine.\n\nThis is the anti-copy step: the value returned here is folded into the signed\ntoken, so a token minted with it runs only on the device it was bound to. The\nderivation is one-way and salted — the signals are never stored and never\nechoed back — so the response is safe to persist client-side and pass to\nissue. Signals too weak to identify a machine (a hostname alone) are refused\nrather than turned into a binding that would collide with other machines.","tags":["licensing"],"requestBody":{"content":{"application/json":{"example":{"signals":{"arch":"arm64","cpuid":"…","machine_id":"…","os":"linux"}},"schema":{"$ref":"#/components/schemas/licensing.FingerprintRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/licensing.FingerprintResponse"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"licensing","x-public":true,"x-tool":true}},"/v1/licensing/healthz":{"get":{"operationId":"get_licensing_healthz","summary":"Health reports which signer this deployment mints with, and in which env.","description":"Health reports which signer this deployment mints with, and in which env.\n\nIt answers 200 whenever the process is up: there is nothing downstream to\nprobe, since KMS is read only when a token is actually minted. Its\nvalue is the `signer` field — `\"signer\":\"local\"` on a production host says\nthat deployment is signing licenses with a development key, which is a\nmisconfiguration worth paging on rather than a healthy 200.","tags":["licensing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/licensing.HealthView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"licensing","x-public":true,"x-tool":true}},"/v1/licensing/issue":{"post":{"operationId":"post_licensing_issue","summary":"Issue mints a signed license token for a product the caller's org already pays for.","description":"Issue mints a signed license token for a product the caller's org already pays\nfor.\n\nThe order is the whole security argument: the caller is an IAM-validated\nprincipal, commerce is then asked whether that principal's ORG holds an ACTIVE\nentitlement for the product, and only then is a token signed, with the\nproduction key KMS holds. A product the org does not own answers\n403 and no token. The signed features are the plan's features verbatim, so the\nengine enforces exactly what was bought, and the expiry is clamped to the\nentitlement's so a token cannot outlive the subscription that paid for it.\n\nThe token is the credential the engine runs on. Treat it as a secret.","tags":["licensing"],"requestBody":{"content":{"application/json":{"example":{"product":"engine","signals":{"machine_id":"…","os":"linux"}},"schema":{"$ref":"#/components/schemas/licensing.IssueRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/licensing.IssueResponse"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"licensing","x-public":true,"x-tool":true}},"/v1/licensing/jwks":{"get":{"operationId":"get_licensing_jwks","summary":"Pubkey publishes the Ed25519 PUBLIC verification key, at both /pubkey and /jwks.","description":"Pubkey publishes the Ed25519 PUBLIC verification key, at both /pubkey and\n/jwks.\n\nThis is the only public-safe surface here and the reason the whole scheme\nworks offline: the engine embeds or fetches this key once and then verifies\nevery license itself, with no call home per launch. The private half lives in\nKMS, so nothing served here is a secret. `provider` names where that half\nlives: `\"kms\"` is the production key every engine embeds; `\"local\"` is a\ndevelopment key, and a token signed by one is not a production credential.","tags":["licensing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/licensing.PubkeyView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"licensing","x-public":true,"x-tool":true}},"/v1/licensing/pubkey":{"get":{"operationId":"get_licensing_pubkey","summary":"Pubkey publishes the Ed25519 PUBLIC verification key, at both /pubkey and /jwks.","description":"Pubkey publishes the Ed25519 PUBLIC verification key, at both /pubkey and\n/jwks.\n\nThis is the only public-safe surface here and the reason the whole scheme\nworks offline: the engine embeds or fetches this key once and then verifies\nevery license itself, with no call home per launch. The private half lives in\nKMS, so nothing served here is a secret. `provider` names where that half\nlives: `\"kms\"` is the production key every engine embeds; `\"local\"` is a\ndevelopment key, and a token signed by one is not a production credential.","tags":["licensing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/licensing.PubkeyView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"licensing","x-public":true,"x-tool":true}},"/v1/licensing/releases":{"get":{"operationId":"get_licensing_releases","summary":"Lists the signed binary releases this deployment can serve.","description":"Lists the signed binary releases this deployment can serve.\n\nMetadata only, and no download URL: the artifact is behind GET\n/v1/licensing/download/{release}, which is gated on a valid license token.\nKnowing that a release exists is not permission to run it, which is why this\nlist needs no license of its own.","tags":["licensing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/licensing.ReleaseList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"licensing","x-public":true,"x-tool":true}},"/v1/licensing/releases/{release}":{"get":{"operationId":"get_licensing_releases_by_release","summary":"Reads one release's metadata: its product, version, platform and the cosign material a client verifies the binary against.","description":"Reads one release's metadata: its product, version, platform and the\ncosign material a client verifies the binary against.\n\nAn unknown id is 404. Like the list, this is metadata only — the bytes are\nbehind the license-gated download.","tags":["licensing"],"parameters":[{"name":"release","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/licensing.Release"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"licensing","x-public":true,"x-tool":true}},"/v1/licensing/verify":{"post":{"operationId":"post_licensing_verify","summary":"Verify checks a license token online: signature, schema, expiry, app_id and the revocation list.","description":"Verify checks a license token online: signature, schema, expiry, app_id and\nthe revocation list.\n\nIt is UNAUTHENTICATED and always answers 200 — a bad token is `valid:false`\nwith a reason rather than an error status, because \"is this token good\" is a\nquestion anyone may ask about a credential they already hold and the answer is\nthe same either way. It is also OPTIONAL: the engine verifies OFFLINE against\nthe published public key (GET /v1/licensing/pubkey) and needs this endpoint\nonly to learn about revocation, so an outage here never stops a paid customer\nworking.","tags":["licensing"],"requestBody":{"content":{"application/json":{"example":{"token":"eyJ2Ijox….Ab3…"},"schema":{"$ref":"#/components/schemas/licensing.VerifyRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/licensing.VerifyResponse"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"licensing","x-public":true,"x-tool":true}},"/v1/link":{"get":{"operationId":"get_link","summary":"Lists your linked accounts and the devices they sit on.","description":"Lists your linked accounts and the devices they sit on.\n\nIt answers the caller's own links plus a devices projection of the same rows\nfolded per machine — the cross-machine \"AI Providers / Accounts\" view. A\ndevice is a projection, not a stored entity: its labels come from its\nmost-recently-seen account, so there is no device to create and none to\ngarbage-collect. Revoked links are INCLUDED rather than dropped, because a\nlogged-out account keeps its usage history and audit trail. Scoped to the\ncaller: a validated principal and a non-empty org, else 403.","tags":["link"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/link.linkList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"link","x-public":true,"x-tool":true},"post":{"operationId":"post_link","summary":"Registers a signed-in AI provider account on a machine.","description":"Registers a signed-in AI provider account on a machine.\n\nIt records that a developer has signed into one provider account on one\nmachine — a Claude Max or ChatGPT Plus subscription, a Hanzo key, a raw\nprovider key — and answers 201 with the stored link. Re-reporting the same\n(machine, provider, account) UPDATES that link rather than creating a second,\nso a collector may call this on every heartbeat. machine and provider are\nrequired (400 otherwise), as is a valid kind, and every field is\nlength-bounded. Scoped to the caller: a validated principal and a non-empty\norg, else 403, so a caller writes only their OWN accounts within their own org.","tags":["link"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/link.enrollReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/link.linkView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"link","x-public":true,"x-tool":true}},"/v1/link/devices/{machine}":{"get":{"operationId":"get_link_devices_by_machine","summary":"Shows one machine: its accounts, usage and live sessions.","description":"Shows one machine: its accounts, usage and live sessions.\n\nIt answers one device — its host and OS labels, every account the caller has\nsigned in on that machine with its latest usage, and how many agent sessions\nthe caller currently has running on it. The device labels come from the\nmost-recently-seen account, since a device is a projection of its links rather\nthan a row of its own. A machine with none of the caller's accounts is 404,\nwhich is also the answer when the machine belongs to someone else — the scope\nmakes the two indistinguishable, deliberately. The session count reports 0\nwhere the agent plane is not mounted rather than failing the read.","tags":["link"],"parameters":[{"name":"machine","in":"path","required":true,"description":"Machine is the machine to act on, from the path. It is scoped to the\ncaller, so a machine with none of the caller's accounts is a 404.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/link.deviceView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"link","x-public":true,"x-tool":true}},"/v1/link/devices/{machine}/revoke":{"post":{"operationId":"post_link_devices_by_machine_revoke","summary":"Logs out every account on one machine and stops its sessions.","description":"Logs out every account on one machine and stops its sessions.\n\nIt revokes every one of the caller's accounts on one machine and stops the\nagent sessions they were running, answering with how many of each. This is the\n\"I lost that laptop\" button. Revoked links are RETAINED, not deleted, so usage\nhistory and the audit trail survive a log-out — the rows come back in the\nresponse with their new status. The session stop reaches only the REVOKING\nuser's own sessions, so a shared machine name can never be used to stop a\nco-tenant's work, and a stop that fails does not fail the revoke: the revoked\nrow is the durable truth and the count then honestly reports fewer. A machine\nwith nothing left to revoke is 404.","tags":["link"],"parameters":[{"name":"machine","in":"path","required":true,"description":"Machine is the machine to act on, from the path. It is scoped to the\ncaller, so a machine with none of the caller's accounts is a 404.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/link.revokeResp"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"link","x-public":true,"x-tool":true}},"/v1/link/route":{"get":{"operationId":"get_link_route","summary":"Gets the failover order across your linked accounts.","description":"Gets the failover order across your linked accounts.\n\nIt answers an ordered redundancy plan over the caller's LINKED (not revoked)\naccounts: each candidate with its remaining rate-limit headroom, whether it is\nroutable right now, how it BILLS (plan or commerce), and a reason when it is\nnot — plus the primary to try first. It is what lets a router fail over from\none subscription to another and fall back to the metered API as the\nalways-available backstop, knowing the cost consequence before it dials.\n\nIt is POLICY, not execution: the plan is computed purely from the usage\nsnapshots already in the registry, never by probing a provider, so it is a\ntotal function of the links and costs nothing to ask for. Actually dialing,\ndetecting a live 429 and advancing to the next candidate belongs to the\ncaller. A link with no snapshot counts as full headroom.","tags":["link"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/link.RoutePlan"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"link","x-public":true,"x-tool":true}},"/v1/link/usage":{"get":{"operationId":"get_link_usage","summary":"Shows one provider account's own usage dashboard.","description":"Shows one provider account's own usage dashboard.\n\nIt answers the time series for a SINGLE provider account — the windows in\nrange plus the currently-open ones — as that provider's own meter reported it:\n\"my plan is 47% through its 6h window, resets at 14:20\". current is the newest\ninstance of each lane (the headline); windows is the history behind it, both\ncomputed from ONE deduped read. provider is required; an unknown window class\nor range is 400, never a quiet fallback to a different one. When no series is\navailable the response is a 200 with available:false and empty lists — an\nhonest \"we have no data\", which is a different claim from zero usage.","tags":["link"],"parameters":[{"name":"provider","in":"query","required":false,"description":"Provider is the provider whose meter to read. Required.","schema":{"type":"string"}},{"name":"account","in":"query","required":false,"description":"Account narrows to one account when a user has several with the provider.","schema":{"type":"string"}},{"name":"window","in":"query","required":false,"description":"Window selects a window class: 6h, day, week or month. Empty reads all.","schema":{"type":"string"}},{"name":"range","in":"query","required":false,"description":"Range is the period, one of 1h, 24h, 7d or 30d; empty means 24h, and an\nunknown label is 400, never a quiet fallback.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/link.boardResp"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"link","x-public":true,"x-tool":true},"post":{"operationId":"post_link_usage","summary":"Reports usage samples from the device collector.","description":"Reports usage samples from the device collector.\n\nIt ingests a batch of usage samples and answers with how many were accepted,\nwhether history was durably stored, and the links they refreshed. A report\nalso REFRESHES one link per distinct (machine, provider, account) it names, so\na running collector keeps the accounts overview current without a separate\nregistration call.\n\nA caller can only ever report for THEMSELVES: org and subject come from the\nvalidated bearer, never from the body, so no sample can be attributed to\nanother user or tenant. History is FAIL-SOFT and stored says which happened —\na warehouse outage still accepts the report and refreshes the links rather\nthan failing the device, and answers 202 either way. Send either one sample\ninline or up to 256 in samples; an empty batch or an over-long one is 400, as\nis a provider, window class or kind outside the closed vocabulary — an\nunrecognized window is refused rather than rewritten, because a silently\nreclassified sample would fill a dashboard with a class nobody reported.","tags":["link"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/link.ingestReq"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/link.ingestResp"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"link","x-public":true,"x-tool":true}},"/v1/link/usage/accounts":{"get":{"operationId":"get_link_usage_accounts","summary":"Breaks down what the gateway routed through each of your accounts.","description":"Breaks down what the gateway routed through each of your accounts.\n\nIt answers one row per linked account the GATEWAY actually routed through,\nplus their total — requests, prompt and completion tokens, and cost. This is\nthe routed ledger, the read twin of the counter the router writes, and it is\ndistinct from both of its neighbours: not the device collector's plan\nsnapshots, and not the org money ledger. The source and scope fields on the\nresponse say so on every payload. The same shape answers in the billing\nnamespace, from one shaping function, so the two mounts cannot drift.","tags":["link"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/link.AccountsUsage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"link","x-public":true,"x-tool":true}},"/v1/link/usage/summary":{"get":{"operationId":"get_link_usage_summary","summary":"Shows plan consumption and Hanzo spend side by side.","description":"Shows plan consumption and Hanzo spend side by side.\n\nIt answers the global usage board over one window: the caller's own linked\naccounts, metered from each provider's own login, alongside their org's\nHanzo-routed inference. These come from different ledgers and mean different\nthings, so every row is LABELLED by source, by scope and by availability, and\nTHE TWO ARE NEVER SUMMED — a plan's percentage is not money, and a provider's\nown spend is not a Hanzo charge. The rows sit side by side and say what they\nare.\n\nOne resolver fixes the window for both halves, so the two sets always cover\nthe same period. range is one of 1h, 24h, 7d or 30d and defaults to 24h;\nanything else is 400 rather than a silent substitution. A ledger that cannot\nanswer reports available:false instead of a zero that would read as \"no usage\".","tags":["link"],"parameters":[{"name":"range","in":"query","required":false,"description":"Range is the period, one of 1h, 24h, 7d or 30d; empty means 24h, and an\nunknown label is 400, never a silent substitution.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/link.summaryResp"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"link","x-public":true,"x-tool":true}},"/v1/link/{id}":{"delete":{"operationId":"delete_link_by_id","summary":"Logs out one account and stops the sessions it was running.","description":"Logs out one account and stops the sessions it was running.\n\nIt revokes a single linked account and stops the agent sessions that ran under\nit, answering with the revoked row and how many sessions stopped. The link is\nRETAINED with a revoked status rather than deleted, so its usage history and\nthe audit trail survive the log-out — which also means a revoked account still\nappears in the list, and is excluded from the route plan rather than absent\nfrom it. The session stop is narrowed to the revoking user's own sessions on\nthat device, provider and account, and a stop that fails does not fail the\nrevoke: the revoked row is the durable truth. An id that does not exist, or\nbelongs to another user or org, is the same 404.","tags":["link"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the link to act on, from the path. It is scoped to the caller, so\nanother user's or org's id is a 404.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/link.revokeResp"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"link","x-public":true,"x-tool":true},"get":{"operationId":"get_link_by_id","summary":"Reads one linked account.","description":"Reads one linked account.\n\nIt answers a single link — its device, provider, account, plan, how it bills,\nits status and its latest usage snapshot. An id that does not exist, or\nbelongs to another user or org, is the same 404: the scope is a bound\npredicate on the read, so a wrong id and a foreign id are indistinguishable\nand neither confirms the other's existence. The static paths on this\ncollection — route, usage, devices — register before this one and win\nfirst-match, so a link whose id collided with one of those words could not be\naddressed here.","tags":["link"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the link to act on, from the path. It is scoped to the caller, so\nanother user's or org's id is a 404.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/link.linkView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"link","x-public":true,"x-tool":true}},"/v1/lsp/complete":{"post":{"operationId":"post_lsp_complete","summary":"Offers the candidates a language server has at a position, typed and resolved through the repository's dependencies rather than guessed from text.","description":"Offers the candidates a language server has at a position, typed and\nresolved through the repository's dependencies rather than guessed from text.","tags":["lsp"],"requestBody":{"content":{"application/json":{"example":{"character":18,"line":120,"path":"apps/lsp/lsp.go","repo":"cloud"},"schema":{"$ref":"#/components/schemas/lsp.Query"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/lsp.Answer"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"lsp","x-public":true,"x-tool":true}},"/v1/lsp/diagnostics":{"post":{"operationId":"post_lsp_diagnostics","summary":"Reports every problem the language server finds in one file — compile errors, type errors and lints, each with its span and its severity (1 error, 2 warning, 3 information, 4 hint).","description":"Reports every problem the language server finds in one file —\ncompile errors, type errors and lints, each with its span and its severity (1\nerror, 2 warning, 3 information, 4 hint). The position is ignored.","tags":["lsp"],"requestBody":{"content":{"application/json":{"example":{"path":"apps/lsp/lsp.go","repo":"cloud"},"schema":{"$ref":"#/components/schemas/lsp.Query"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/lsp.Answer"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"lsp","x-public":true,"x-tool":true}},"/v1/lsp/hover":{"post":{"operationId":"post_lsp_hover","summary":"Renders the type and documentation of the symbol at a position, as the language server itself renders it.","description":"Renders the type and documentation of the symbol at a position, as the\nlanguage server itself renders it.\n\nPositions are the LSP's: line and character are 0-BASED and character counts\nUTF-16 code units, so an editor's 1-based line must have 1 subtracted before it\nis sent. The repository is named by slug and is always one in the caller's own\norg; rev pins a branch, tag or commit sha, and empty means the default branch.","tags":["lsp"],"requestBody":{"content":{"application/json":{"example":{"character":18,"line":120,"path":"apps/lsp/lsp.go","repo":"cloud"},"schema":{"$ref":"#/components/schemas/lsp.Query"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/lsp.Answer"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"lsp","x-public":true,"x-tool":true}},"/v1/lsp/locate":{"post":{"operationId":"post_lsp_locate","summary":"Finds where a symbol lives: its definition, its references, its type or its implementations, chosen by relation (definition, reference, type, implementation — empty means definition).","description":"Finds where a symbol lives: its definition, its references, its type or\nits implementations, chosen by relation (definition, reference, type,\nimplementation — empty means definition).\n\nIt resolves THROUGH dependencies. An answer whose external flag is set left the\nrepository, and its path is then the module coordinate it landed in — which is\nthe question a static index cannot answer and this service exists for.","tags":["lsp"],"requestBody":{"content":{"application/json":{"example":{"character":18,"line":120,"path":"apps/lsp/lsp.go","relation":"definition","repo":"cloud"},"schema":{"$ref":"#/components/schemas/lsp.Query"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/lsp.Answer"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"lsp","x-public":true,"x-tool":true}},"/v1/lsp/symbols":{"post":{"operationId":"post_lsp_symbols","summary":"Outlines one file: every declaration in it, with its kind and its span.","description":"Outlines one file: every declaration in it, with its kind and its span.\nThe position is ignored — the answer is the whole file.","tags":["lsp"],"requestBody":{"content":{"application/json":{"example":{"path":"apps/lsp/lsp.go","repo":"cloud"},"schema":{"$ref":"#/components/schemas/lsp.Query"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/lsp.Answer"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"lsp","x-public":true,"x-tool":true}},"/v1/market/chains":{"get":{"operationId":"get_market_chains","summary":"Answers every chain this deployment can read, what is deployed on each, and what its automated market maker amounts to.","description":"Answers every chain this deployment can read, what is deployed on each, and what\nits automated market maker amounts to.\n\nOne call. It reads the chain registry, then every chain's indexer for its figures\nand its most recent active day, all at once — where a client doing it itself makes\none registry request and two more per chain.\n\nTHE ROW IS THE UNIT OF TRUTH. Each carries its own reach, so one indexer being\nunreachable costs one row its figures and leaves the rest answered. A chain with no\nmarket maker deployed — the registry names no factory for it — answers `read` with\ntotals of nothing, which is a fact about that chain and is not the same as a chain\nnobody could ask.","tags":["market"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/market.Roster"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"security":[],"x-app":"market","x-public":true,"x-tool":true}},"/v1/market/pools":{"get":{"operationId":"get_market_pools","summary":"Answers the automated market makers on one chain: their two tokens, their fee tier, and what has moved through each.","description":"Answers the automated market makers on one chain: their two tokens, their fee tier,\nand what has moved through each.\n\nThe two price fields on a pool are the ratio its own reserves stand at, as the\nindexer computed them. They are not a price ON either token and not a mark: nothing\nhere derives one, ranks the pools, or names a route through them.\n\nA chain with no market maker deployed answers `read` with no pools. That is the\nchain's real condition, and it is deliberately not the same answer as an indexer\nthat could not be asked.","tags":["market"],"parameters":[{"name":"chain","in":"query","required":false,"description":"Chain is the chain's slug — `cchain`, `zoo` — as `chains` reports it. It is\nthe indexer's word for the chain and NOT the chain id: `96369`, `C` and\n`c-chain` all name nothing.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/market.Pools"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"security":[],"x-app":"market","x-public":true,"x-tool":true}},"/v1/market/survey":{"get":{"operationId":"get_market_survey","summary":"Answers which of the four settlement precompiles carry code on one chain.","description":"Answers which of the four settlement precompiles carry code on one chain.\n\nAn address with no code answers a call with empty data rather than an error, so\n\"this chain has no view precompile\" and \"this market was never opened\" reach a\ncaller as the same silence — and only the second is a fact about a market. This\nsays which it is, by asking the node for the code at each address.\n\nIt reads presence and nothing else. No market, no quote, no depth and no order is\nrequested here, and `eth_getCode` is the only method this operation ever sends.","tags":["market"],"parameters":[{"name":"chain","in":"query","required":false,"description":"Chain is the chain's slug — `cchain`, `zoo` — as `chains` reports it. It is\nthe indexer's word for the chain and NOT the chain id: `96369`, `C` and\n`c-chain` all name nothing.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/market.Survey"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"security":[],"x-app":"market","x-public":true,"x-tool":true}},"/v1/market/token":{"get":{"operationId":"get_market_token","summary":"Answers one token's daily history — open, high, low, close, price and volume per UTC day, oldest first.","description":"Answers one token's daily history — open, high, low, close, price and volume per\nUTC day, oldest first.\n\nEvery figure is the indexer's own arithmetic, passed through as the decimal string\nit computed. Nothing here rounds one, converts one, or fills a gap: a day the\nindexer holds no figure for arrives with that field absent, which says \"not\nindexed\" where a zero would say \"worth nothing\".","tags":["market"],"parameters":[{"name":"chain","in":"query","required":false,"schema":{"type":"string"}},{"name":"at","in":"query","required":false,"description":"At is the token's contract address.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/market.History"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"security":[],"x-app":"market","x-public":true,"x-tool":true}},"/v1/market/tokens":{"get":{"operationId":"get_market_tokens","summary":"Answers the tokens one chain's indexer has seen, with the decimals a caller needs to read any amount of one correctly.","description":"Answers the tokens one chain's indexer has seen, with the decimals a caller needs\nto read any amount of one correctly.\n\nThis is what the indexer INGESTED, which is not the same as what exists on the\nchain: a token nothing has traded has no row here, and this is not a registry of\nwhat is permitted or listed.","tags":["market"],"parameters":[{"name":"chain","in":"query","required":false,"description":"Chain is the chain's slug — `cchain`, `zoo` — as `chains` reports it. It is\nthe indexer's word for the chain and NOT the chain id: `96369`, `C` and\n`c-chain` all name nothing.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/market.Tokens"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"security":[],"x-app":"market","x-public":true,"x-tool":true}},"/v1/marketing/audiences":{"get":{"operationId":"get_marketing_audiences","summary":"Returns the org's saved audiences, most recently updated first.","description":"Returns the org's saved audiences, most recently updated first.","tags":["marketing"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned; 0 means 200 and nothing above 1000 is honoured.","schema":{"format":"int64","type":"integer"},"example":50}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.AudienceList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true},"post":{"operationId":"post_marketing_audiences","summary":"Saves a cohort filter for the caller's org.","description":"Saves a cohort filter for the caller's org. Name is required.\nOmitting event saves the WHOLE-ORG audience — every mailable customer — which\nneeds no analytics warehouse; naming one narrows that roster to the customers\nwho fired it within windowDays.\n\nOrg admin or SuperAdmin only; a member of the org is refused.","tags":["marketing"],"requestBody":{"content":{"application/json":{"example":{"event":"model.invoked","name":"Model users, last 30d","windowDays":30},"schema":{"$ref":"#/components/schemas/marketing.Audience"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.Audience"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/audiences/{id}":{"delete":{"operationId":"delete_marketing_audiences_by_id","summary":"Removes one of the caller org's audiences and answers 204.","description":"Removes one of the caller org's audiences and answers 204. It\ndeletes the saved filter only — no customer, event or enrollment is touched.\n\nOrg admin or SuperAdmin only; a member of the org is refused.","tags":["marketing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the audience id from the path, as returned by create.","schema":{"type":"string"},"example":"aud_4c1e9b7a2d6f0538e4a7c9b1d3f5027a"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true},"get":{"operationId":"get_marketing_audiences_by_id","summary":"Returns one of the caller org's saved audiences.","description":"Returns one of the caller org's saved audiences. An audience\nbelonging to another org reads as not found.","tags":["marketing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the audience id from the path, as returned by create.","schema":{"type":"string"},"example":"aud_4c1e9b7a2d6f0538e4a7c9b1d3f5027a"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.Audience"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/audiences/{id}/preview":{"get":{"operationId":"get_marketing_audiences_by_id_preview","summary":"Evaluates the cohort LIVE — the same resolution an enrollment would run — and reports how big it is and how many real mailboxes it reaches.","description":"Evaluates the cohort LIVE — the same resolution an enrollment\nwould run — and reports how big it is and how many real mailboxes it reaches.\nIt is the honest answer to \"is this send worth making\": a cohort of 500 that\nmails 3 says so, in deliverable and unmatched. Nothing is sent.","tags":["marketing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the audience id from the path, as returned by create.","schema":{"type":"string"},"example":"aud_4c1e9b7a2d6f0538e4a7c9b1d3f5027a"}],"responses":{"200":{"content":{"application/json":{"example":{"available":true,"count":500,"deliverable":3,"sample":["u_1","u_2"],"source":"event.fact","unmatched":497},"schema":{"$ref":"#/components/schemas/marketing.AudiencePreview"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/beta":{"get":{"operationId":"get_marketing_beta","summary":"Answers the signed-in caller's waitlist record: the application as it stands, the betas asked for, the points and the actions that earned them, and the place on the waitlist.","description":"Answers the signed-in caller's waitlist record: the application as it\nstands, the betas asked for, the points and the actions that earned them, and\nthe place on the waitlist. An account that has not applied answers applied\nfalse and place 0.","tags":["marketing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.Beta"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true},"put":{"operationId":"put_marketing_beta","summary":"Writes the signed-in caller's application: the program, the answers, the betas asked for and the lead it was filed under.","description":"Writes the signed-in caller's application: the program, the answers, the\nbetas asked for and the lead it was filed under. A field left out keeps what\nthe record holds; betas replace the set, each new id stamped with the time it\nwas asked for and stated on the event plane as beta_requested.","tags":["marketing"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.BetaIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.Beta"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/beta/actions":{"post":{"operationId":"post_marketing_beta_actions","summary":"Counts one action of the signed-in caller: a star on a Hanzo repository, verified on GitHub for the login named, or a follow of a founder's link, taken on trust.","description":"Counts one action of the signed-in caller: a star on a Hanzo repository,\nverified on GitHub for the login named, or a follow of a founder's link, taken\non trust. An action already counted changes nothing. A star GitHub does not\nshow answers 422, and a login another account's stars are counted for, 409.","tags":["marketing"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.BetaActIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.Beta"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/beta/invites":{"get":{"operationId":"get_marketing_beta_invites","summary":"Answers the caller's invites, newest first, with how many were sent, how many joined, and how many more they may send now.","description":"Answers the caller's invites, newest first, with how many were sent,\nhow many joined, and how many more they may send now. A reservation that\nlapsed unsent is not listed: it holds nothing.","tags":["marketing"],"responses":{"200":{"content":{"application/json":{"example":{"counts":{"joined":1,"left":19,"sent":1},"invites":[{"at":"2026-10-27T18:00:00Z","id":"inv_4f1a9c2e7b3d5a6c8e0f1a2b","status":"joined","to":"grace@example.com"}]},"schema":{"$ref":"#/components/schemas/marketing.BetaInviteList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true},"post":{"operationId":"post_marketing_beta_invites","summary":"Reserves an invite for each address the limits admit and answers the message the member's mailbox sends for each: subject, text and HTML, the unsubscribe headers, with the member's referral link for that invite and a one-click unsubscribe for that address.","description":"Reserves an invite for each address the limits admit and answers the\nmessage the member's mailbox sends for each: subject, text and HTML, the\nunsubscribe headers, with the member's referral link for that invite and a\none-click unsubscribe for that address. Nothing is sent from here; the member's\nbrowser sends each from their own Gmail and reports it to POST\n/v1/marketing/beta/invites/sent.\n\nAn address is skipped, with why, when it is not an email address, is the\nmember's own, cannot be invited (it opted out of the brand's email, its company\ndid, the platform bars it, or it already holds an account: one reason for all,\nso no one learns which), was invited in the last 30 days, or is past the\nmember's 20 a day or 100 a month. When the limits leave the member nothing to\nreserve the answer is 429, with Retry-After the seconds until a slot frees.","tags":["marketing"],"requestBody":{"content":{"application/json":{"example":{"to":["grace@example.com","alan@example.com"]},"schema":{"$ref":"#/components/schemas/marketing.BetaInviteIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"invites":[{"headers":{"List-Unsubscribe":"\u003chttps://api.hanzo.ai/v1/marketing/unsubscribe?…\u003e","List-Unsubscribe-Post":"List-Unsubscribe=One-Click"},"html":"…","id":"inv_4f1a9c2e7b3d5a6c8e0f1a2b","link":"https://hanzo.ai/beta?ref=H4NZ0ABC\u0026utm_source=invite\u0026utm_medium=email\u0026utm_campaign=beta_referral\u0026utm_content=inv_4f1a9c2e7b3d5a6c8e0f1a2b","subject":"Ada invited you to the Hanzo beta","text":"…","to":"grace@example.com"}],"left":19,"skipped":[{"to":"alan@example.com","why":"this address cannot be invited"}]},"schema":{"$ref":"#/components/schemas/marketing.BetaInvites"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/beta/invites/sent":{"post":{"operationId":"post_marketing_beta_invites_sent","summary":"Records what the member's browser did with its reservations: the invites sent, and the ones that failed with the mailbox's reason.","description":"Records what the member's browser did with its reservations: the\ninvites sent, and the ones that failed with the mailbox's reason. Only the\nmember who reserved an invite marks it, only while it is reserved, and only\nwithin the 24 hours it holds; anything else is left as it stands. Each invite\nthat becomes sent is filed on its invitee's CRM timeline, the person made when\nthe org held none, a CRM that cannot answer costing the timeline an entry and\nnever the report. It answers the named invites that are the caller's, as they\nstand.","tags":["marketing"],"requestBody":{"content":{"application/json":{"example":{"failed":[{"id":"inv_0d9e8c7b6a5f4e3d2c1b0a9f","why":"Gmail refused the recipient"}],"ids":["inv_4f1a9c2e7b3d5a6c8e0f1a2b"]},"schema":{"$ref":"#/components/schemas/marketing.BetaInviteSentIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"invites":[{"at":"2026-10-26T02:10:00Z","id":"inv_4f1a9c2e7b3d5a6c8e0f1a2b","status":"sent","to":"grace@example.com"},{"at":"2026-10-26T02:09:58Z","id":"inv_0d9e8c7b6a5f4e3d2c1b0a9f","status":"failed","to":"linus@example.com"}]},"schema":{"$ref":"#/components/schemas/marketing.BetaInviteRows"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/beta/request":{"post":{"operationId":"post_marketing_beta_request","summary":"Adds betas to those the signed-in caller asked for, creating the record when there is none.","description":"Adds betas to those the signed-in caller asked for, creating the record\nwhen there is none. Each new id is stamped with the time it was asked for and\nstated on the event plane as beta_requested.","tags":["marketing"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.BetaRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.Beta"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/calendar":{"get":{"operationId":"get_marketing_calendar","summary":"Returns the org's calendar, latest scheduled first, optionally narrowed to one status.","description":"Returns the org's calendar, latest scheduled first,\noptionally narrowed to one status.","tags":["marketing"],"parameters":[{"name":"status","in":"query","required":false,"description":"Status keeps only posts in that state (draft, scheduled, published,\nfailed, canceled). Empty means every post.","schema":{"type":"string"},"example":"scheduled"},{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned; 0 means 200 and nothing above 1000 is honoured.","schema":{"format":"int64","type":"integer"},"example":50}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.PostList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true},"post":{"operationId":"post_marketing_calendar","summary":"Adds a post to the content calendar.","description":"Adds a post to the content calendar. Channel and body are\nrequired. A scheduledAt in the future makes the post \"scheduled\" and the\ndurable sweep publishes it when it comes due — claimed once, so a post\npublishes at most once; without one it stays a draft.","tags":["marketing"],"requestBody":{"content":{"application/json":{"example":{"body":"Hanzo Cloud is live.","channel":"x","scheduledAt":1780000000,"title":"Launch day"},"schema":{"$ref":"#/components/schemas/marketing.CalendarPost"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.CalendarPost"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/calendar/{id}":{"delete":{"operationId":"delete_marketing_calendar_by_id","summary":"Removes one of the caller org's posts and answers 204.","description":"Removes one of the caller org's posts and answers 204. A\npost already published is deleted from the calendar only — nothing is\nretracted from the network it went out on.","tags":["marketing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the post id from the path, as returned by create.","schema":{"type":"string"},"example":"cal_1d7f3b9e5a2c8046f1b3d5a7c9e02468"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true},"get":{"operationId":"get_marketing_calendar_by_id","summary":"Returns one of the caller org's posts, including the exact error behind a failed publish.","description":"Returns one of the caller org's posts, including the exact\nerror behind a failed publish. A post belonging to another org reads as not\nfound.","tags":["marketing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the post id from the path, as returned by create.","schema":{"type":"string"},"example":"cal_1d7f3b9e5a2c8046f1b3d5a7c9e02468"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.CalendarPost"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true},"put":{"operationId":"put_marketing_calendar_by_id","summary":"Replaces a post's editable fields.","description":"Replaces a post's editable fields. It is a full write, not\na patch, and it RESETS the lifecycle from the schedule: a scheduledAt makes\nthe post \"scheduled\" again and none makes it a draft — so editing a failed\npost requeues it rather than leaving it stuck.","tags":["marketing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the server-assigned post id (\"cal_\" + 128 random bits).","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"body":"Hanzo Cloud is live — try it free.","channel":"x","scheduledAt":1780003600,"title":"Launch day"},"schema":{"$ref":"#/components/schemas/marketing.CalendarPost"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.CalendarPost"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/campaigns":{"get":{"operationId":"get_marketing_campaigns","summary":"Returns the org's campaigns, most recently updated first, optionally narrowed to one lifecycle status.","description":"Returns the org's campaigns, most recently updated first,\noptionally narrowed to one lifecycle status.","tags":["marketing"],"parameters":[{"name":"status","in":"query","required":false,"description":"Status keeps only campaigns in that lifecycle state (draft, scheduled,\nactive, paused, completed). Empty means every campaign.","schema":{"type":"string"},"example":"active"},{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned; 0 means 200 and nothing above 1000 is honoured.","schema":{"format":"int64","type":"integer"},"example":25}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.CampaignList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true},"post":{"operationId":"post_marketing_campaigns","summary":"Registers a campaign in the caller's org.","description":"Registers a campaign in the caller's org. Name is required;\nchannel defaults to email and status to draft, and a future scheduledAt with\nno explicit status makes the campaign \"scheduled\". Budget and spend are cents\nand are clamped to \u003e= 0. The id, createdAt and updatedAt of the input are\nignored — the server assigns them.","tags":["marketing"],"requestBody":{"content":{"application/json":{"example":{"budget":50000,"channel":"meta","name":"Spring Launch","objective":"signups","scheduledAt":1780000000},"schema":{"$ref":"#/components/schemas/marketing.Campaign"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.Campaign"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/campaigns/{id}":{"delete":{"operationId":"delete_marketing_campaigns_by_id","summary":"Removes one of the caller org's campaigns and answers 204.","description":"Removes one of the caller org's campaigns and answers 204. A\ncampaign belonging to another org reads as not found and is left untouched.","tags":["marketing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the campaign id from the path, as returned by create.","schema":{"type":"string"},"example":"camp_9f2a1c7d4e8b0a6f3d2c5b1e7a9f4c60"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true},"get":{"operationId":"get_marketing_campaigns_by_id","summary":"Returns one of the caller org's campaigns.","description":"Returns one of the caller org's campaigns. A campaign belonging to\nanother org reads as not found.","tags":["marketing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the campaign id from the path, as returned by create.","schema":{"type":"string"},"example":"camp_9f2a1c7d4e8b0a6f3d2c5b1e7a9f4c60"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.Campaign"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true},"put":{"operationId":"put_marketing_campaigns_by_id","summary":"Replaces a campaign's editable fields.","description":"Replaces a campaign's editable fields. It is a full write, not\na patch: every field takes the value in the body, and an omitted one is\ncleared. The id comes from the path — the body cannot retarget another\ncampaign — and createdAt is never rewritten.","tags":["marketing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the server-assigned campaign id (\"camp_\" + 128 random bits).","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"budget":50000,"channel":"meta","name":"Spring Launch","objective":"signups","spend":12500,"status":"active"},"schema":{"$ref":"#/components/schemas/marketing.Campaign"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.Campaign"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/campaigns/{id}/schedule":{"post":{"operationId":"post_marketing_campaigns_by_id_schedule","summary":"Sets a campaign's send time and moves it to \"scheduled\".","description":"Sets a campaign's send time and moves it to \"scheduled\". A\nscheduledAt of 0 clears the schedule and returns it to \"draft\".","tags":["marketing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the campaign id from the path.","schema":{"type":"string"},"example":"camp_9f2a1c7d4e8b0a6f3d2c5b1e7a9f4c60"}],"requestBody":{"content":{"application/json":{"example":{"id":"camp_9f2a1c7d4e8b0a6f3d2c5b1e7a9f4c60","scheduledAt":1780000000},"schema":{"$ref":"#/components/schemas/marketing.ScheduleInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.Campaign"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/click":{"get":{"operationId":"get_marketing_click","summary":"Follows a tracked email link.","description":"Follows a tracked email link. It is public — the person clicking has no\nsession — and the token is its only authority: a token that verifies, for a\nsequence of one of Hanzo's own orgs that still exists, answers 302 to the\ndestination it signs and records one click (time and user-agent family; no IP\naddress), off the request path so the redirect never waits on storage. A token\nthat is missing, altered, signed under another key, older than a year, or for\nany other org or a deleted sequence answers 302 to the brand's home page\n(https://hanzo.ai/ on Hanzo's deployment). The location is only ever a\ndestination a token signs or that page, never a URL the request names.","tags":["marketing"],"parameters":[{"name":"User-Agent","in":"header","required":false,"description":"Agent is the clicker's User-Agent header. Only its family (chrome,\nsafari, automated, …) is kept.","schema":{"type":"string"}},{"name":"t","in":"query","required":false,"description":"T is the click token the send minted for this link and this recipient:\nbase64url, signed under the deployment's KMS key marketing/click-hmac. It\nis the request's only authority.","schema":{"type":"string"},"example":"AQGAgICAAQVoYW56bw…"}],"responses":{"302":{"description":"found","headers":{"Cache-Control":{"description":"Set by GET /v1/marketing/click.","schema":{"type":"string"}},"Location":{"description":"Set by GET /v1/marketing/click.","schema":{"type":"string"}},"Referrer-Policy":{"description":"Set by GET /v1/marketing/click.","schema":{"type":"string"}}}},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"security":[],"x-app":"marketing","x-public":true,"x-tool":true,"x-writes":true}},"/v1/marketing/leads":{"post":{"operationId":"post_marketing_leads","summary":"Files one public form in the deployment's own CRM.","description":"Files one public form in the deployment's own CRM. A sales inquiry or a\nprogram application becomes a lead: the person, and the form on their timeline\nwith every answer, the campaign and coupon its page carried; it is stated on the\nevent plane and mailed to the brand's sales mailbox. A body naming a job opening\nbecomes a candidate and its form, mailed to the brand's careers mailbox and stated\nnowhere. Program investor is an investor and their form at status submitted,\nstated nowhere, mailed to nobody, and sent a SAFE to sign (`sent` says whether it\nwent). No account is needed: every record lands in the brand's org. A person\nsigned in who applies to the beta also opens the products in beta (the CRM) for\nthe org they act in. Answers 201 with an opaque reference.\n\nA brand org whose Base cannot hold the CRM answers 503, a caller past ten forms\nin an hour 429, a body over 16 KiB 413, and a missing or malformed email 400 — in\nthat order; an investor's form then answers 400 for its name, its amount\n(\"The minimum investment is $25,000.\"), its address, entity, title and phone, in\nthat order.","tags":["marketing"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.LeadIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.Lead"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/leads/esign":{"post":{"operationId":"post_marketing_leads_esign","summary":"Takes Hanzo eSign's webhook: a SAFE was signed, countersigned, completed, declined or voided, and the investor's form in the brand's CRM moves to that status.","description":"Takes Hanzo eSign's webhook: a SAFE was signed, countersigned,\ncompleted, declined or voided, and the investor's form in the brand's CRM moves\nto that status. The caller is Hanzo eSign acting as itself: its own IAM\nclient_credentials token, verified by the identity boundary like every other.\nNo caller answers 401, and any caller but eSign's application 403.\n\nA status only moves forward (submitted, investor signed, countersigned,\ncompleted; or declined, or voided), so a replay or a late event changes\nnothing. The document must be the one the form recorded; any other, and any\nreference that names no investor's form, answers 200 with no status and\nchanges nothing.","tags":["marketing"],"requestBody":{"content":{"application/json":{"example":{"event":"DOCUMENT_SIGNED","payload":{"externalId":"lead_0123456789abcdef01234567","id":42,"recipients":[{"signingOrder":1,"signingStatus":"SIGNED"},{"signingOrder":2,"signingStatus":"NOT_SIGNED"}]}},"schema":{"$ref":"#/components/schemas/marketing.EsignEvent"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.Signing"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/leads/resume":{"post":{"operationId":"post_marketing_leads_resume","summary":"Signs a form the careers page posts one resume through, into the brand org's private careers bucket, and answers the key to name on the application (`resume_file`).","description":"Signs a form the careers page posts one resume through, into the brand\norg's private careers bucket, and answers the key to name on the application\n(`resume_file`). PUBLIC like the form itself: each caller is limited to ten an\nhour, a file that is not a PDF, DOC or DOCX of at most 10 MB is refused 400, and\na deployment that cannot sign one answers 503.","tags":["marketing"],"requestBody":{"content":{"application/json":{"example":{"name":"ada.pdf","size":120000,"type":"application/pdf"},"schema":{"$ref":"#/components/schemas/marketing.ResumeIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.ResumeForm"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/mail":{"post":{"operationId":"post_marketing_mail","summary":"Sends one email from the org to one person, the way a person on the org's team writes back to a lead from its record.","description":"Sends one email from the org to one person, the way a person on the org's team\nwrites back to a lead from its record.\n\nIt leaves by the org's own path, the one every marketing send takes: the org's\nmailbox when it has one, else the platform's notify rail, and never to an\naddress that opted out of the org's mail, whose company did, or that the\nplatform blocks (Sent is false then, and that is not an error). It carries the\nopt-out footer and List-Unsubscribe. The org's mailbox caps hold: at its cap\nthe send is refused with 429 and the time it frees.\n\nAn admin of the org acting, or SuperAdmin, may send: mail that leaves in the\norg's name is the team's to write, not every member's. The send is on the audit\ntrail before it leaves (marketing.mail.send: the address, the subject and the\nperson, never the text), and the mail, sent or refused, goes on the timeline of\nits person.\n\nA named handler, not a closure, so zipdoc can lift this prose into the registry.","tags":["marketing"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.MailIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.MailOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/promos":{"get":{"operationId":"get_marketing_promos","summary":"Returns every promo the deployment offers with its live counters: how many orgs have redeemed it and how many redemptions remain under the cap.","description":"Returns every promo the deployment offers with its live counters:\nhow many orgs have redeemed it and how many redemptions remain under the cap.\nThe promos are fleet-wide, not per-org — only the counters move.","tags":["marketing"],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"promo":{"active":true,"code":"first1000","maxRedemptions":1000,"percentOff":90},"redeemed":137,"remaining":863}]},"schema":{"$ref":"#/components/schemas/marketing.PromoList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/promos/{code}/eligibility":{"get":{"operationId":"get_marketing_promos_by_code_eligibility","summary":"Prices a promo against a plan and seat count.","description":"Prices a promo against a plan and seat count. It is PURE: nothing\nis redeemed, credited or counted, so it is safe to call from a pricing page on\nevery keystroke. An inactive promo or an exhausted cap quotes ineligible with\nthe reason rather than erroring.","tags":["marketing"],"parameters":[{"name":"code","in":"path","required":true,"description":"Code is the promo code from the path.","schema":{"type":"string"},"example":"first1000"},{"name":"plan","in":"query","required":false,"description":"Plan is the plan being priced: pro, max or team. Anything else (including\nthe free Developer plan) has no list price and so nothing to discount.","schema":{"type":"string"},"example":"team"},{"name":"seats","in":"query","required":false,"description":"Seats is the Team seat count; 0 means 1, and it is ignored for the\nsingle-seat plans.","schema":{"format":"int64","type":"integer"},"example":12}],"responses":{"200":{"content":{"application/json":{"example":{"chargeCents":7500,"code":"first1000","discountCents":22500,"eligible":true,"listCents":2500,"plan":"team","remaining":863,"seats":12},"schema":{"$ref":"#/components/schemas/marketing.Quote"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/promos/{code}/redeem":{"post":{"operationId":"post_marketing_promos_by_code_redeem","summary":"Records the caller org's claim on a promo.","description":"Records the caller org's claim on a promo. NOTHING IS CREDITED:\nthe redemption is a row, and credit into an org is an admin decision made on\nthe admin surface against an auditable ledger.\n\nThe plan is DERIVED from the org's live ACTIVE/TRIALING paid subscription and\ncan never be named by the caller — an org with no qualifying subscription is\nrefused, and so is one whose subscription cannot be read. The seat count is\nthe single-seat floor (claimSeats), so the recorded figure has no input that\ncan inflate it.\n\nGuards run under one lock so the cap cannot be raced past: the fleet-wide\nredemption cap, one redemption per org, one per payment instrument (REQUIRED),\nand the per-redemption ceiling.\n\nIt is IDEMPOTENT: an org that already redeemed gets its original redemption\nback with alreadyRedeemed true.","tags":["marketing"],"parameters":[{"name":"code","in":"path","required":true,"description":"Code is the promo code from the path.","schema":{"type":"string"},"example":"first1000"}],"requestBody":{"content":{"application/json":{"example":{"code":"first1000","instrument":"pm_1QxYz2AbCdEf"},"schema":{"$ref":"#/components/schemas/marketing.RedeemInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.RedeemResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/promos/{code}/redemption":{"get":{"operationId":"get_marketing_promos_by_code_redemption","summary":"Returns the caller org's OWN redemption of a promo — an org-scoped read, so it can never surface another tenant's.","description":"Returns the caller org's OWN redemption of a promo — an\norg-scoped read, so it can never surface another tenant's. Not found when this\norg has not redeemed it.","tags":["marketing"],"parameters":[{"name":"code","in":"path","required":true,"description":"Code is the promo code from the path, e.g. \"first1000\".","schema":{"type":"string"},"example":"first1000"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.Redemption"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/sequences":{"get":{"operationId":"get_marketing_sequences","summary":"Returns the org's drip sequences, most recently updated first.","description":"Returns the org's drip sequences, most recently updated first.","tags":["marketing"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned; 0 means 200 and nothing above 1000 is honoured.","schema":{"format":"int64","type":"integer"},"example":50}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.SequenceList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true},"post":{"operationId":"post_marketing_sequences","summary":"Registers a drip sequence in the caller's org.","description":"Registers a drip sequence in the caller's org. Name is\nrequired; status defaults to draft, and a sequence must be ACTIVE before it\nwill accept enrollments. The id, createdAt and updatedAt of the input are\nignored — the server assigns them.\n\nOrg admin or SuperAdmin only; a member of the org is refused.","tags":["marketing"],"requestBody":{"content":{"application/json":{"example":{"name":"Trial onboarding","status":"draft"},"schema":{"$ref":"#/components/schemas/marketing.Sequence"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.Sequence"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/sequences/{id}":{"get":{"operationId":"get_marketing_sequences_by_id","summary":"Returns one of the caller org's sequences together with its steps in send order.","description":"Returns one of the caller org's sequences together with its steps\nin send order. A sequence belonging to another org reads as not found.","tags":["marketing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the sequence id from the path, as returned by create.","schema":{"type":"string"},"example":"seq_7b3e5a1c9d024f68b0a3e7c5d9f1a248"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.SequenceView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/sequences/{id}/enroll":{"post":{"operationId":"post_marketing_sequences_by_id_enroll","summary":"Adds one contact or a whole audience to a sequence and schedules the first step for each.","description":"Adds one contact or a whole audience to a sequence and schedules the\nfirst step for each. The sequence must be ACTIVE (a draft sends nothing), and\nthe request must name exactly one of address or audienceId.\n\nEnrolling is ALL this does: the message itself is sent later by the drip\nengine, through the suppression gate, so an opted-out customer can be enrolled\nhere and still never be mailed. Re-posting is safe — an address this sequence\nalready took is counted in alreadyEnrolled and never double-dripped — which is\nwhat makes retrying a partially-applied announcement a resume rather than a\nsecond send.\n\nOrg admin or SuperAdmin only; a member of the org is refused.","tags":["marketing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the sequence id from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"audienceId":"aud_4c1e9b7a2d6f0538e4a7c9b1d3f5027a","channel":"email"},"schema":{"$ref":"#/components/schemas/marketing.EnrollInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"alreadyEnrolled":3,"enrolled":409,"resolved":412},"schema":{"$ref":"#/components/schemas/marketing.EnrollResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/sequences/{id}/enrollments":{"get":{"operationId":"get_marketing_sequences_by_id_enrollments","summary":"Returns who is walking one sequence, most recently enrolled first, with each walk's current step and next due time.","description":"Returns who is walking one sequence, most recently enrolled\nfirst, with each walk's current step and next due time.","tags":["marketing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the sequence id from the path.","schema":{"type":"string"},"example":"seq_7b3e5a1c9d024f68b0a3e7c5d9f1a248"},{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned; 0 means 200 and nothing above 1000 is honoured.","schema":{"format":"int64","type":"integer"},"example":100}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.EnrollmentList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/sequences/{id}/enrollments/{eid}/cancel":{"post":{"operationId":"post_marketing_sequences_by_id_enrollments_by_eid_cancel","summary":"Stops one walk mid-sequence and answers 204: no further step is sent, and steps already delivered are not recalled.","description":"Stops one walk mid-sequence and answers 204: no further step\nis sent, and steps already delivered are not recalled. Only an ACTIVE\nenrollment can be canceled — one already completed or canceled reads as not\nfound.\n\nOrg admin or SuperAdmin only; a member of the org is refused.","tags":["marketing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the sequence id from the path.","schema":{"type":"string"},"example":"seq_7b3e5a1c9d024f68b0a3e7c5d9f1a248"},{"name":"eid","in":"path","required":true,"description":"EID is the enrollment id from the path, as returned by a single-address\nenroll.","schema":{"type":"string"},"example":"enr_2a8d6f0b4c1e9375a0d2f6b8c4e19f73"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/sequences/{id}/status":{"post":{"operationId":"post_marketing_sequences_by_id_status","summary":"Flips draft/active/archived — the activation gate for sending, since only an active sequence accepts enrollments.","description":"Flips draft/active/archived — the activation gate for\nsending, since only an active sequence accepts enrollments. It does not touch\nenrollments already walking: archiving stops new ones, not in-flight ones.\n\nOrg admin or SuperAdmin only; a member of the org is refused.","tags":["marketing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the sequence id from the path.","schema":{"type":"string"},"example":"seq_7b3e5a1c9d024f68b0a3e7c5d9f1a248"}],"requestBody":{"content":{"application/json":{"example":{"id":"seq_7b3e5a1c9d024f68b0a3e7c5d9f1a248","status":"active"},"schema":{"$ref":"#/components/schemas/marketing.SequenceStatus"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.SequenceStatus"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/sequences/{id}/steps":{"get":{"operationId":"get_marketing_sequences_by_id_steps","summary":"Returns one sequence's steps in send order.","description":"Returns one sequence's steps in send order.","tags":["marketing"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the sequence id from the path, as returned by create.","schema":{"type":"string"},"example":"seq_7b3e5a1c9d024f68b0a3e7c5d9f1a248"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.StepList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true},"post":{"operationId":"post_marketing_sequences_by_id_steps","summary":"Appends a message to the END of a sequence: the new step's idx is one past the last, so steps arrive in the order they are added.","description":"Appends a message to the END of a sequence: the new step's idx is one\npast the last, so steps arrive in the order they are added. Body is required\nand delaySeconds must be \u003e= 0. Adding a step does not disturb enrollments\nalready walking — one that has passed this index simply never sees it.\n\nOrg admin or SuperAdmin only; a member of the org is refused.","tags":["marketing"],"parameters":[{"name":"id","in":"path","required":true,"description":"SequenceID is the sequence id from the path (the route's :id).","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"body":"Here is how to make your first request…","delaySeconds":86400,"subject":"Day 1: your first model call"},"schema":{"$ref":"#/components/schemas/marketing.StepInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.Step"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/summary":{"get":{"operationId":"get_marketing_summary","summary":"Rolls up the caller org's campaigns: how many there are, how many are active, and the summed budget and spend in cents.","description":"Rolls up the caller org's campaigns: how many there are, how many are\nactive, and the summed budget and spend in cents.","tags":["marketing"],"responses":{"200":{"content":{"application/json":{"example":{"active":3,"budget":500000,"campaigns":12,"spend":128400},"schema":{"$ref":"#/components/schemas/marketing.Summary"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/suppressions":{"delete":{"operationId":"delete_marketing_suppressions","summary":"Re-subscribes an address on one channel and answers 204.","description":"Re-subscribes an address on one channel and answers 204. The\nentry is named in the query. An address that is not on the list reads as not\nfound.\n\nOrg admin or SuperAdmin only; a member of the org is refused.","tags":["marketing"],"parameters":[{"name":"channel","in":"query","required":false,"description":"Channel is the surface the entry opts out of; empty is email.","schema":{"type":"string"},"example":"email"},{"name":"address","in":"query","required":false,"description":"Address is the entry: an address, or \"@example.com\" for a company.","schema":{"type":"string"},"example":"person@example.com"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true},"get":{"operationId":"get_marketing_suppressions","summary":"Returns the org's opt-out list, newest first — everyone the send gate will refuse to deliver to.","description":"Returns the org's opt-out list, newest first — everyone the\nsend gate will refuse to deliver to.","tags":["marketing"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned; 0 means 200 and nothing above 1000 is honoured.","schema":{"format":"int64","type":"integer"},"example":100}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.SuppressionList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true},"post":{"operationId":"post_marketing_suppressions","summary":"Records an opt-out for the org (admin / self-service management).","description":"Records an opt-out for the org (admin / self-service\nmanagement). Address is required; channel defaults to email. An address of\nthe form \"@example.com\" opts out the whole domain, a company; a free mail\nprovider's domain is refused 422. The admin org's list is the platform's:\nwhat it holds, every org's send gate refuses. It is idempotent:\nre-suppressing the same tuple keeps the original record rather than erroring.\nFrom here on the ONE send gate refuses that recipient on that channel.\n\nOrg admin or SuperAdmin only; a member of the org is refused.","tags":["marketing"],"requestBody":{"content":{"application/json":{"example":{"address":"person@example.com","channel":"email","reason":"asked support to stop"},"schema":{"$ref":"#/components/schemas/marketing.Suppression"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketing.Suppression"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/suppressions/check":{"get":{"operationId":"get_marketing_suppressions_check","summary":"Answers whether the org's send gate refuses an address, and which list holds it, by the same check every commercial send asks.","description":"Answers whether the org's send gate refuses an address, and\nwhich list holds it, by the same check every commercial send asks.","tags":["marketing"],"parameters":[{"name":"channel","in":"query","required":false,"description":"Channel is the surface the entry opts out of; empty is email.","schema":{"type":"string"}},{"name":"address","in":"query","required":false,"description":"Address is the entry: an address, or \"@example.com\" for a company.","schema":{"type":"string"},"example":"person@example.com"}],"responses":{"200":{"content":{"application/json":{"example":{"reason":"company unsubscribe by ada@example.com","scope":"domain","suppressed":true},"schema":{"$ref":"#/components/schemas/marketing.SuppressionCheck"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketing/unsubscribe":{"get":{"operationId":"get_marketing_unsubscribe","summary":"Is the PUBLIC one-click endpoint (no principal): a recipient clicks the signed link in an email footer.","description":"Is the PUBLIC one-click endpoint (no principal): a recipient\nclicks the signed link in an email footer. The token binds (org, channel,\naddress), so a caller can only opt OUT exactly the tuple it was minted for —\nnever another address and never another org. With company=true the address's\nwhole domain is opted out of this org's mail too, which a free mail address\nmay not ask (422); without it, the answer offers the company's domain when\nthere is one to offer. An invalid token is refused, and\na deployment with no KMS-sealed key refuses rather than accepting anything.","tags":["marketing"],"parameters":[{"name":"org","in":"query","required":false,"description":"Org is the org the link was minted for.","schema":{"type":"string"},"example":"acme"},{"name":"channel","in":"query","required":false,"description":"Channel is the surface to opt out of.","schema":{"type":"string"},"example":"email"},{"name":"address","in":"query","required":false,"description":"Address is the recipient to opt out.","schema":{"type":"string"},"example":"person@example.com"},{"name":"token","in":"query","required":false,"description":"Token is the HMAC over (org, channel, address). It is the ONLY authority\nhere — there is no principal — so it binds the request to one tuple and\nnothing else.","schema":{"type":"string"},"example":"9f2a…"},{"name":"company","in":"query","required":false,"description":"Company opts out everyone at the address's domain as well, in this org\nalone: a company's unsubscribe. An address at a free mail provider is a\nperson's and is refused 422.","schema":{"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"example":{"address":"person@example.com","channel":"email","unsubscribed":true},"schema":{"$ref":"#/components/schemas/marketing.Unsubscribed"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"security":[],"x-app":"marketing","x-public":true,"x-tool":true,"x-writes":true},"post":{"operationId":"post_marketing_unsubscribe","summary":"Is the one-click unsubscribe a mail client sends from the List-Unsubscribe header (RFC 8058): the same signed link the footer carries, POSTed with the form body List-Unsubscribe=One-Click.","description":"Is the one-click unsubscribe a mail client sends from the\nList-Unsubscribe header (RFC 8058): the same signed link the footer carries,\nPOSTed with the form body List-Unsubscribe=One-Click. It opts out exactly what\na click on the link does, under the same token check, and is as public.","tags":["marketing"],"parameters":[{"name":"org","in":"query","required":false,"description":"Org is the org the link was minted for.","schema":{"type":"string"},"example":"acme"},{"name":"channel","in":"query","required":false,"description":"Channel is the surface to opt out of.","schema":{"type":"string"},"example":"email"},{"name":"address","in":"query","required":false,"description":"Address is the recipient to opt out.","schema":{"type":"string"},"example":"person@example.com"},{"name":"token","in":"query","required":false,"description":"Token is the HMAC over (org, channel, address), the only authority here.","schema":{"type":"string"},"example":"9f2a…"}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"properties":{"List-Unsubscribe":{"description":"OneClick is the form's List-Unsubscribe field, \"One-Click\" from a mail\nclient. The token decides; this field only names the form.","type":"string"}},"type":"object"}},"multipart/form-data":{"schema":{"properties":{"List-Unsubscribe":{"description":"OneClick is the form's List-Unsubscribe field, \"One-Click\" from a mail\nclient. The token decides; this field only names the form.","type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"address":"person@example.com","channel":"email","unsubscribed":true},"schema":{"$ref":"#/components/schemas/marketing.Unsubscribed"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketing","x-public":true,"x-tool":true}},"/v1/marketplace":{"get":{"operationId":"get_marketplace","summary":"Lists every tool and agent the caller can reach in their own org and project, enriched with any public listing's title, category and price, and with installed=true on the ones already activated for that scope.","description":"Lists every tool and agent the caller can reach in their own org and\nproject, enriched with any public listing's title, category and price, and with\ninstalled=true on the ones already activated for that scope. It is the shop\nwindow: one read that answers what exists, what it costs and what is already on.","tags":["marketplace"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.marketCatalog"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/marketplace/install":{"post":{"operationId":"post_marketplace_install","summary":"Activates one tool for the caller's own org and project.","description":"Activates one tool for the caller's own org and project. A marketplace\ninstall IS the tool plane's activation write — one store, one truth — so an\ninstalled capability is immediately dispatchable and a monetized one is priced\nfrom its listing at every call. The tool must resolve in the caller's scope, so\ninstalling something that does not exist is refused rather than recorded.","tags":["marketplace"],"requestBody":{"content":{"application/json":{"example":{"tool":"summarize"},"schema":{"$ref":"#/components/schemas/marketplace.installReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.installState"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/marketplace/jobs":{"get":{"operationId":"get_marketplace_jobs","summary":"Lists the jobs the caller's org is a party to, newest first: as buyer, the work it hired — with the quotes it has not paid and the jobs being funded, each with the attempt that made it, so a hire whose answer was lost is found here — and as seller, the work it was hired for, which never includes another org's quote.","description":"Lists the jobs the caller's org is a party to, newest first: as buyer, the work\nit hired — with the quotes it has not paid and the jobs being funded, each with\nthe attempt that made it, so a hire whose answer was lost is found here — and as\nseller, the work it was hired for, which never includes another org's quote.\nAny member of the org.","tags":["marketplace"],"parameters":[{"name":"role","in":"query","required":false,"description":"Role is buyer — the jobs the caller's org hired for — or seller, the jobs it\nwas hired for. Buyer when empty.","schema":{"type":"string"},"example":"seller"},{"name":"status","in":"query","required":false,"description":"Status keeps one state.","schema":{"type":"string"},"example":"open"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.jobPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true},"post":{"operationId":"post_marketplace_jobs","summary":"Hires another org for a piece of work, through a public listing or by a direct offer, and answers 201 with the job — open, waiting for the seller.","description":"Hires another org for a piece of work, through a public listing or by a direct\noffer, and answers 201 with the job — open, waiting for the seller.\n\nIt is paid over x402, in two steps on this one call. Sent without payment, the\nterms are cleared first — principal decides whether the buyer may pay the seller\nthis amount, and a blocked payment, one that waits on the seller's tax form, and\none that clears only with tax withheld, which this rail does not withhold, are\nrefused and nothing is opened — and it answers 402 with the terms to sign, for\nthe job resource job:\u003cid\u003e: on PAYMENT-REQUIRED, in the body, and in the message.\nSent again with the signed authorization — on PAYMENT-SIGNATURE, or as\npayment — echoing that resource, the terms are cleared once more, the job is\nfunding, and the rail checks the payment against exactly those terms, checks\nit stays acceptable until a dispute could last be ruled on, holds it for this\njob, and sets the amount aside in the buyer's wallet: a wallet that cannot\ncover it answers 402 insufficient_funds and opens nothing. Nothing is paid\nuntil the buyer releases the job, or its review window passes after delivery;\na job that ends unpaid returns the amount to the wallet. Any member of the\nbuying org; a platform SuperAdmin inspecting another org cannot spend it.\n\nA hire sent with an attempt — the buyer's own key for it, in the body — is one\nhire however often it is sent: the same attempt with the same request answers\nthe same job, so a request whose answer was lost is sent again as it was, and\nopens one job and sets its amount aside once. It answers the quote's terms\nagain while the job is quoted or funding (a quote over its hour is given up\nand quoted anew), and the job, 201, once it opened. Another request under an\nattempt already used is refused, 422. The buyer's own jobs list its quotes\nand those being funded, with their attempts, so an attempt in flight is found\nthere too. Without an attempt, the same terms asked again within the hour\nanswer the same quote, and the same payment sent again answers the job it\nopened.","tags":["marketplace"],"requestBody":{"content":{"application/json":{"example":{"amount":"250.00","attempt":"8f14e45f-ea8d-4c4e-9c1b-0f3b2b1a7d6e","brief":"Summarize our Q3 filings","listing":"lst_4f1c"},"schema":{"$ref":"#/components/schemas/marketplace.hireIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.Job"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/marketplace/jobs/{id}":{"get":{"operationId":"get_marketplace_jobs_by_id","summary":"Reads one job the caller's org is a party to.","description":"Reads one job the caller's org is a party to. Another org's job, and one that\ndoes not exist, are the same 404.","tags":["marketplace"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the job, from the path.","schema":{"type":"string"},"example":"job_9a1f"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.Job"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/marketplace/jobs/{id}/accept":{"post":{"operationId":"post_marketplace_jobs_by_id_accept","summary":"Accepts a job the caller's org was hired for: the seller takes the work on and the clock toward its deadline is the seller's.","description":"Accepts a job the caller's org was hired for: the seller takes the work on and\nthe clock toward its deadline is the seller's. Only an open job, and only before\nits deadline.","tags":["marketplace"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the job, from the path.","schema":{"type":"string"},"example":"job_9a1f"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.Job"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/marketplace/jobs/{id}/cancel":{"post":{"operationId":"post_marketplace_jobs_by_id_cancel","summary":"Takes back a job the caller's org opened, before the seller accepts it.","description":"Takes back a job the caller's org opened, before the seller accepts it. Nothing\nwas paid: the amount set aside returns to the wallet.","tags":["marketplace"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the job, from the path.","schema":{"type":"string"},"example":"job_9a1f"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.Job"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/marketplace/jobs/{id}/decline":{"post":{"operationId":"post_marketplace_jobs_by_id_decline","summary":"Declines a job the caller's org was hired for, before any work.","description":"Declines a job the caller's org was hired for, before any work. Nothing was\npaid: the buyer's authorization is given up, never settled, and the amount it\nset aside returns to the buyer's wallet.","tags":["marketplace"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the job, from the path.","schema":{"type":"string"},"example":"job_9a1f"}],"requestBody":{"content":{"application/json":{"example":{"id":"job_9a1f","reason":"Booked through March"},"schema":{"$ref":"#/components/schemas/marketplace.declineIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.Job"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/marketplace/jobs/{id}/deliver":{"post":{"operationId":"post_marketplace_jobs_by_id_deliver","summary":"Records delivery of a job the caller's org accepted, before its deadline, and starts the review window: the buyer releases or disputes within it, or it releases itself when it closes.","description":"Records delivery of a job the caller's org accepted, before its deadline, and\nstarts the review window: the buyer releases or disputes within it, or it\nreleases itself when it closes.","tags":["marketplace"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the job, from the path.","schema":{"type":"string"},"example":"job_9a1f"}],"requestBody":{"content":{"application/json":{"example":{"id":"job_9a1f","note":"Summary attached","url":"https://files.example.com/q3.pdf"},"schema":{"$ref":"#/components/schemas/marketplace.deliverIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.Job"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/marketplace/jobs/{id}/dispute":{"post":{"operationId":"post_marketplace_jobs_by_id_dispute","summary":"Stops a job for a ruling, as either party: before delivery (and before the deadline), or within the review window after it.","description":"Stops a job for a ruling, as either party: before delivery (and before the\ndeadline), or within the review window after it. Nothing moves while it is\ndisputed. It ends when the buyer releases it, the seller refunds it, the\nplatform's arbiter rules, or the arbiter's time lapses and it is refunded.","tags":["marketplace"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the job, from the path.","schema":{"type":"string"},"example":"job_9a1f"}],"requestBody":{"content":{"application/json":{"example":{"id":"job_9a1f","reason":"The summary covers Q2, not Q3"},"schema":{"$ref":"#/components/schemas/marketplace.disputeIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.Job"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/marketplace/jobs/{id}/feedback":{"post":{"operationId":"post_marketplace_jobs_by_id_feedback","summary":"Rates the other party of a settled job — the seller when the caller's org bought, the buyer when it sold — once per party per job, and never edited.","description":"Rates the other party of a settled job — the seller when the caller's org\nbought, the buyer when it sold — once per party per job, and never edited. A\njob counts as settled once it was released, or refunded after the seller took\nit on; one cancelled or declined before any work earns nothing. What buyers say\nof a seller is its listing's and its own reputation in the shop. It answers 201\nwith the feedback recorded.","tags":["marketplace"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the job, from the path.","schema":{"type":"string"},"example":"job_9a1f"}],"requestBody":{"content":{"application/json":{"example":{"comment":"Thorough and on time","id":"job_9a1f","rating":5},"schema":{"$ref":"#/components/schemas/marketplace.feedbackIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.Feedback"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/marketplace/jobs/{id}/refund":{"post":{"operationId":"post_marketplace_jobs_by_id_refund","summary":"Refunds a job the caller's org accepted, as the seller, at any point before it is paid: nothing was moved, so the buyer's authorization is given up, never settled, and the amount it set aside returns to the buyer's wallet.","description":"Refunds a job the caller's org accepted, as the seller, at any point before it\nis paid: nothing was moved, so the buyer's authorization is given up, never\nsettled, and the amount it set aside returns to the buyer's wallet.","tags":["marketplace"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the job, from the path.","schema":{"type":"string"},"example":"job_9a1f"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.Job"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/marketplace/jobs/{id}/release":{"post":{"operationId":"post_marketplace_jobs_by_id_release","summary":"Releases a job the caller's org is paying for, paying the seller the whole amount: the buyer's authorization is settled on the rail, once, and the rail states the payment.","description":"Releases a job the caller's org is paying for, paying the seller the whole\namount: the buyer's authorization is settled on the rail, once, and the rail\nstates the payment. The buyer may release any time after acceptance, including\nto end a dispute.","tags":["marketplace"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the job, from the path.","schema":{"type":"string"},"example":"job_9a1f"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.Job"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/marketplace/listings":{"get":{"operationId":"get_marketplace_listings","summary":"Returns the listings the caller's own org has published — what this org is offering, not what it can buy.","description":"Returns the listings the caller's own org has published — what this\norg is offering, not what it can buy. A publisher only ever sees its own rows.","tags":["marketplace"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.listingPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true},"post":{"operationId":"post_marketplace_listings","summary":"Offers one thing the caller's org owns on the marketplace — an agent, persona, app, skill or MCP server, or, for the platform, a tool sold per call — optionally monetized.","description":"Offers one thing the caller's org owns on the marketplace — an agent,\npersona, app, skill or MCP server, or, for the platform, a tool sold per call —\noptionally monetized. The owning app is asked, as the org, whether the thing is\nthe org's, so a listing never sells something that does not exist or belongs to\nsomeone else: a tool every org reaches is the platform's, and a server enabled\noff the public shelf is the shelf's. A monetized listing names a payout wallet of\nthe org's own, which wallets confirms, so a price is never unpayable. The price\nis exact to 18 decimal places, so a per-call price below a cent is a real price\nand not a rounded-away zero. An org admin publishes, at most 1000 listings an\norg; it answers 201 with the created row.","tags":["marketplace"],"requestBody":{"content":{"application/json":{"example":{"kind":"agent","price":"250","public":true,"recipient":"wal_9f2","title":"Research analyst","tool":"researcher"},"schema":{"$ref":"#/components/schemas/marketplace.publishReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.Listing"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/marketplace/listings/{id}":{"delete":{"operationId":"delete_marketplace_listings_by_id","summary":"Withdraws one of the caller org's listings from the marketplace and answers 204.","description":"Withdraws one of the caller org's listings from the marketplace and\nanswers 204. Only the publishing org can remove its own listing; an id that is\nunknown, or belongs to another org, is the same 404, so a probe learns nothing\nabout what exists. Removing a listing removes its price from per-call enforcement;\nit does not uninstall the tool for anyone who already installed it, and a job\nalready opened through it runs to its end. An org admin unpublishes.","tags":["marketplace"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the listing, from the path.","schema":{"type":"string"},"example":"lst_1"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true},"patch":{"operationId":"patch_marketplace_listings_by_id","summary":"Edits one of the caller org's listings — its copy, price, payout wallet, visibility and documentation — under the same rules publish applies, and answers the listing as it now stands.","description":"Edits one of the caller org's listings — its copy, price, payout wallet,\nvisibility and documentation — under the same rules publish applies, and\nanswers the listing as it now stands. Another org's listing and one that does\nnot exist are the same 404. An org admin edits.","tags":["marketplace"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the listing to edit, from the path.","schema":{"type":"string"},"example":"lst_4f1c"}],"requestBody":{"content":{"application/json":{"example":{"id":"lst_4f1c","price":"300","public":true},"schema":{"$ref":"#/components/schemas/marketplace.patchReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.Listing"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/marketplace/seller":{"get":{"operationId":"get_marketplace_seller","summary":"Answers where the caller's org stands as a seller, in one read: its founders' identity verification (KYC) and legal entity (KYB), its tax form and whether it is certified and valid, its own sanctions screening — only what an org may see about itself — the payout wallet it proved, the TaxPrincipalCredentials signed for its agents, what it earned in the year from the economic events the rails stated, and the 1099s payers furnished it.","description":"Answers where the caller's org stands as a seller, in one read: its founders'\nidentity verification (KYC) and legal entity (KYB), its tax form and whether it\nis certified and valid, its own sanctions screening — only what an org may see\nabout itself — the payout wallet it proved, the TaxPrincipalCredentials signed\nfor its agents, what it earned in the year from the economic events the rails\nstated, and the 1099s payers furnished it. Ready says nothing is missing. Each\nowning app is asked as the org; one this deployment does not run is named absent\nrather than read as empty. An org admin reads it.","tags":["marketplace"],"parameters":[{"name":"year","in":"query","required":false,"description":"Year is the calendar year (UTC); the current one when zero.","schema":{"format":"int64","type":"integer"},"example":2026}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.Onboarding"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/marketplace/seller/payout":{"post":{"operationId":"post_marketplace_seller_payout","summary":"Starts binding one of the caller org's wallets as the wallet it is paid into: answers a challenge naming the org, the wallet and its address, to be signed with that wallet within fifteen minutes and sent to POST /v1/marketplace/seller/payout/verify.","description":"Starts binding one of the caller org's wallets as the wallet it is paid into:\nanswers a challenge naming the org, the wallet and its address, to be signed\nwith that wallet within fifteen minutes and sent to POST\n/v1/marketplace/seller/payout/verify. A newer challenge replaces an older one.\nAn org admin binds.","tags":["marketplace"],"requestBody":{"content":{"application/json":{"example":{"wallet":"wal_9f2"},"schema":{"$ref":"#/components/schemas/marketplace.payoutIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.PayoutChallenge"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/marketplace/seller/payout/verify":{"post":{"operationId":"post_marketplace_seller_payout_verify","summary":"Binds the caller org's payout wallet: the signature over its outstanding challenge is recovered, and must recover to the wallet's address, before the challenge expires.","description":"Binds the caller org's payout wallet: the signature over its outstanding\nchallenge is recovered, and must recover to the wallet's address, before the\nchallenge expires. A challenge binds once. It answers the payout wallet as it\nnow stands; a job offered directly to the org is paid into it. An org admin\nbinds.","tags":["marketplace"],"requestBody":{"content":{"application/json":{"example":{"signature":"0x5f1c…1b"},"schema":{"$ref":"#/components/schemas/marketplace.verifyIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.Payout"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/marketplace/shop":{"get":{"operationId":"get_marketplace_shop","summary":"Searches every public listing of every kind — agents and personas to hire, apps, skills, MCP servers and tools — newest first, with facets by kind, category, price and rating, paged.","description":"Searches every public listing of every kind — agents and personas to hire,\napps, skills, MCP servers and tools — newest first, with facets by kind,\ncategory, price and rating, paged. Each listing carries its seller's public\nface, its reputation from settled jobs and installs, and the command and MCP\noperation that buy it. It needs no credential and answers the same to everyone.","tags":["marketplace"],"parameters":[{"name":"q","in":"query","required":false,"description":"Q keeps listings whose title, description, category, thing or seller\ncontains every word of it, case-insensitively.","schema":{"type":"string"},"example":"research"},{"name":"kind","in":"query","required":false,"description":"Kind keeps one kind: agent, persona, app, skill, mcp or tool.","schema":{"type":"string"},"example":"agent"},{"name":"category","in":"query","required":false,"description":"Category keeps one category, exactly.","schema":{"type":"string"}},{"name":"price","in":"query","required":false,"description":"Price keeps free listings or priced ones.","schema":{"type":"string"}},{"name":"rating","in":"query","required":false,"description":"Rating keeps listings rated at least this many stars, 1 to 5.","schema":{"format":"int64","type":"integer"}},{"name":"seller","in":"query","required":false,"description":"Seller keeps one seller org's listings.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit is the page size: 48 by default, 200 at most.","schema":{"format":"int64","type":"integer"},"example":48},{"name":"offset","in":"query","required":false,"description":"Offset is where the page starts.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.Shop"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"security":[],"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/marketplace/shop/{id}":{"get":{"operationId":"get_marketplace_shop_by_id","summary":"Reads one public listing as the shop shows it — its seller's public face, its reputation and the ways to buy it.","description":"Reads one public listing as the shop shows it — its seller's public face, its\nreputation and the ways to buy it. A private listing and one that does not\nexist are the same 404. It needs no credential.","tags":["marketplace"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the listing, from the path.","schema":{"type":"string"},"example":"lst_4f1c"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.ShopListing"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"security":[],"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/marketplace/uninstall":{"post":{"operationId":"post_marketplace_uninstall","summary":"Deactivates one tool for the caller's own org and project, so it stops being dispatchable there.","description":"Deactivates one tool for the caller's own org and project, so it stops\nbeing dispatchable there. It is the exact inverse of install and touches the same\nactivation record; deactivating something that was never active is not an error.\nThe listing itself is untouched — this withdraws the caller's use of a capability,\nnot anyone's offer of it.","tags":["marketplace"],"requestBody":{"content":{"application/json":{"example":{"tool":"summarize"},"schema":{"$ref":"#/components/schemas/marketplace.installReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/marketplace.installState"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"marketplace","x-public":true,"x-tool":true}},"/v1/mcp":{"post":{"operationId":"post_mcp","summary":"The agent endpoint: every subsystem's operations as MCP tools","description":"Model Context Protocol over JSON-RPC 2.0 — one POST per message, stateless, protocol revision 2026-07-28. tools/list answers without a credential with one tool per subsystem (its operations in the \"op\" enum) plus \"describe\", which returns one operation's input schema. tools/call names a subsystem tool and carries {\"op\": \u003coperation\u003e, \"input\": \u003cits arguments\u003e}; it takes the same bearer the REST API does, and a call that carries none is answered 401 with a WWW-Authenticate header naming the resource metadata at /.well-known/oauth-protected-resource, which names the authorization server to sign in at. The tool surface is the public contract: the operator's admin product is not offered, and a name that would disclose a secret or mutate an identity is withheld — the list says how many, under _meta.","tags":["openapi"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCPRequest"}}}},"responses":{"2XX":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCPResponse"}}}}},"x-app":"openapi","x-public":true}},"/v1/meet/call":{"get":{"operationId":"meetCall","summary":"Where a room's call happens","description":"Answers where a room's call happens, for a caller who may join it.\n\nIt is the \"resolved at render\" half of HIP-0523 §12: a surface showing a channel\nasks for the room's call at the moment it draws one, rather than reading a media\nroom name someone stored on the room. Nothing here is persisted and nothing is\ncreated — a media room begins existing when the first participant connects and\nstops when the last leaves, so there is no call to create and none to clean up.\n\nAUTHORIZATION IS THE JOIN DECISION, unchanged and shared. It delegates to\nstate.admits, the same function POST /v1/meet/getToken and all three recording\noperations admit on, so a caller who is told where a call is, is a caller who\ncould have joined it. Answering the address to someone who cannot join would make\nthis a space-membership oracle for anyone who can guess a room id.\n\nIt deliberately does NOT report whether a call is in progress. That is a fact the\nmedia server holds and this binary would have to ask for it over the network,\nwhich is a different decision with a different failure mode — and reporting\n\"nobody is in this call\" when the question could not be asked would be exactly the\nunknown-rendered-as-zero this surface refuses elsewhere.","tags":["meet"],"parameters":[{"name":"space","in":"query","required":true,"description":"Space is the space uuid holding the room, as GET /v1/team/rooms\nreports it. It is the segment the caller's membership is checked against.","schema":{"type":"string"}},{"name":"room","in":"query","required":true,"description":"Room is the room's own id within that space, as GET /v1/team/rooms\nreports it. It is opaque here: meet keeps no rooms and cannot say whether\none exists, only whether this caller may be seated in the space holding\nit.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/meet.venue"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"meet","x-public":true,"x-tool":true}},"/v1/meet/getToken":{"post":{"operationId":"post_meet_gettoken","summary":"Mint a join token for one video room","description":"Answers with a LiveKit join token for exactly the room named in the body. The body is the RAW token as text/plain — one opaque string, not JSON and not wrapped in an envelope, which is what the office client reads.\n\nThe caller presents its space session as a Bearer. Every clause is a refusal: the session must verify, its SIGNED space claim must equal the room's leading name segment — rooms are named `\u003cspace\u003e_\u003croom\u003e_\u003cid\u003e`, and that prefix is the only thing binding a room to a tenant — and the session must carry a privileged space role, so a guest is refused rather than seated.\n\nThe participant identity is the SESSION'S, never the body's. `_id` is accepted for compatibility with the published client bundle and deliberately ignored: LiveKit treats the identity as unique and ejects a duplicate, so honouring a caller-chosen one would let anyone in a space kick out a colleague and impersonate them. `participantName` is a display name only.\n\nAn unconfigured deployment answers 503 under its own name rather than 404, and the refusal states only that the office is unconfigured — the reason names key material and stays in the boot log.","tags":["meet"],"x-app":"meet","x-public":true}},"/v1/meet/health":{"get":{"operationId":"get_meet_health","summary":"Reports whether the office can mint join tokens.","description":"Reports whether the office can mint join tokens.\n\nIt reports whether this deployment holds the LiveKit key pair it needs:\nready:true with 200 when tokens can be minted, the SAME body with ready:false,\nstatus \"degraded\" and 503 when they cannot — so a probe and a dashboard both\nread the degraded state instead of someone grepping a boot log.\n\nIt takes no credential and is reachable on every public host, so it withholds\nboth the reason and the signing key's name on purpose: ready is the whole\ndashboard fact, and the reason — which names the key file and the Secret — is\nwritten to the boot log where an operator already is.","tags":["meet"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/meet.meetHealth"}}},"description":"ok"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/meet.meetHealth"}}},"description":"service unavailable"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"meet","x-public":true,"x-tool":true}},"/v1/meet/record":{"delete":{"operationId":"meetRecordStop","summary":"Stop a room's recording","description":"Ends a room's recording — EVERY one of them.\n\nWhoever the room admits may stop it, including someone who did not start it:\na person being recorded has to be able to end it, and a rule that only the\nstarter may stop would deny exactly that. Stopping is free — a caller made to\npay to stop being recorded would be paying for the wrong thing.\n\n200 MEANS THE ROOM IS NOT BEING RECORDED, and that is why this ends all of them\nrather than the first. \"At most one per room\" is an invariant this surface wants\nand cannot impose: reading the list and starting are two calls, and two replicas\nracing through that window both start. When the list comes back holding two, two\nis the truth — and ending one while answering 200 tells the person withdrawing\nconsent that it stopped while a second worker keeps writing. A stop that cannot\nfinish the job says so instead.\n\nStopping a room that is not being recorded is not an error. The answer names the\nroom with no recording on it, which is the state the caller asked for.","tags":["meet"],"parameters":[{"name":"room","in":"query","required":true,"description":"Room is the LiveKit room, named the way the office client names one\n(`\u003cspace\u003e_\u003cname\u003e_\u003cid\u003e`). Its leading segment is what binds the room to a\ntenant, and it is the segment the caller's membership is checked against.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/meet.recording"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"meet","x-public":true,"x-tool":true},"get":{"operationId":"meetRecordRead","summary":"What is being recorded in a room, and where the file goes","description":"Answers what is being recorded in a room, and where the file went.\n\nIt reports the recording that is RUNNING, and once none is, the most recent one\nthe media server still holds — with its final status and its object. That second\ncase is the one that matters for finding a file: the answer to a start is the\nonly other place the location appears, and a client that lost it, or a colleague\nwho was not the one to press record, has nowhere else to look.\n\nIt is behind the same check as starting one: where a recording of a private\nconversation is kept is a fact about that conversation, so it is told to the\npeople the room admits and to nobody else.","tags":["meet"],"parameters":[{"name":"room","in":"query","required":true,"description":"Room is the LiveKit room, named the way the office client names one\n(`\u003cspace\u003e_\u003cname\u003e_\u003cid\u003e`). Its leading segment is what binds the room to a\ntenant, and it is the segment the caller's membership is checked against.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/meet.recording"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"meet","x-public":true,"x-tool":true},"post":{"operationId":"meetRecordStart","summary":"Start recording a room, or return the recording already running","description":"Begins recording a room, or hands back the recording already running.\n\nA recording is a durable artifact of a conversation, so only someone this room\nwould admit may make one: the caller is authorized by the SAME decision\n/v1/meet/getToken makes about the same room, and refused with the same 401.\n\nA SECOND START RETURNS THE FIRST rather than refusing it. There is at most one\nrecording per room and this operation's job is to establish that there is one —\nwhich is already true when a colleague, or the caller's own double-click,\nstarted it a moment ago. The answer is the same shape either way, naming the\nrecording that is actually running, so a client never has to tell the two cases\napart to find the id.\n\nA deployment with no media server address or no object store answers 503 naming\nwhich, because a recording that silently does not happen is worse than one that\nis refused. The reason reaches only a caller this room already admits.","tags":["meet"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/meet.recordIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/meet.recording"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"meet","x-public":true,"x-tool":true}},"/v1/meet/session":{"get":{"operationId":"get_meet_session","summary":"What this caller may open a room in","description":"Answers the three facts the native lobby cannot know on its own: the identity a seat would be taken under, the LiveKit address the browser dials, and the spaces this caller may open a room in.\n\nIt is the SAME decision getToken makes, asked before the room exists rather than after it is named. A room is bound to its tenant by its name's leading space segment, and only a space this answer lists will be admitted — so the lobby offers exactly what the mint would grant, and a person is never shown a room they would then be refused. Spaces the caller holds only a guest role in are omitted for that reason.\n\nAn empty list is a real answer, not a fault: an IAM identity with no space has no room to open, and the lobby says so instead of failing.\n\n`ws` is empty when this deployment has not been told where its media plane is (LIVEKIT_WS). Token minting is unaffected — the published office client supplies its own address — so this is a degraded native UI, not a degraded service, and the lobby refuses to dial rather than guessing a host.","tags":["meet"],"x-app":"meet","x-public":true}},"/v1/messages":{"post":{"operationId":"post_messages","summary":"Implements the Anthropic Messages API.","description":"Implements the Anthropic Messages API.","tags":["ai"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.AnthropicRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.AnthropicResponse"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/messages/count_tokens":{"post":{"operationId":"post_messages_count_tokens","summary":"Implements POST /v1/messages/count_tokens.","description":"Implements POST /v1/messages/count_tokens. Claude Code\ncalls it before a request; it returns {\"input_tokens\": N} for the given\nmodel + messages + tools.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.TokenCount"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/metrics/batch":{"post":{"operationId":"post_metrics_batch","summary":"Ingest a MetricBatch — the same payload the ZAP transport carries","description":"Writes every sample in a luxfi/metric `MetricBatch` into the calling org's store and answers `{written}`: the number of SAMPLES stored, not families and not metrics. This is the exact wire shape the ZAP `MsgMetricBatch` transport carries, so the HTTP endpoint and the optional ZAP push receiver share one code path and one meaning — the transport is an optimisation, never a different contract.\n\nA counter or gauge lands as one sample. A histogram or summary contributes DERIVED `\u003cname\u003e_sum` and `\u003cname\u003e_count` series, so one metric can write more than one sample and `written` can exceed the number of metrics you sent. The batch's own `TimestampNs` stamps every sample it carries.\n\nThe tenant is the gateway-minted `X-Org-Id` header, falling back to the deployment brand and then `default`; each org gets its own store, WAL-durable under the deployment's data dir. A body that does not decode is 400.","tags":["metrics"],"x-app":"metrics","x-public":true}},"/v1/metrics/health":{"get":{"operationId":"get_metrics_health","summary":"How many metric series this deployment holds for your org","description":"Reports the native metrics store's live state for the calling tenant: the subsystem version, the resolved `org`, and `series` — the number of distinct series actually held right now, read out of the store rather than a constant. It is not a dependency probe and has nothing downstream to fail on: the store is in-process, so this answers 200 whenever the process is up.\n\nThe tenant is the gateway-minted `X-Org-Id` header, falling back to the deployment brand and then `default`. This surface trusts the edge rather than re-deriving the org from a validated claim of its own, so it belongs behind the gateway and nowhere else.","tags":["metrics"],"x-app":"metrics","x-public":true}},"/v1/metrics/logs/health":{"get":{"operationId":"get_metrics_logs_health","summary":"How many log records this deployment holds for your org","description":"Reports the native log store's live state for the calling tenant: the subsystem version and `records`, the count actually held right now rather than a constant. Not a dependency probe — the store is in-process, so this answers 200 whenever the process is up.\n\nThe tenant is the gateway-minted `X-Org-Id` header, falling back to the deployment brand and then `default`.","tags":["metrics"],"x-app":"metrics","x-public":true}},"/v1/metrics/logs/query":{"get":{"operationId":"get_metrics_logs_query","summary":"Search your org's logs by label, time and substring","description":"Answers `{count, records}`, newest first. `match` is the same `k=v,k2=v2` superset label matcher the metrics query uses; `contains` is a case-insensitive substring test against the record body; `start` and `end` are nanosecond bounds.\n\nA bound that is absent, empty or unparseable becomes 0, which means UNBOUNDED — a malformed `start` widens the search rather than failing it. `limit` caps the page and defaults to 100 when absent or non-positive, so an unfiltered read is never the whole ring.\n\nThe tenant is the gateway-minted `X-Org-Id` header, falling back to the deployment brand and then `default`, so a search can only reach the org the edge asserted.","tags":["metrics"],"x-app":"metrics","x-public":true}},"/v1/metrics/logs/write":{"post":{"operationId":"post_metrics_logs_write","summary":"Append structured log records for your org","description":"Takes `{records:[{t, level, body, labels}]}`, appends each one, and answers `{written}`. Bodies are stored verbatim; `labels` are the indexed dimensions a query filters on, so what you do not label you can only find by substring.\n\n`t` is NANOSECONDS since the Unix epoch. A record sent without one is stored at 0 and then falls outside any query carrying a lower bound — the usual reason a successful write does not read back. Retention is a bounded ring, 1048576 records per org, oldest evicted first. No record is validated or rejected, so `written` is the number of records SENT; only a body that does not decode at all is 400.\n\nThe tenant is the gateway-minted `X-Org-Id` header, falling back to the deployment brand and then `default`; each org's records live in its own WAL-durable store.","tags":["metrics"],"x-app":"metrics","x-public":true}},"/v1/metrics/query":{"get":{"operationId":"get_metrics_query","summary":"Read your org's series back over a time range","description":"Answers `{count, series}`, where `count` is the number of matching SERIES and each series carries the samples that fall inside the window. `name` selects one series name, and an absent or empty `name` returns every series the org holds. `match` is a `k=v,k2=v2` label matcher applied as a SUPERSET test: a series matches when it carries all the named labels with those values, extra labels and all.\n\n`start` and `end` are nanoseconds since the Unix epoch, and here is the rule worth knowing: a bound that is absent, empty or unparseable becomes 0, which this store reads as UNBOUNDED. A malformed `start` therefore silently widens the query instead of failing it. There is no limit parameter — the window and the matcher are the whole of what bounds the answer.\n\nThe tenant is the gateway-minted `X-Org-Id` header, falling back to the deployment brand and then `default`, so a query can only ever read the org the edge asserted.","tags":["metrics"],"x-app":"metrics","x-public":true}},"/v1/metrics/traces/health":{"get":{"operationId":"get_metrics_traces_health","summary":"How many spans this deployment holds for your org","description":"Reports the native trace store's live state for the calling tenant: the subsystem version and `spans`, the count actually held right now. Not a dependency probe — the store is in-process, so this answers 200 whenever the process is up.\n\nThe tenant is the gateway-minted `X-Org-Id` header, falling back to the deployment brand and then `default`.","tags":["metrics"],"x-app":"metrics","x-public":true}},"/v1/metrics/traces/query":{"get":{"operationId":"get_metrics_traces_query","summary":"Recent spans for your org over a time range","description":"Answers `{count, spans}`, newest first, filtered on each span's START time. `start` and `end` are nanosecond bounds where 0 — which is what an absent, empty or unparseable value becomes — means UNBOUNDED, so a malformed bound widens the listing instead of failing it. `limit` defaults to 100 when absent or non-positive.\n\nIt lists SPANS, not traces: several spans of one trace each count separately and each take a slot against `limit`. Assembling one trace is /v1/metrics/traces/trace. The tenant is the gateway-minted `X-Org-Id` header, falling back to the deployment brand and then `default`.","tags":["metrics"],"x-app":"metrics","x-public":true}},"/v1/metrics/traces/trace":{"get":{"operationId":"get_metrics_traces_trace","summary":"Every span of one trace — the waterfall","description":"Answers `{spans}`: every span the org holds for the trace id in `id`, in the order they were appended, which is what a waterfall view renders. Unlike the other reads there is no count, no time range and no limit — a trace is addressed by id or not at all.\n\nAn id with no spans answers an EMPTY list, never a 404: the store cannot tell a trace that never existed from one whose spans retention has already dropped, so it does not pretend to. The tenant is the gateway-minted `X-Org-Id` header, falling back to the deployment brand and then `default`, and a trace id belonging to another org is simply not in this org's store.","tags":["metrics"],"x-app":"metrics","x-public":true}},"/v1/metrics/traces/write":{"post":{"operationId":"post_metrics_traces_write","summary":"Append spans for your org","description":"Takes `{spans:[{traceId, spanId, parentId, name, startNs, endNs, attrs}]}`, appends each, and answers `{written}` — the number of spans sent. Every span is indexed by its trace id as it lands, which is what makes the waterfall read possible without a second store.\n\nTimes are NANOSECONDS since the Unix epoch. Retention is a bounded ring of 1048576 spans per org: past that the OLDEST are evicted to keep the newest 1048576, and the trace index is rebuilt — so a long-lived trace can lose its early spans while its later ones survive, and a waterfall read is best-effort against retention, not a guarantee.\n\nThe tenant is the gateway-minted `X-Org-Id` header, falling back to the deployment brand and then `default`. A body that does not decode is 400.","tags":["metrics"],"x-app":"metrics","x-public":true}},"/v1/metrics/write":{"post":{"operationId":"post_metrics_write","summary":"Append samples to your org's named, labelled series","description":"Takes `{series:[{name, labels, samples:[{t, v}]}]}`, appends every sample, creating each series on first write, and answers `{written}` — again counting SAMPLES, so three series of ten samples is 30.\n\nA series is identified by its name PLUS its whole label set, so adding one label makes a different series rather than annotating an existing one. Timestamps `t` are NANOSECONDS since the Unix epoch; a sample sent without one is stored at 0 and is then excluded by any query that sets a lower bound, which is the usual reason a write that reported success does not read back. Retention is per series and bounded — past 65536 samples the oldest are evicted.\n\nThe tenant is the gateway-minted `X-Org-Id` header, falling back to the deployment brand and then `default`. A body that does not decode is 400; nothing else is validated or rejected.","tags":["metrics"],"x-app":"metrics","x-public":true}},"/v1/ml/health":{"get":{"operationId":"get_ml_health","summary":"Whether model serving can actually work right now","description":"Reports whether the model-serving plane is genuinely usable: that the Kubernetes API answers, that the InferenceService CRD is actually served by this cluster, and that the cluster holds at least one serving runtime to run a model ON. It is a REAL probe, not status theatre — it makes a live call rather than reporting a flag set at boot.\n\n200 only when everything checks out. Otherwise 503 CARRYING THE REPORT — which component failed, and the real error — and that body is the reason this is not a typed op: a typed op reaches a non-2xx by returning an error, and the envelope that produces would drop exactly the detail the probe exists to deliver.\n\nThe runtime count is reported as its own field and is a SEPARATE fact from the CRD being served: a cluster with the CRD but no runtime accepts a deploy and then never schedules it, so reporting only the CRD would answer 200 while every model hangs. A runtime list this service cannot read reports the read error instead of a count, because a missing grant is a broken probe and not an empty cluster.\n\nIt answers about the cluster, not about a tenant, so it takes no org and reveals no tenant data. A cluster with no kserve CRD reports degraded honestly rather than failing later at the first deploy.","tags":["ml"],"x-app":"ml","x-public":true}},"/v1/ml/models":{"get":{"operationId":"get_ml_models","summary":"Lists the inference models deployed in the caller's org.","description":"Lists the inference models deployed in the caller's org. Each entry\ncarries the model's name, when Kubernetes admitted it, and kserve's live status\n— the spec is on the single-model read. An org that has deployed nothing gets\nan empty list.","tags":["ml"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ml.mlResourceList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ml","x-public":true,"x-tool":true},"post":{"operationId":"post_ml_models","summary":"Deploys one inference model for the caller's org, and answers 201 with the model as Kubernetes admitted it.","description":"Deploys one inference model for the caller's org, and answers 201\nwith the model as Kubernetes admitted it.\n\nThe `spec` is a kserve InferenceService spec, passed through unchanged — this\nplane owns the tenancy, the billing and the namespace, and kserve owns what a\nmodel IS. An unfunded org is refused BEFORE anything is created, so nobody runs\nfree GPU compute and nobody is charged for a resource that was never made.","tags":["ml"],"requestBody":{"content":{"application/json":{"example":{"name":"sentiment","spec":{"predictor":{"model":{"modelFormat":{"name":"sklearn"},"storageUri":"s3://models/sentiment"}}}},"schema":{"$ref":"#/components/schemas/ml.mlCreate"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ml.mlResource"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ml","x-public":true,"x-tool":true}},"/v1/ml/models/{name}":{"delete":{"operationId":"delete_ml_models_by_name","summary":"Deletes a deployed inference model.","description":"Deletes a deployed inference model. kserve owns the teardown: the\nInferenceService goes away and the serving deployment behind it follows, so the\nmodel stops answering predict calls. Answers 204, or 404 for a name the\ncaller's org does not own.","tags":["ml"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the resource to act on, taken from the path. Lower-cased and\ntrimmed to the DNS-1123 label a CustomResource's metadata.name must be.","schema":{"type":"string"},"example":"sentiment"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ml","x-public":true,"x-tool":true},"get":{"operationId":"get_ml_models_by_name","summary":"Returns one deployed inference model.","description":"Returns one deployed inference model. Its spec comes with it, and\nkserve's live status, which is where readiness and the serving address appear.\nA name the caller's org does not own answers 404, exactly as an unknown name\ndoes, so a probe learns nothing about another tenant's models.","tags":["ml"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the resource to act on, taken from the path. Lower-cased and\ntrimmed to the DNS-1123 label a CustomResource's metadata.name must be.","schema":{"type":"string"},"example":"sentiment"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ml.mlResource"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"ml","x-public":true,"x-tool":true},"patch":{"operationId":"patch_ml_models_by_name","summary":"Change a deployed model in place","description":"Applies a JSON merge patch to one of the caller org's deployed models and answers the updated resource — the way to change a model's image, replica count or resource requests without tearing the deployment down.\n\nThe body is relayed to Kubernetes VERBATIM. That is deliberate and it is why this route is not a typed op: re-encoding a merge patch changes what it means, because an integer that round-trips through a generic decoder comes back a float. Merge-patch semantics apply as written — a null removes a field, and a list is replaced whole rather than merged.\n\nScoped to the caller's own tenant namespace, resolved from the validated org and project; a name the caller's tenant does not hold is a 404, never another tenant's resource. An empty body is refused, and a patch Kubernetes rejects comes back 422 with its reason rather than being silently dropped.","tags":["ml"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"ml","x-public":true}},"/v1/ml/models/{name}/predict":{"post":{"operationId":"post_ml_models_by_name_predict","summary":"Run inference against one of your deployed models","description":"Sends the request body to the named model's predictor and answers the predictor's reply — its status code, its body bytes and its Content-Type, all unchanged. This is the inference call itself, not a description of one.\n\nVERBATIM IS THE CONTRACT, and it is why this route is not a typed op: a model-side error has to surface as the model's own error, not as this layer's paraphrase of it. The body shape is the kserve v2 inference protocol's, which means the runtime decides it, not this API. The v2 model name defaults to the resource name — kserve's single-model convention — and a multi-model runtime selects one with the `model` query parameter.\n\nA model that exists but has no serving address yet answers 503 'not ready' rather than a confusing connection error: deployed is not the same as serving. Scoped to the caller's own tenant namespace from the validated org and project, so a name another tenant owns is simply a 404. The predictor's response body is read up to a fixed ceiling.","tags":["ml"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"ml","x-public":true}},"/v1/models":{"get":{"operationId":"get_models","summary":"Returns the list of available models from the routing table.","description":"Returns the list of available models from the routing table.\n\nPUBLIC BY DESIGN, AND IT DOES NOT AUTHENTICATE — that is the whole contract, so it\nis stated here rather than left to be inferred. The catalogue is the same for\neveryone (listAvailableModels takes no principal), docs.hanzo.ai fetches it from\nthe browser, and every policy layer around it says so: the authz filter lists\n\"models\" as public, filter_balance does not gate it, the rate limiter excludes it,\nand cloud's spend.Reachable carries /v1/models/ as \"the model catalog the shell\nreads for discovery\".\n\nSO THE Authorization HEADER IS NOT AN ADMISSION CHECK HERE. It is read for ONE\nthing — annotating gated SKUs with the caller's own access standing — and\nannotation degrades to nothing when there is no verified principal.\n\nA credential that is presented is verified, never merely shape-checked: a caller\nusing /v1/models to ask \"is my key working?\" gets an honest answer, because a key\nthat does not verify annotates nothing rather than reading as accepted.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.ModelList"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/models/providers":{"get":{"operationId":"get_models_providers","summary":"Public, secret-free list of the providers serving the models that GET /v1/models lists — the same source, projected.","description":"Public, secret-free list of the providers serving the models that\nGET /v1/models lists — the same source, projected. Safe unauthenticated: no\nkeys, URLs, or config are returned, and it reports a SET of names, never\nwhich provider serves which model.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/ai.ModelProviders"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/models/vendors/{vendor}":{"get":{"operationId":"get_models_vendors_by_vendor","summary":"Lists every model a vendor lists now, each entry exactly as the vendor listed it (prices, context, output bound, modalities, parameters, created, expiration), and when the list was last synced.","description":"Lists every model a vendor lists now, each entry exactly as the vendor\nlisted it (prices, context, output bound, modalities, parameters, created,\nexpiration), and when the list was last synced. ?free=1 keeps the models the\nvendor charges nothing for. Public, as the vendor's own list is: the free lane\nreads it in place of the vendor's.","tags":["ai"],"parameters":[{"name":"vendor","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"ai","x-public":true}},"/v1/models/vendors/{vendor}/events":{"get":{"operationId":"get_models_vendors_by_vendor_events","summary":"Lists the changes syncs read in a vendor's model list, newest first.","description":"Lists the changes syncs read in a vendor's model list, newest\nfirst. Each is new, back, gone, price, free (was priced, now free) or paid (was\nfree, now priced), with the price list before and after. ?id= keeps one model's;\n?limit= bounds the rows (100, at most 1000).","tags":["ai"],"parameters":[{"name":"vendor","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"ai","x-public":true}},"/v1/models/{model}/access":{"get":{"operationId":"get_models_by_model_access","summary":"Returns the caller's own standing for a gated model: \"granted\", \"requested\", or empty when they have never asked.","description":"Returns the caller's own standing for a gated model:\n\"granted\", \"requested\", or empty when they have never asked.","tags":["ai"],"parameters":[{"name":"model","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"additionalProperties":{"type":"string"},"type":"object"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true},"post":{"operationId":"post_models_by_model_access","summary":"Records the caller's waitlist request for a gated model and answers their new standing.","description":"Records the caller's waitlist request for a gated model and\nanswers their new standing. Authed, idempotent, and self-scoped: the row is keyed\nto the caller's own org and identity, never to a body-supplied owner.","tags":["ai"],"parameters":[{"name":"model","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"properties":{"data":{"$ref":"#/components/schemas/ModelAccess"}},"type":"object"}]}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/mq/health":{"get":{"operationId":"get_mq_health","summary":"Reports whether the message plane behind this surface answers.","description":"Reports whether the message plane behind this surface answers.","tags":["mq"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/mq.Health"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"mq","x-public":true,"x-tool":true}},"/v1/mq/info":{"get":{"operationId":"get_mq_info","summary":"Returns the broker's identity and the org's stream count.","description":"Returns the broker's identity and the org's stream count.","tags":["mq"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/mq.infoOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"mq","x-public":true,"x-tool":true}},"/v1/mq/stream":{"get":{"operationId":"get_mq_stream","summary":"Returns the org's streams, name-ordered, with their live state.","description":"Returns the org's streams, name-ordered, with their live state.","tags":["mq"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit caps the streams returned (1–1000, default 100).","schema":{"format":"int64","type":"integer"}},{"name":"offset","in":"query","required":false,"description":"Offset skips that many streams, name-ordered.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/mq.Streams"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"mq","x-public":true,"x-tool":true},"post":{"operationId":"post_mq_stream","summary":"Creates a durable stream in the org's namespace and returns it.","description":"Creates a durable stream in the org's namespace and returns it.","tags":["mq"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/mq.Config"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/mq.Stream"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"mq","x-public":true,"x-tool":true}},"/v1/mq/stream/{name}":{"delete":{"operationId":"delete_mq_stream_by_name","summary":"Removes a stream with all its messages and consumers.","description":"Removes a stream with all its messages and consumers. Irreversible.","tags":["mq"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the stream name, from the path.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"mq","x-public":true,"x-tool":true},"get":{"operationId":"get_mq_stream_by_name","summary":"Returns one stream's configuration and live state.","description":"Returns one stream's configuration and live state.","tags":["mq"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the stream name, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/mq.Stream"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"mq","x-public":true,"x-tool":true},"put":{"operationId":"put_mq_stream_by_name","summary":"Reconfigures an existing stream; the path names the stream, and the immutable fields (storage, retention) must restate what they are.","description":"Reconfigures an existing stream; the path names the stream, and the\nimmutable fields (storage, retention) must restate what they are.","tags":["mq"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the stream name, unique within the org (alphanumeric, hyphens, underscores).","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/mq.Config"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/mq.Stream"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"mq","x-public":true,"x-tool":true}},"/v1/mq/stream/{name}/message":{"get":{"operationId":"get_mq_stream_by_name_message","summary":"Reads stored messages without a consumer: by sequence, by newest on a subject, or walking a subject forward from a sequence.","description":"Reads stored messages without a consumer: by sequence, by newest on a\nsubject, or walking a subject forward from a sequence.","tags":["mq"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the stream name, from the path.","schema":{"type":"string"}},{"name":"seq","in":"query","required":false,"description":"Seq reads the message at this sequence (with next_by_subject: the walk's start).","schema":{"format":"uint64","type":"integer"}},{"name":"last_by_subject","in":"query","required":false,"description":"LastBySubject reads the newest message on this org-relative subject.","schema":{"type":"string"}},{"name":"next_by_subject","in":"query","required":false,"description":"NextBySubject walks forward from seq collecting messages on this org-relative subject (wildcards supported).","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps a next_by_subject walk (1–1000, default 100).","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/mq.readOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"mq","x-public":true,"x-tool":true}},"/v1/mq/stream/{name}/message/{seq}":{"delete":{"operationId":"delete_mq_stream_by_name_message_by_seq","summary":"Erases one message by sequence; the sequence gap remains.","description":"Erases one message by sequence; the sequence gap remains.","tags":["mq"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the stream name, from the path.","schema":{"type":"string"}},{"name":"seq","in":"path","required":true,"description":"Seq is the message's stream sequence, from the path.","schema":{"format":"uint64","type":"integer"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"mq","x-public":true,"x-tool":true}},"/v1/mq/stream/{name}/purge":{"post":{"operationId":"post_mq_stream_by_name_purge","summary":"Removes messages from a stream, leaving its consumers in place.","description":"Removes messages from a stream, leaving its consumers in place.","tags":["mq"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the stream name, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/mq.Purge"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/mq.purgeOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"mq","x-public":true,"x-tool":true}},"/v1/mq/stream/{stream}/consumer":{"get":{"operationId":"get_mq_stream_by_stream_consumer","summary":"Returns a stream's consumers, name-ordered, with delivery state.","description":"Returns a stream's consumers, name-ordered, with delivery state.","tags":["mq"],"parameters":[{"name":"stream","in":"path","required":true,"description":"Stream is the stream name, from the path.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps the consumers returned (1–1000, default 100).","schema":{"format":"int64","type":"integer"}},{"name":"offset","in":"query","required":false,"description":"Offset skips that many consumers, name-ordered.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/mq.pickOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"mq","x-public":true,"x-tool":true},"post":{"operationId":"post_mq_stream_by_stream_consumer","summary":"Creates a durable pull consumer on a stream and returns it.","description":"Creates a durable pull consumer on a stream and returns it.","tags":["mq"],"parameters":[{"name":"stream","in":"path","required":true,"description":"Stream is the stream name, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/mq.makeIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/mq.Consumer"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"mq","x-public":true,"x-tool":true}},"/v1/mq/stream/{stream}/consumer/{name}":{"delete":{"operationId":"delete_mq_stream_by_stream_consumer_by_name","summary":"Removes a consumer and its delivery state; unacknowledged messages stay in the stream.","description":"Removes a consumer and its delivery state; unacknowledged messages\nstay in the stream.","tags":["mq"],"parameters":[{"name":"stream","in":"path","required":true,"description":"Stream is the stream name, from the path.","schema":{"type":"string"}},{"name":"name","in":"path","required":true,"description":"Name is the consumer name, from the path.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"mq","x-public":true,"x-tool":true},"get":{"operationId":"get_mq_stream_by_stream_consumer_by_name","summary":"Returns one consumer's configuration and delivery state.","description":"Returns one consumer's configuration and delivery state.","tags":["mq"],"parameters":[{"name":"stream","in":"path","required":true,"description":"Stream is the stream name, from the path.","schema":{"type":"string"}},{"name":"name","in":"path","required":true,"description":"Name is the consumer name, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/mq.Consumer"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"mq","x-public":true,"x-tool":true}},"/v1/mq/stream/{stream}/consumer/{name}/next":{"post":{"operationId":"post_mq_stream_by_stream_consumer_by_name_next","summary":"Pulls the consumer's next batch.","description":"Pulls the consumer's next batch. Delivered messages are acknowledged on\ndelivery — the broker will not redeliver what this call returns; an empty\nwait answers 408.","tags":["mq"],"parameters":[{"name":"stream","in":"path","required":true,"description":"Stream is the stream name, from the path.","schema":{"type":"string"}},{"name":"name","in":"path","required":true,"description":"Name is the consumer name, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/mq.nextIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/mq.readOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"mq","x-public":true,"x-tool":true}},"/v1/network":{"get":{"operationId":"get_network","summary":"Returns the caller's org overlay network on the Zero Trust fabric.","description":"Returns the caller's org overlay network on the Zero Trust fabric.\n\nThe org has at most ONE overlay, projected from the edge-routers tagged with its\n\"org-\u003corg\u003e\" role attribute: nodes is the real router count and status is\n\"connected\" once at least one router has dialed home, \"provisioning\" while none\nhas. An org with no routers gets an empty list, never a fabricated network.\n\nThe read degrades rather than erroring: a deployment with no ZT credential, and a\ncontroller that cannot be reached, both answer 200 with an empty list so the\nconsole's Networks page renders a clean empty state instead of an error.","tags":["network"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/network.networkList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"network","x-public":true,"x-tool":true}},"/v1/network/identities":{"get":{"operationId":"get_network_identities","summary":"Returns the fabric identities the caller's org owns.","description":"Returns the fabric identities the caller's org owns.\n\nOne row per identity tagged with the org's \"org-\u003corg\u003e\" role attribute, each\nnaming the IAM subject it logs in as. A steward sees every one; a plain member\nsees only its own, since who else is on the org's network is not a member's\nto read, and a plain member's API key, which holds no identity, is refused.\n\nA tenancy read over the full inventory, so like the mesh list it does NOT\ndegrade: an unconfigured deployment answers 503.","tags":["network"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/network.identityList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"network","x-public":true,"x-tool":true},"post":{"operationId":"post_network_identities","summary":"Puts the caller on the org's overlay as its own IAM subject.","description":"Puts the caller on the org's overlay as its own IAM subject.\n\nThe identity is the one whose externalId is the caller's `sub`, admitted by\nthe controller's \"iam\" auth policy: the caller logs in to the fabric with its\nown IAM access token, and nothing is enrolled. It is named by the subject\nunless a name is given, and carries the org's \"org-\u003corg\u003e\" role attribute plus\nany supplied roles — each scoped to the org, and a \"\u003cservice\u003e-host\" role\nrefused unless the org has published that service. Roles are a steward's to\ntake: a plain member joins with the org role alone, and asking for more is\n403 before the controller is written.\n\nAn API key is refused 403: the fabric admits an IAM access token, a person's\nor an application's, and a key has none to log in with.\n\nIDEMPOTENT: a caller who already has an identity gets the same one back, with\nany of these roles it lacked added — which is how one person's identity comes\nto serve every org they act in.\n\nA write, so it does not degrade: an unconfigured deployment answers 503.","tags":["network"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/network.identityIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/network.identityView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"network","x-public":true,"x-tool":true}},"/v1/network/identities/{id}":{"delete":{"operationId":"delete_network_identities_by_id","summary":"Takes one of the org's fabric identities out of the org.","description":"Takes one of the org's fabric identities out of the org.\n\nThe identity's \"org-\u003corg\u003e\" role and every role scoped to the org are\nremoved and the rest is left alone, so an identity another org shares keeps\nworking there. The identity itself is deleted when no org role is left on\nit, or when the caller IS its IAM subject — a person may always remove\nthemselves.\n\nAn id belonging to another org — or to nothing — is 404 before any write\nreaches the controller: whether an identity exists is itself a cross-tenant\nfact, and a delete may only ever act on what the caller could list, which for\na plain member is its own identity. A fabric administrator is the\ncontroller's own and is refused.","tags":["network"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the identity id from the path. The URL is the addressing authority,\nso it binds from there whatever else the request carries.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"network","x-public":true,"x-tool":true}},"/v1/network/routers":{"get":{"operationId":"get_network_routers","summary":"Returns the Zero Trust routers the caller's org owns.","description":"Returns the Zero Trust routers the caller's org owns.\n\nOne row per real ZT edge-router tagged with the org's \"org-\u003corg\u003e\" role attribute,\ncarrying the controller's own health signal: \"online\" when connected, \"disabled\"\nwhen administratively disabled, \"offline\" otherwise. region is filled only from a\n\"region-\u003cslug\u003e\" role attribute and omitted when the router carries none, so the\ncolumn renders \"—\" rather than a guess.\n\nThe read degrades rather than erroring: a deployment with no ZT credential, and a\ncontroller that cannot be reached, both answer 200 with an empty list.","tags":["network"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/network.routerList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"network","x-public":true,"x-tool":true}},"/v1/network/services":{"get":{"operationId":"get_network_services","summary":"Returns the Zero Trust edge services the caller's org owns.","description":"Returns the Zero Trust edge services the caller's org owns.\n\nOne row per real ZT edge service tagged with the org's \"org-\u003corg\u003e\" role\nattribute: mtls is \"required\" when the service mandates end-to-end encryption and\n\"enabled\" otherwise (the fabric always mutually authenticates every link), and\nstatus is \"active\" because a listed service is a configured, dialable entry. A\nservice tagged for another org, or tagged for none, is invisible here.\n\nUnlike the network and router reads this does NOT degrade: an unconfigured\ndeployment answers 503 and an unreachable controller surfaces the upstream's\nstatus, so a mesh page never renders \"no services\" for a fabric it simply could\nnot read.","tags":["network"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/network.meshServiceList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"network","x-public":true,"x-tool":true},"post":{"operationId":"post_network_services","summary":"Puts a name on the org's overlay: a fabric service forwarding to host:port on whichever of the org's devices carries the \"\u003cname\u003e-host\" role, dialable at \"\u003cname\u003e.\u003corg\u003e.zt\" by any of the org's identities — and by the cloud's own, which is what lets a BYO cluster's apiserver be attached to the fleet with a \".zt\" kubeconfig.","description":"Puts a name on the org's overlay: a fabric service forwarding\nto host:port on whichever of the org's devices carries the \"\u003cname\u003e-host\"\nrole, dialable at \"\u003cname\u003e.\u003corg\u003e.zt\" by any of the org's identities — and by\nthe cloud's own, which is what lets a BYO cluster's apiserver be attached to\nthe fleet with a \".zt\" kubeconfig.\n\nAnswers 201 with the service and its DNS name. The objects behind it are\ncreated in dependency order and unwound on failure, so a half-published\nservice never lingers on the fabric. Publishing is a steward's act — an\nadmin of the org or its own machine client — and a plain member is 403.\n\nA write, so it does not degrade: an unconfigured deployment answers 503.","tags":["network"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/network.serviceIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/network.publishedView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"network","x-public":true,"x-tool":true}},"/v1/network/services/{id}":{"delete":{"operationId":"delete_network_services_by_id","summary":"Takes a name off the org's overlay: the two policies, the service and its two configs that publishing made, in that order, and the \"\u003cname\u003e-host\" role from each of the org's identities — that role exists only for the bind policy to select, and a role naming no service is one the identities endpoint refuses to write.","description":"Takes a name off the org's overlay: the two policies, the\nservice and its two configs that publishing made, in that order, and the\n\"\u003cname\u003e-host\" role from each of the org's identities — that role exists\nonly for the bind policy to select, and a role naming no service is one\nthe identities endpoint refuses to write.\n\nOnly objects carrying this service's own names are deleted, so a policy\nthat selects the service by attribute is left alone. An id belonging to\nanother org — or to nothing — is 404 before any write, as for an identity.\nLike publishing it is a steward's act, and a plain member is 403 before the\ncontroller is read.","tags":["network"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the service id from the path. The URL is the addressing authority,\nso it binds from there whatever else the request carries.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"network","x-public":true,"x-tool":true}},"/v1/network/{id}":{"get":{"operationId":"get_network_by_id","summary":"Returns one overlay network by id, scoped to the caller's org.","description":"Returns one overlay network by id, scoped to the caller's org.\n\nThe org has exactly one overlay network and its id is derived from the org, so\nany other id — another tenant's, or one that does not exist — is 404 rather than\na peek across the tenant boundary. An org whose network exists but has no\nedge-routers is 404 too, for the same reason the list is empty: there is no\noverlay until something is on it.","tags":["network"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the network id from the path. The URL is the addressing authority, so\nit binds from there whatever else the request carries.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/network.networkView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"network","x-public":true,"x-tool":true}},"/v1/node":{"get":{"operationId":"get_node","summary":"Returns the caller org's currently connected bot nodes: what each one calls itself, the platform it runs on, its agent version, when its socket was established, and the capabilities and commands it reported.","description":"Returns the caller org's currently connected bot nodes: what each one\ncalls itself, the platform it runs on, its agent version, when its socket was\nestablished, and the capabilities and commands it reported.\n\nOnly this org's nodes are listed — the org is half of every key in the table it\nreads — and only nodes attached to THIS replica, because the list is of live\nsockets rather than of registrations. The capability and command lists are the\nnode's own self-report: useful to show, never load-bearing, because what a node\nmay actually be asked to do is decided at the socket against the deployment's\nallowlist.","tags":["node"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/node.nodesView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"node","x-public":true,"x-tool":true}},"/v1/node/connect":{"get":{"operationId":"get_node_connect","summary":"The socket a bot node dials and holds open to become invokable.","description":"Upgrades to a WebSocket and keeps it for the life of the node. cloud writes a challenge frame immediately; the node answers with a connect frame naming the protocol range it speaks, the role `node`, its own node id, and the display name, platform, agent version, capabilities and commands it reports for itself. On acceptance the session is registered, the node appears in this org's node list, and invocations begin arriving as frames on the same connection.\n\nThe upgrade needs a validated principal and answers 401 without one. The org is the gateway's verdict — injected after IAM validation and after any client copy is stripped — and is never read from the request itself, because a caller that could name an org could attach a machine into someone else's tenant.\n\nA request carrying an Origin header is refused outright. A node is a daemon and a browser has no business here; since no same-origin policy applies to WebSockets, a page could otherwise ride a signed-in viewer's session into registering a node. Removing the whole category is the gate, not an allowlist of brand domains. The handshake deadline is one fixed instant rather than a per-read timer, so a peer cannot hold a pre-handshake socket open indefinitely by sending frames this endpoint ignores.\n\nTwo things to get right. Everything the node declares about itself — capabilities, commands, platform — is a SELF-REPORT: it is useful to show and never load-bearing, because what the node may actually be asked to run is decided at this socket against the deployment's allowlist. And a node can only ever answer calls placed on its own connection: correlation ids are minted under the connection id and checked against it, so naming another node's in-flight call resolves nothing.","tags":["node"],"x-app":"node","x-public":true}},"/v1/node/peer/invoke":{"post":{"operationId":"post_node_peer_invoke","summary":"Replica-to-replica forward of one invocation to the pod holding the node's socket.","description":"A machine hop, not a caller-facing route. A node's socket lands on one replica while invocations land on any, so the replica that took the request forwards it here to the one that actually holds the node, and returns that answer as its own.\n\nIt authenticates with the shared peer token, compared in constant time, and carries no user identity at all. That is why the org arrives IN THE BODY here: the forwarding replica already derived it from a gateway-validated header, so the value is a fact being relayed rather than a claim being made. On any caller-facing route the same field would be a cross-tenant invoke primitive.\n\nIt fails closed on its own configuration: with no peer token set, or a half-wired cluster that has presence but no way to forward, it serves 503 and forwards nothing — an unauthenticated endpoint that takes an org from a body is precisely the hole. A missing or wrong token is 403, and the forwarded body is bounded.\n\nTwo things to get right. Its refusals are text/plain rather than the JSON every zip error uses, so a client decoding them as JSON will fail on the error path only. And an invocation that RAN but was denied still answers 200 here, carrying a stable error token in the JSON body — no such node, timeout, node gone, denied, failed — which the calling replica maps back onto the status codes a caller sees. Authorization already ran on this replica at the socket and is deliberately not repeated.","tags":["node"],"x-app":"node","x-public":true}},"/v1/node/{id}/invoke":{"post":{"operationId":"post_node_by_id_invoke","summary":"Ask one of your connected machines to run a command, and get its answer back.","description":"Sends {command, params, timeoutMs, idempotencyKey} to the named node and answers with what the node returned: {ok, payload, code, message}, where payload is the node's own JSON passed through — cloud routes the call, it does not interpret the result. A reply that is not valid JSON becomes an empty payload rather than corrupting the response, which ok and code already qualify.\n\nNeither the node nor the org is a body field: the node is the path and the org is the caller's validated identity, and a field for either would be a field somebody could set to a stranger's. A validated principal is required (401 without one), and a node id that belongs to another org answers exactly like one that does not exist — not found — so this cannot be used to probe another tenant's fleet.\n\nAuthorization happened ONCE, at the socket, on the replica holding that node — the only place that knows what the node declared it can do. A node attached to a different replica is reached through the peer forward and is authorized by the same code with the same session in hand, so a local node and a forwarded one cannot get different answers. The timeout defaults to 30s and is clamped to 5 minutes, so one request can never pin a node's socket open indefinitely.\n\nsystem.run is rewritten before dispatch: its approval control fields are re-derived from the approval record and whatever the caller claimed is discarded, because a caller that could pre-approve itself is the whole thing approvals exist to prevent. No approval registry is wired today, so an invocation CLAIMING an approval is refused while an ordinary one is unaffected.\n\nThe one thing to get right: a refusal is a 403 carrying a DOMAIN body — {error, code, reason} — not the flat error envelope the rest of cloud returns, and the same body comes back whether the pre-flight sanitize refused it or the node's own gate did. Switch on `code`. The remaining failures are ordinary statuses: the node not answering in time is 504, and a node that disconnected or could not be reached is 502.","tags":["node"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"node","x-public":true}},"/v1/notify/credentials/{provider}/{key}":{"delete":{"operationId":"delete_notify_credentials_by_provider_by_key","summary":"Removes one of your org's notify provider credentials.","description":"Removes one of your org's notify provider credentials.\n\nThe value is forgotten in KMS. A provider missing a key it cannot send\nwithout is no longer picked for its channel, and a send that pins it fails\nwith the key it lacks. Removing a key that is not set succeeds, since what was\nasked for is already true. Org admin only.","tags":["notify"],"parameters":[{"name":"provider","in":"path","required":true,"description":"Provider is the delivery provider the credential is for.","schema":{"type":"string"}},{"name":"key","in":"path","required":true,"description":"Key is the credential's name within that provider.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"notify","x-public":true,"x-tool":true},"put":{"operationId":"put_notify_credentials_by_provider_by_key","summary":"Sets one of your org's notify provider credentials.","description":"Sets one of your org's notify provider credentials.\n\nThe value is sealed in KMS under your org and read by notify alone, at the\nmoment it sends; no route answers it back, this one included. Setting a key\nthat is already set replaces it, which is how a credential is rotated, and the\nnext send uses the new value. The key must be one the provider reads — Twilio's\naccount-sid, auth-token and from-number, say — and anything else is a 400\nnaming the keys it does read. An unknown provider is a 404.\n\nOrg admin only: a credential set here is what every message the org sends\ngoes out with.","tags":["notify"],"parameters":[{"name":"provider","in":"path","required":true,"description":"Provider is the delivery provider the credential is for: twilio, plivo,\ntwilio_email or mail.","schema":{"type":"string"},"example":"twilio"},{"name":"key","in":"path","required":true,"description":"Key is one of the credentials that provider reads, such as auth-token or\nsmtp-host. A key the provider does not read is refused.","schema":{"type":"string"},"example":"auth-token"}],"requestBody":{"content":{"application/json":{"example":{"key":"auth-token","provider":"twilio","value":"…"},"schema":{"$ref":"#/components/schemas/notify.notifyCredential"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/notify.notifyStored"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"notify","x-public":true,"x-tool":true}},"/v1/notify/health":{"get":{"operationId":"get_notify_health","summary":"Reports that the notify send surface is mounted.","description":"Reports that the notify send surface is mounted.\n\nIt is a pure liveness probe: it answers 200 whenever this subsystem is mounted\nand checks nothing downstream, so an \"ok\" here says the routes are reachable, not\nthat any provider credential is configured. The body is notifyd's verbatim, so\nprobes and clients that keyed on the standalone service keep working unchanged.","tags":["notify"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/notify.notifyHealth"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"notify","x-public":true,"x-tool":true}},"/v1/notify/send":{"post":{"operationId":"post_notify_send","summary":"Delivers one transactional message by email or SMS through the caller org's own provider credential.","description":"Delivers one transactional message by email or SMS through the caller\norg's own provider credential.\n\nThe channel comes from the body — sms or email — and the provider credential is\nread from KMS at orgs/\u003corg\u003e/notify/\u003cservice\u003e/\u003ckey\u003e, never from the environment.\nThe org is the validated principal's, never a client-supplied value, so a caller\ncan only ever send as their own tenant; an unauthenticated caller gets 401.\nNaming no provider picks the one whose credentials are actually configured\n(Twilio, then Plivo for SMS; Twilio Email, then SMTP for email) and fails closed\nwhen none is. Delivery is synchronous and per recipient: one recipient answers\nthe bare {message_id,status} outcome, several answer the {items:[…]} envelope. A\nterminal provider failure is a 200 whose status is failed with the reason in\nerror, never a transport error. sync=true is REQUIRED — an async dispatch\nanswers 503, because the queue plane that would run it is owned elsewhere. The\nmessage body wins verbatim when present; otherwise template_id (or the event\nname) selects a built-in template rendered against template_vars.","tags":["notify"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/notify.notifySend"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"notify","x-public":true,"x-tool":true}},"/v1/notify/send/email":{"post":{"operationId":"post_notify_send_email","summary":"Delivers one transactional email through the caller org's own provider credential.","description":"Delivers one transactional email through the caller org's own\nprovider credential.\n\nIt is the channel-pinned form of the generic send: identical in every respect\nexcept that the channel is fixed to email, OVERRIDING whatever the body names —\nso a body that says sms still goes out as mail. The provider is the org's own\nemail credential from KMS (Twilio Email, then SMTP), resolved for the validated\nprincipal's org; an unauthenticated caller gets 401. Subject is carried on the\nemail channel only.","tags":["notify"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/notify.notifySend"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"notify","x-public":true,"x-tool":true}},"/v1/notify/send/sms":{"post":{"operationId":"post_notify_send_sms","summary":"Delivers one transactional SMS through the caller org's own provider credential.","description":"Delivers one transactional SMS through the caller org's own provider\ncredential.\n\nIt is the channel-pinned form of the generic send: identical in every respect\nexcept that the channel is fixed to sms, OVERRIDING whatever the body names —\nso a body that says email still goes out as a text message. The provider is the\norg's own SMS credential from KMS (Twilio, then Plivo), resolved for the\nvalidated principal's org; an unauthenticated caller gets 401.","tags":["notify"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/notify.notifySend"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"notify","x-public":true,"x-tool":true}},"/v1/o11y/alerts":{"get":{"operationId":"GetAlerts","summary":"Returns the org's current alerts.","description":"Returns the org's current alerts. Viewer gate.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yAlertsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/alerts/heartbeat":{"get":{"operationId":"get_o11y_alerts_heartbeat","summary":"Reports whether the alert path's heartbeat is still arriving: the dead-man's switch for paging.","description":"Reports whether the alert path's heartbeat is still arriving:\nthe dead-man's switch for paging. The o11y ruler fires one alert forever,\nlabelled watchdog=\"true\", and every notification of it that reaches this\nprocess is a heartbeat — recorded as ALERT-HEARTBEAT, never sent to a human.\n\nIt answers 200 with the heartbeat's age while one arrived within the last 15\nminutes, and 503 once none has. A 503 means the path from the ruler to this\nreceiver stopped — the ruler, its Alertmanager, or this process — which nothing\ninside the cluster can be trusted to say, so something OUTSIDE it polls this and\npages on the 503. Process-local, like the replay ring: a restart starts the\nclock again rather than answering 503 before the first beat can arrive.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.Heartbeat"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/alerts/last":{"get":{"operationId":"get_o11y_alerts_last","summary":"Replay the alert records this process took","description":"Answers the most recent Alertmanager deliveries THIS process received, as plain text — one greppable `ALERT-RECEIVED` line per alert, followed by the `ALERT-DELIVERED` / `ALERT-UNDELIVERED` outcome of carrying it out of the process, newest last, so piping to `tail` reads in arrival order. `(none)` when nothing has landed.\n\nArrival and delivery are separate lines because they are separate facts that fail independently. Alertmanager can tell you it dispatched a notification, never that anything received it; this process taking the call says nothing about whether a human was reached. Reading only the first as if it were the second is how a pager stays silent for months behind a log where everything looks fine.\n\nThe ring is PROCESS-LOCAL and bounded to the last 200 lines. Both are the point: a record that outlived the process that took the call would be a claim about something nobody observed, and an unbounded log is a memory leak with a nice name. A restart empties it.","tags":["o11y"],"x-app":"o11y","x-public":true}},"/v1/o11y/alerts/{receiver}":{"post":{"operationId":"post_o11y_alerts_by_receiver","summary":"Take an Alertmanager notification and page a human","description":"Records one Alertmanager webhook delivery and pages the on-call. Each alert prints an `ALERT-RECEIVED` line and joins the replay ring, then the batch is carried out of the process by the egress chain: the org's KMS-custodied Slack bot token first (the ONE product Slack egress, not a second webhook credential), then an email to `CLOUD_ALERTS_EMAIL_TO` on the org's own notify credential, then a plain POST to `CLOUD_ALERTS_WEBHOOK_URL` — which needs no Slack connection and so works in exactly the state that silences the first. Resolved notifications page too: \"it recovered\" is the half of an incident people are actually waiting for. An alert labelled `watchdog=\"true\"` is the path's heartbeat (see `GET /v1/o11y/alerts/heartbeat`) and pages nobody.\n\nTHE STATUS CODE REPORTS DELIVERY, NOT ARRIVAL. 200 `ok` means an egress accepted the batch. If none did — including when none is configured at all — it answers **503** naming the failure, so Alertmanager retries and counts it in `alertmanager_notifications_failed_total`. An alert nobody could be told about must never answer the same way as one that was delivered.\n\nA body that will not parse is still recorded (with empty fields) rather than rejected: the delivery happened, which is the fact being recorded, and a 400 would make Alertmanager retry a malformed payload forever.\n\nThe receiver segment is Alertmanager's own receiver name, a parameter rather than a hand-listed route because the receiver set is config, not code.","tags":["o11y"],"parameters":[{"name":"receiver","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"o11y","x-public":true}},"/v1/o11y/authz/check":{"post":{"operationId":"AuthzCheck","summary":"Evaluates a batch of transactions — relation plus object — for the authenticated caller and answers each with its authorization verdict, in the order they were asked.","description":"Evaluates a batch of transactions — relation plus object — for\nthe authenticated caller and answers each with its authorization verdict, in\nthe order they were asked. It is the read a UI uses to decide which controls\nto show.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/o11y.O11yTransaction"},"type":"array"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yCheckOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/auto_complete/attribute_values":{"post":{"operationId":"post_o11y_auto_complete_attribute_values","summary":"Reads the attribute-value request from the body rather than off the query string — the spelling the newer builder uses to send its filters alongside the request.","description":"Reads the attribute-value request from the body rather\nthan off the query string — the spelling the newer builder uses to send its\nfilters alongside the request.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.FilterAttributeValueRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yAttributeValuesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/autocomplete/aggregate_attributes":{"get":{"operationId":"get_o11y_autocomplete_aggregate_attributes","summary":"Lists the attributes usable as an aggregate target for the given telemetry and operator — what a filter builder offers after the aggregation is chosen.","description":"Lists the attributes usable as an aggregate target for\nthe given telemetry and operator — what a filter builder offers after the\naggregation is chosen.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the attributes come from — traces, logs,\nmetrics or meter. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the attribute will be used under, e.g.\ncount, avg, sum. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the attributes to those containing it.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many attributes come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yAggregateAttributesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/autocomplete/attribute_keys":{"get":{"operationId":"get_o11y_autocomplete_attribute_keys","summary":"Lists the attribute keys available for filtering the given telemetry, each with its data type and whether it is a materialized column.","description":"Lists the attribute keys available for filtering the given\ntelemetry, each with its data type and whether it is a materialized column.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the keys come from — traces, logs, metrics or\nmeter. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the keys will be used under. The\nruntime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the keys must appear on.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the keys to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many keys come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yAttributeKeysOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/autocomplete/attribute_values":{"get":{"operationId":"get_o11y_autocomplete_attribute_values","summary":"Lists the values one attribute key has taken — string, number and bool values in their own lists — for completing a filter.","description":"Lists the values one attribute key has taken — string,\nnumber and bool values in their own lists — for completing a filter.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the values come from — traces, logs or\nmetrics. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the values will be used under. The\nruntime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the values must appear on.","schema":{"type":"string"}},{"name":"attributeKey","in":"query","required":false,"description":"AttributeKey is the key whose values to list.","schema":{"type":"string"}},{"name":"filterAttributeKeyDataType","in":"query","required":false,"description":"FilterAttributeKeyDataType is the key's data type — string, int64, float64\nor bool. Empty means unspecified.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the values to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the search to one kind of key — tag or resource.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many values come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yAttributeValuesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/channels":{"get":{"operationId":"ListChannels","summary":"Lists the org's notification channels.","description":"Lists the org's notification channels. Viewer gate.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yChannelsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"CreateChannel","summary":"Creates a notification channel, answering with the stored channel.","description":"Creates a notification channel, answering with the stored\nchannel. Admin gate.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.PostableChannel"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yChannelOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/channels/test":{"post":{"operationId":"TestChannel","summary":"Sends a test notification to the posted receiver.","description":"Sends a test notification to the posted receiver. Editor gate.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.alertmanagertypes.Receiver"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/channels/{id}":{"delete":{"operationId":"DeleteChannelByID","summary":"Removes a notification channel, by id.","description":"Removes a notification channel, by id. Admin gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"get":{"operationId":"GetChannelByID","summary":"Returns one notification channel, by id.","description":"Returns one notification channel, by id. Viewer gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yChannelOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"UpdateChannelByID","summary":"Replaces a notification channel's receiver, by id.","description":"Replaces a notification channel's receiver, by id. Admin gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yChannelUpdateIn"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/cloud-integrations/{cloud_provider}/agent-check-in":{"post":{"operationId":"AgentCheckInDeprecated","summary":"Is the deployed agent's check-in on its original hyphenated path, kept for backward compatibility with agents already running.","description":"Is the deployed agent's check-in on its original\nhyphenated path, kept for backward compatibility with agents already\nrunning. Viewer gate — the agent's role is viewer.","tags":["o11y"],"parameters":[{"name":"cloud_provider","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yAgentCheckInIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yAgentCheckInOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/cloud_integrations/{cloud_provider}/accounts":{"get":{"operationId":"ListAccounts","summary":"Lists the cloud-integration accounts connected for the given provider.","description":"Lists the cloud-integration accounts connected for the given\nprovider. Admin gate.","tags":["o11y"],"parameters":[{"name":"cloud_provider","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yAccountsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"CreateAccount","summary":"Connects a new cloud-integration account for the given provider from its posted config and credentials, answering with the account and the artifact the agent deploys to complete the connection.","description":"Connects a new cloud-integration account for the given\nprovider from its posted config and credentials, answering with the account\nand the artifact the agent deploys to complete the connection. Admin gate.","tags":["o11y"],"parameters":[{"name":"cloud_provider","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yCreateAccountIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yCreateAccountOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/cloud_integrations/{cloud_provider}/accounts/check_in":{"post":{"operationId":"AgentCheckIn","summary":"Is the deployed agent's check-in — the path consistent with the account surface, reporting the agent's account and telemetry state so the connection can be tracked.","description":"Is the deployed agent's check-in — the path consistent with the\naccount surface, reporting the agent's account and telemetry state so the\nconnection can be tracked. Viewer gate — the agent's role is viewer.","tags":["o11y"],"parameters":[{"name":"cloud_provider","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yAgentCheckInIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yAgentCheckInOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/cloud_integrations/{cloud_provider}/accounts/{id}":{"delete":{"operationId":"DisconnectAccount","summary":"Tears down a connected account for the given provider, by id.","description":"Tears down a connected account for the given provider, by\nid. Admin gate.","tags":["o11y"],"parameters":[{"name":"cloud_provider","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"get":{"operationId":"GetAccount","summary":"Returns one connected account for the given provider, by id.","description":"Returns one connected account for the given provider, by id. Admin\ngate.","tags":["o11y"],"parameters":[{"name":"cloud_provider","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yAccountOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"UpdateAccount","summary":"Changes a connected account's configuration for the given provider, by id.","description":"Changes a connected account's configuration for the given\nprovider, by id. Admin gate.","tags":["o11y"],"parameters":[{"name":"cloud_provider","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yUpdateAccountIn"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/cloud_integrations/{cloud_provider}/accounts/{id}/services":{"get":{"operationId":"ListAccountServicesMetadata","summary":"Lists the services metadata for one connected account of the given provider, by account id.","description":"Lists the services metadata for one connected\naccount of the given provider, by account id. Admin gate.","tags":["o11y"],"parameters":[{"name":"cloud_provider","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yServicesMetadataOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/cloud_integrations/{cloud_provider}/accounts/{id}/services/{service_id}":{"get":{"operationId":"GetAccountService","summary":"Returns one service and its configuration for a connected account of the given provider, by account id and service id.","description":"Returns one service and its configuration for a connected\naccount of the given provider, by account id and service id. Admin gate.","tags":["o11y"],"parameters":[{"name":"cloud_provider","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"service_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yServiceOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"UpdateService","summary":"Changes a service's configuration for one connected account of the given provider, by account id and service id.","description":"Changes a service's configuration for one connected account of\nthe given provider, by account id and service id. Admin gate.","tags":["o11y"],"parameters":[{"name":"cloud_provider","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"service_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yUpdateServiceIn"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/cloud_integrations/{cloud_provider}/credentials":{"get":{"operationId":"GetConnectionCredentials","summary":"Returns the credentials the connecting agent needs to establish the cloud integration, for the given cloud provider.","description":"Returns the credentials the connecting agent needs\nto establish the cloud integration, for the given cloud provider. Admin gate.","tags":["o11y"],"parameters":[{"name":"cloud_provider","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yCredentialsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/cloud_integrations/{cloud_provider}/services":{"get":{"operationId":"ListServicesMetadata","summary":"Lists the services the given provider can collect from, optionally scoped to one cloud integration.","description":"Lists the services the given provider can collect from,\noptionally scoped to one cloud integration. Admin gate.","tags":["o11y"],"parameters":[{"name":"cloud_provider","in":"path","required":true,"schema":{"type":"string"}},{"name":"cloud_integration_id","in":"query","required":false,"description":"CloudIntegrationID, when set, scopes the listing to one cloud integration.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yServicesMetadataOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/cloud_integrations/{cloud_provider}/services/{service_id}":{"get":{"operationId":"GetService","summary":"Returns one service the given provider can collect from, by service id, optionally scoped to one cloud integration.","description":"Returns one service the given provider can collect from, by\nservice id, optionally scoped to one cloud integration. Admin gate.","tags":["o11y"],"parameters":[{"name":"cloud_provider","in":"path","required":true,"schema":{"type":"string"}},{"name":"service_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cloud_integration_id","in":"query","required":false,"description":"CloudIntegrationID, when set, scopes the service to one cloud integration.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yServiceOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/clusters/attribute_keys":{"get":{"operationId":"get_o11y_clusters_attribute_keys","summary":"Lists the metric attribute keys Kubernetes clusters report, for building cluster filters.","description":"Lists the metric attribute keys Kubernetes clusters\nreport, for building cluster filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the keys must appear on.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the keys to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many keys come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeKeysOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/clusters/attribute_values":{"get":{"operationId":"get_o11y_clusters_attribute_values","summary":"Lists the values one cluster attribute key has taken, for building cluster filters.","description":"Lists the values one cluster attribute key has taken,\nfor building cluster filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the values must appear on.","schema":{"type":"string"}},{"name":"attributeKey","in":"query","required":false,"description":"AttributeKey is the key whose values to list.","schema":{"type":"string"}},{"name":"filterAttributeKeyDataType","in":"query","required":false,"description":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the values to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the search to one kind of key — tag or resource.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many values come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeValuesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/clusters/list":{"post":{"operationId":"post_o11y_clusters_list","summary":"Lists Kubernetes clusters over a time range, each with its CPU and memory usage against allocatable capacity and its attributes; filterable, groupable and paginated.","description":"Lists Kubernetes clusters over a time range, each with its CPU\nand memory usage against allocatable capacity and its attributes;\nfilterable, groupable and paginated.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.ClusterListRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yClusterListOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/countErrors":{"post":{"operationId":"post_o11y_counterrors","summary":"Counts the grouped exceptions in the query window for the caller's org.","description":"Counts the grouped exceptions in the query window for the caller's\norg.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yErrorsCountIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"format":"uint64","type":"integer"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/daemonsets/attribute_keys":{"get":{"operationId":"get_o11y_daemonsets_attribute_keys","summary":"Lists the metric attribute keys Kubernetes daemonsets report, for building daemonset filters.","description":"Lists the metric attribute keys Kubernetes daemonsets\nreport, for building daemonset filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the keys must appear on.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the keys to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many keys come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeKeysOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/daemonsets/attribute_values":{"get":{"operationId":"get_o11y_daemonsets_attribute_values","summary":"Lists the values one daemonset attribute key has taken, for building daemonset filters.","description":"Lists the values one daemonset attribute key has\ntaken, for building daemonset filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the values must appear on.","schema":{"type":"string"}},{"name":"attributeKey","in":"query","required":false,"description":"AttributeKey is the key whose values to list.","schema":{"type":"string"}},{"name":"filterAttributeKeyDataType","in":"query","required":false,"description":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the values to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the search to one kind of key — tag or resource.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many values come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeValuesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/daemonsets/list":{"post":{"operationId":"post_o11y_daemonsets_list","summary":"Lists Kubernetes daemonsets over a time range, each with the CPU and memory its pods used against request and limit, desired and available node counts, restarts and attributes; filterable, groupable and paginated.","description":"Lists Kubernetes daemonsets over a time range, each with the\nCPU and memory its pods used against request and limit, desired and\navailable node counts, restarts and attributes; filterable, groupable and\npaginated.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.DaemonSetListRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDaemonSetListOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/dashboard_views":{"get":{"operationId":"ListDashboardViews","summary":"Returns every saved view in the calling user's org.","description":"Returns every saved view in the calling user's org. Saved\nviews are shared org-wide.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDashboardViewListOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"CreateDashboardView","summary":"Persists the calling user's dashboard-listing state (query, sort, order) as a named, reusable view shared across the org.","description":"Persists the calling user's dashboard-listing state (query,\nsort, order) as a named, reusable view shared across the org.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDashboardViewPostable"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDashboardViewOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/dashboard_views/{id}":{"delete":{"operationId":"DeleteDashboardView","summary":"Removes a saved view.","description":"Removes a saved view. Saved views are shared org-wide.\nDeleting a non-existent view refuses with the runtime's not-found.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource id from the path.","schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"UpdateDashboardView","summary":"Replaces a saved view's name and data.","description":"Replaces a saved view's name and data. Saved views are shared\norg-wide.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the saved view id from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDashboardViewUpdateIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDashboardViewOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/dashboards":{"get":{"operationId":"ListDashboardsV2","summary":"Returns a page of v2-shape dashboards for the org.","description":"Returns a page of v2-shape dashboards for the org. This is the\npure, user-independent list — it carries no pin state; use\ndashboardListForUserV2 for the personalized, pin-aware list. Supports a filter\nDSL (query), sort (updated_at/created_at/name), order (asc/desc), and\noffset-based pagination (limit/offset).\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"query","in":"query","required":false,"description":"Query is the filter DSL over dashboard columns and tags, e.g.\n`name:cpu source:user`. Empty lists everything.","schema":{"type":"string"}},{"name":"sort","in":"query","required":false,"description":"Sort is the sort field: updated_at, created_at or name. Empty sorts by\nupdated_at.","schema":{"type":"string"}},{"name":"order","in":"query","required":false,"description":"Order is the sort direction: asc or desc. Empty orders desc.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many dashboards come back. Zero means the default of 20;\nthe runtime caps it at 200.","schema":{"format":"int64","type":"integer"}},{"name":"offset","in":"query","required":false,"description":"Offset is how many dashboards to skip for pagination.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDashboardListOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"CreateDashboardV2","summary":"Creates a dashboard in the v2 format that follows the Perses spec and answers with the stored dashboard.","description":"Creates a dashboard in the v2 format that follows the Perses\nspec and answers with the stored dashboard.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDashboardPostable"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDashboardOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/dashboards/{id}":{"delete":{"operationId":"DeleteDashboardV2","summary":"Deletes a v2-shape dashboard along with its tag relations.","description":"Deletes a v2-shape dashboard along with its tag relations.\nLocked dashboards are rejected.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource id from the path.","schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"get":{"operationId":"GetDashboardV2","summary":"Returns a v2-shape dashboard.","description":"Returns a v2-shape dashboard.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource id from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDashboardOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"patch":{"operationId":"PatchDashboardV2","summary":"Applies an RFC 6902 JSON Patch to a v2-shape dashboard.","description":"Applies an RFC 6902 JSON Patch to a v2-shape dashboard. The\npatch is applied against the postable view (metadata, spec, tags), so individual\npanels, queries, variables, layouts or tags can be updated without re-sending the\nrest. Apply is lenient — remove on a missing path is a no-op and add creates any\nmissing parent objects — and the result is still validated. Locked dashboards are\nrejected. The request body is the bare JSON Patch operations array.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the dashboard id from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDashboardPatchIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDashboardOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"UpdateDashboardV2","summary":"Updates a v2-shape dashboard's metadata, spec and tag set.","description":"Updates a v2-shape dashboard's metadata, spec and tag set.\nThe name is immutable and locked dashboards are rejected.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the dashboard id from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDashboardUpdateIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDashboardOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/dashboards/{id}/clone":{"post":{"operationId":"CloneDashboardV2","summary":"Clones an existing v2-shape dashboard.","description":"Clones an existing v2-shape dashboard. User and integration\ndashboards can be cloned; system dashboards are rejected. The clone keeps the\nsource's display name, panels and tags, but gets a freshly generated unique\ninternal name and is always created as an unlocked user dashboard owned by the\ncaller.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource id from the path.","schema":{"type":"string"}}],"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDashboardOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/dashboards/{id}/lock":{"delete":{"operationId":"UnlockDashboardV2","summary":"Unlocks a v2-shape dashboard.","description":"Unlocks a v2-shape dashboard. Only the dashboard's creator or\nan org admin may lock or unlock.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource id from the path.","schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"LockDashboardV2","summary":"Locks a v2-shape dashboard.","description":"Locks a v2-shape dashboard. Only the dashboard's creator or an\norg admin may lock or unlock.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource id from the path.","schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/dashboards/{id}/public":{"delete":{"operationId":"DeletePublicDashboard","summary":"Deletes the public-sharing config and disables public sharing of a dashboard.","description":"Deletes the public-sharing config and disables public\nsharing of a dashboard.\n\nCallers need the admin role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource id from the path.","schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"get":{"operationId":"GetPublicDashboard","summary":"Returns the public-sharing config for a dashboard.","description":"Returns the public-sharing config for a dashboard.\n\nCallers need the admin role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource id from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yPublicDashboardOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"CreatePublicDashboard","summary":"Creates the public-sharing config for a dashboard and enables public sharing, answering with the new share's id.","description":"Creates the public-sharing config for a dashboard and\nenables public sharing, answering with the new share's id.\n\nCallers need the admin role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the dashboard id from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yPublicDashboardWriteIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yIdentifiableOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"UpdatePublicDashboard","summary":"Updates the public-sharing config for a dashboard.","description":"Updates the public-sharing config for a dashboard.\n\nCallers need the admin role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the dashboard id from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yPublicDashboardWriteIn"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/dependency_graph":{"post":{"operationId":"post_o11y_dependency_graph","summary":"Returns the service dependency graph over the requested window: every parent→child edge observed, with call and error rates and latency percentiles per edge.","description":"Returns the service dependency graph over the requested\nwindow: every parent→child edge observed, with call and error rates and\nlatency percentiles per edge.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDependencyGraphIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/o11y.O11yDependency"},"type":"array"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/deployments/attribute_keys":{"get":{"operationId":"get_o11y_deployments_attribute_keys","summary":"Lists the metric attribute keys Kubernetes deployments report, for building deployment filters.","description":"Lists the metric attribute keys Kubernetes\ndeployments report, for building deployment filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the keys must appear on.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the keys to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many keys come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeKeysOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/deployments/attribute_values":{"get":{"operationId":"get_o11y_deployments_attribute_values","summary":"Lists the values one deployment attribute key has taken, for building deployment filters.","description":"Lists the values one deployment attribute key has\ntaken, for building deployment filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the values must appear on.","schema":{"type":"string"}},{"name":"attributeKey","in":"query","required":false,"description":"AttributeKey is the key whose values to list.","schema":{"type":"string"}},{"name":"filterAttributeKeyDataType","in":"query","required":false,"description":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the values to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the search to one kind of key — tag or resource.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many values come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeValuesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/deployments/list":{"post":{"operationId":"post_o11y_deployments_list","summary":"Lists Kubernetes deployments over a time range, each with the CPU and memory its pods used against request and limit, desired and available replica counts, restarts and attributes; filterable, groupable and paginated.","description":"Lists Kubernetes deployments over a time range, each with the\nCPU and memory its pods used against request and limit, desired and\navailable replica counts, restarts and attributes; filterable, groupable and\npaginated.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.DeploymentListRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDeploymentListOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/disks":{"get":{"operationId":"get_o11y_disks","summary":"Lists the storage disks the datastore reports, with their names and types.","description":"Lists the storage disks the datastore reports, with their names and\ntypes.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/o11y.O11yDisk"},"type":"array"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/downtime_schedules":{"get":{"operationId":"ListDowntimeSchedules","summary":"Lists all planned maintenance windows, optionally narrowed to the active ones or the recurring ones.","description":"Lists all planned maintenance windows, optionally\nnarrowed to the active ones or the recurring ones. Viewer gate.","tags":["o11y"],"parameters":[{"name":"active","in":"query","required":false,"description":"Active, when \"true\" or \"false\", keeps only the active or inactive windows.\nAbsent lists all.","schema":{"type":"string"}},{"name":"recurring","in":"query","required":false,"description":"Recurring, when \"true\" or \"false\", keeps only the recurring or one-off\nwindows. Absent lists all.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDowntimeSchedulesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"CreateDowntimeSchedule","summary":"Creates a planned maintenance window, answering with the stored schedule.","description":"Creates a planned maintenance window, answering with\nthe stored schedule. Editor gate.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.PostablePlannedMaintenance"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDowntimeScheduleOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/downtime_schedules/{id}":{"delete":{"operationId":"DeleteDowntimeScheduleByID","summary":"Removes a planned maintenance window, by id.","description":"Removes a planned maintenance window, by id. Editor gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"get":{"operationId":"GetDowntimeScheduleByID","summary":"Returns one planned maintenance window, by id.","description":"Returns one planned maintenance window, by id. Viewer gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDowntimeScheduleOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"UpdateDowntimeScheduleByID","summary":"Replaces a planned maintenance window, by id.","description":"Replaces a planned maintenance window, by id. Editor gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDowntimeUpdateIn"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/errorFromErrorID":{"get":{"operationId":"get_o11y_errorfromerrorid","summary":"Returns one exception instance and the span it happened on, by its error id within a group at a timestamp.","description":"Returns one exception instance and the span it happened on,\nby its error id within a group at a timestamp.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"timestamp","in":"query","required":true,"description":"Timestamp is the instance's time as a nanosecond epoch spelled as a\nstring. Required.","schema":{"type":"string"}},{"name":"groupID","in":"query","required":true,"description":"GroupID is the exception group the instance belongs to. Required.","schema":{"type":"string"}},{"name":"errorID","in":"query","required":false,"description":"ErrorID is the exception instance id. Required by errorFromErrorID and\nnextPrevErrorIDs; unused by errorFromGroupID.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yErrorWithSpan"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/errorFromGroupID":{"get":{"operationId":"get_o11y_errorfromgroupid","summary":"Returns the representative exception instance of a group at a timestamp, and the span it happened on.","description":"Returns the representative exception instance of a group at a\ntimestamp, and the span it happened on.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"timestamp","in":"query","required":true,"description":"Timestamp is the instance's time as a nanosecond epoch spelled as a\nstring. Required.","schema":{"type":"string"}},{"name":"groupID","in":"query","required":true,"description":"GroupID is the exception group the instance belongs to. Required.","schema":{"type":"string"}},{"name":"errorID","in":"query","required":false,"description":"ErrorID is the exception instance id. Required by errorFromErrorID and\nnextPrevErrorIDs; unused by errorFromGroupID.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yErrorWithSpan"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/errortracking/issues":{"get":{"operationId":"get_o11y_errortracking_issues","summary":"Lists the caller's org's grouped error issues (by fingerprint) with status, level, counts and first/last-seen.","description":"Lists the caller's org's grouped error issues (by\nfingerprint) with status, level, counts and first/last-seen.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"status","in":"query","required":false,"description":"Status narrows to one lifecycle state: unresolved, resolved or ignored.","schema":{"type":"string"}},{"name":"level","in":"query","required":false,"description":"Level narrows to one severity, e.g. error, warning, info.","schema":{"type":"string"}},{"name":"environment","in":"query","required":false,"description":"Environment narrows to one deployment environment.","schema":{"type":"string"}},{"name":"serviceName","in":"query","required":false,"description":"ServiceName narrows to one reporting service.","schema":{"type":"string"}},{"name":"query","in":"query","required":false,"description":"Query narrows to issues whose text contains it.","schema":{"type":"string"}},{"name":"sort","in":"query","required":false,"description":"Sort orders the page, e.g. lastSeen, firstSeen, count.","schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"description":"Offset is how many issues to skip. Zero starts at the first.","schema":{"format":"int64","type":"integer"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many issues come back. Zero means the default.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yErrorIssuesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/errortracking/issues/{id}":{"get":{"operationId":"get_o11y_errortracking_issues_by_id","summary":"Returns one grouped issue with its latest occurrence sample.","description":"Returns one grouped issue with its latest occurrence sample.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the issue id.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yErrorGettableIssueOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"post_o11y_errortracking_issues_by_id","summary":"Changes an issue's lifecycle — resolve, ignore, reopen or assign — and returns the updated issue.","description":"Changes an issue's lifecycle — resolve, ignore, reopen or\nassign — and returns the updated issue. Fields left unset are left unchanged.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the issue id.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yErrorUpdateIssueIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yErrorIssueOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/event":{"post":{"operationId":"post_o11y_event","summary":"Records one product-analytics event for the signed-in user — a track event with a name and free-form attributes.","description":"Records one product-analytics event for the signed-in user — a track\nevent with a name and free-form attributes.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yEventIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yMessage"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/explorer/views":{"get":{"operationId":"get_o11y_explorer_views","summary":"Lists the caller's org's saved explorer views, optionally narrowed to one source page, name or category.","description":"Lists the caller's org's saved explorer views, optionally\nnarrowed to one source page, name or category.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"sourcePage","in":"query","required":false,"description":"SourcePage narrows the views to one source page, e.g. traces, logs.","schema":{"type":"string"}},{"name":"name","in":"query","required":false,"description":"Name narrows the views to one name.","schema":{"type":"string"}},{"name":"category","in":"query","required":false,"description":"Category narrows the views to one category.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySavedViewListOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"post_o11y_explorer_views","summary":"Saves a new explorer view for the caller's org and returns its id.","description":"Saves a new explorer view for the caller's org and returns its\nid.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.SavedView"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySavedViewCreateOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/explorer/views/{viewId}":{"delete":{"operationId":"delete_o11y_explorer_views_by_viewid","summary":"Deletes one saved explorer view by id.","description":"Deletes one saved explorer view by id.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"viewId","in":"path","required":true,"description":"ViewID is the view's id.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySavedViewDeleteOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"get":{"operationId":"get_o11y_explorer_views_by_viewid","summary":"Returns one saved explorer view by id.","description":"Returns one saved explorer view by id.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"viewId","in":"path","required":true,"description":"ViewID is the view's id.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySavedViewOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"put_o11y_explorer_views_by_viewid","summary":"Replaces one saved explorer view by id with the given view and echoes it back.","description":"Replaces one saved explorer view by id with the given view and\nechoes it back.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"viewId","in":"path","required":true,"description":"ViewID is the id of the view to replace, taken from the URL.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySavedViewUpdateIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySavedViewOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/export_raw_data":{"post":{"operationId":"post_o11y_export_raw_data","summary":"Export raw telemetry rows as a file","description":"Runs a query and returns its rows as a downloadable CSV or JSONL attachment, chunked, with a trailer that says whether the export completed — so a truncated download is detectable rather than silently short.\n\nThe answer is a file, not a value, which is why it is not a typed operation: the body is neither JSON nor bounded. Use the query operations when you want rows in a response.\n\nA validated, org-scoped principal is required and the export carries that principal's own tenant only.","tags":["o11y"],"x-app":"o11y","x-public":true}},"/v1/o11y/features":{"get":{"operationId":"get_o11y_features","summary":"Returns the supported feature flags and their resolved values for the caller's org.","description":"Returns the supported feature flags and their resolved values for\nthe caller's org.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFeaturesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/fields/keys":{"get":{"operationId":"get_o11y_fields_keys","summary":"Returns the telemetry field keys matching the selector — the signal's fields grouped by name, and whether the catalog is complete.","description":"Returns the telemetry field keys matching the selector — the\nsignal's fields grouped by name, and whether the catalog is complete.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"signal","in":"query","required":false,"description":"Signal is the telemetry to read the fields of — traces, logs or metrics.","schema":{"type":"string"}},{"name":"source","in":"query","required":false,"description":"Source narrows the fields to one source within the signal.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many keys come back.","schema":{"format":"int64","type":"integer"}},{"name":"startUnixMilli","in":"query","required":false,"description":"StartUnixMilli is the window start as a unix millisecond epoch. Zero reads\nas unset.","schema":{"format":"int64","type":"integer"}},{"name":"endUnixMilli","in":"query","required":false,"description":"EndUnixMilli is the window end as a unix millisecond epoch. Zero reads as\nunset.","schema":{"format":"int64","type":"integer"}},{"name":"fieldContext","in":"query","required":false,"description":"FieldContext narrows the keys to one context — resource, scope, attribute,\nspan, log or metric.","schema":{"type":"string"}},{"name":"fieldDataType","in":"query","required":false,"description":"FieldDataType narrows the keys to one data type.","schema":{"type":"string"}},{"name":"metricName","in":"query","required":false,"description":"MetricName narrows the keys to those on one metric.","schema":{"type":"string"}},{"name":"metricNamespace","in":"query","required":false,"description":"MetricNamespace narrows the keys to one metric namespace.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the keys to those containing it.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFieldKeysOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/fields/values":{"get":{"operationId":"get_o11y_fields_values","summary":"Returns the values one telemetry field has taken — string, bool, number and related values — and whether the value list is complete.","description":"Returns the values one telemetry field has taken — string, bool,\nnumber and related values — and whether the value list is complete.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"signal","in":"query","required":false,"description":"Signal is the telemetry to read the field of — traces, logs or metrics.","schema":{"type":"string"}},{"name":"source","in":"query","required":false,"description":"Source narrows the field to one source within the signal.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many values come back.","schema":{"format":"int64","type":"integer"}},{"name":"startUnixMilli","in":"query","required":false,"description":"StartUnixMilli is the window start as a unix millisecond epoch. Zero reads\nas unset.","schema":{"format":"int64","type":"integer"}},{"name":"endUnixMilli","in":"query","required":false,"description":"EndUnixMilli is the window end as a unix millisecond epoch. Zero reads as\nunset.","schema":{"format":"int64","type":"integer"}},{"name":"fieldContext","in":"query","required":false,"description":"FieldContext narrows the field to one context.","schema":{"type":"string"}},{"name":"fieldDataType","in":"query","required":false,"description":"FieldDataType narrows the field to one data type.","schema":{"type":"string"}},{"name":"metricName","in":"query","required":false,"description":"MetricName narrows the field to one metric.","schema":{"type":"string"}},{"name":"metricNamespace","in":"query","required":false,"description":"MetricNamespace narrows the field to one metric namespace.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the values to those containing it.","schema":{"type":"string"}},{"name":"name","in":"query","required":false,"description":"Name is the field whose values to read.","schema":{"type":"string"}},{"name":"existingQuery","in":"query","required":false,"description":"ExistingQuery is the query the field appears in, so related values can be\nsuggested for it.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFieldValuesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/filter_suggestions":{"get":{"operationId":"get_o11y_filter_suggestions","summary":"Suggests attribute keys and example filter queries for the query builder, seeded by what the org's own telemetry carries.","description":"Suggests attribute keys and example filter queries for the\nquery builder, seeded by what the org's own telemetry carries. Only the logs\ndata source is supported today.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":true,"description":"DataSource is the signal suggestions are drawn from; only logs is\nsupported today. Required.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows attribute suggestions to keys containing it.","schema":{"type":"string"}},{"name":"existingFilter","in":"query","required":false,"description":"ExistingFilter is the current filter set, JSON base64url-encoded, so\nexample queries build on it rather than repeat it.","schema":{"type":"string"}},{"name":"attributesLimit","in":"query","required":false,"description":"AttributesLimit caps how many attribute keys come back.","schema":{"format":"int64","type":"integer"}},{"name":"examplesLimit","in":"query","required":false,"description":"ExamplesLimit caps how many example queries come back.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFilterSuggestionsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/gateway/ingestion_keys":{"get":{"operationId":"GetIngestionKeys","summary":"Lists the workspace's ingestion keys, paginated.","description":"Lists the workspace's ingestion keys, paginated. Editor\ngate.","tags":["o11y"],"parameters":[{"name":"page","in":"query","required":false,"description":"Page is the 1-based page number.","schema":{"format":"int64","type":"integer"}},{"name":"per_page","in":"query","required":false,"description":"PerPage is the page size.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yIngestionKeysOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"CreateIngestionKey","summary":"Mints an ingestion key for the workspace, answering with the created key.","description":"Mints an ingestion key for the workspace, answering with\nthe created key. Editor gate.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.PostableIngestionKey"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yCreatedIngestionKeyOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/gateway/ingestion_keys/limits/{limitId}":{"delete":{"operationId":"DeleteIngestionKeyLimit","summary":"Removes an ingestion key limit, by limit id.","description":"Removes an ingestion key limit, by limit id. Editor\ngate.","tags":["o11y"],"parameters":[{"name":"limitId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"patch":{"operationId":"UpdateIngestionKeyLimit","summary":"Changes an ingestion key limit, by limit id.","description":"Changes an ingestion key limit, by limit id. Editor\ngate.","tags":["o11y"],"parameters":[{"name":"limitId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yUpdateLimitIn"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/gateway/ingestion_keys/search":{"get":{"operationId":"SearchIngestionKeys","summary":"Lists the workspace's ingestion keys whose name matches the search, paginated.","description":"Lists the workspace's ingestion keys whose name matches\nthe search, paginated. Editor gate.","tags":["o11y"],"parameters":[{"name":"name","in":"query","required":false,"description":"Name is the substring to match ingestion-key names against.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Page is the 1-based page number.","schema":{"format":"int64","type":"integer"}},{"name":"per_page","in":"query","required":false,"description":"PerPage is the page size.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yIngestionKeysOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/gateway/ingestion_keys/{keyId}":{"delete":{"operationId":"DeleteIngestionKey","summary":"Removes an ingestion key, by id.","description":"Removes an ingestion key, by id. Editor gate.","tags":["o11y"],"parameters":[{"name":"keyId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"patch":{"operationId":"UpdateIngestionKey","summary":"Changes an ingestion key, by id.","description":"Changes an ingestion key, by id. Editor gate.","tags":["o11y"],"parameters":[{"name":"keyId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yUpdateIngestionKeyIn"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/gateway/ingestion_keys/{keyId}/limits":{"post":{"operationId":"CreateIngestionKeyLimit","summary":"Sets a signal limit on an ingestion key, by key id, answering with the created limit.","description":"Sets a signal limit on an ingestion key, by key id,\nanswering with the created limit. Editor gate.","tags":["o11y"],"parameters":[{"name":"keyId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yCreateLimitIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yCreatedLimitOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/global/config":{"get":{"operationId":"get_o11y_global_config","summary":"Returns the deployment's global configuration: its public endpoints and which identity providers are enabled.","description":"Returns the deployment's global configuration: its public\nendpoints and which identity providers are enabled. Open by design — the\nsign-in page reads it before anyone is signed in.\n\nOpen by design; the runtime's own gate is OpenAccess.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yGlobalConfigOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/health":{"get":{"operationId":"get_o11y_health","summary":"Reports service health.","description":"Reports service health. With live set, the datastore connection is\nchecked too and an unhealthy store refuses with 503.\n\nOpen by design; the runtime's own gate is OpenAccess.","tags":["o11y"],"parameters":[{"name":"live","in":"query","required":false,"description":"Live also checks the datastore connection; an unreachable store refuses\nwith 503.","schema":{"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yHealthOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/healthz":{"get":{"operationId":"get_o11y_healthz","summary":"Health of the observability runtime's services","description":"Reports whether every service in the runtime's registry is healthy, and names them grouped by state — so a failure says WHICH component is down, not merely that something is. An unhealthy registry answers 503, not a 200 with a false flag inside, so a plain status check cannot read a sick runtime as well.\n\nUNAUTHENTICATED by design, like the other two probes: it carries no tenant data and is reached by k8s and by external checks that hold no principal.","tags":["o11y"],"x-app":"o11y","x-public":true}},"/v1/o11y/hosts/attribute_keys":{"get":{"operationId":"get_o11y_hosts_attribute_keys","summary":"Lists the metric attribute keys hosts report, for building host filters — each with its data type and whether it is a materialized column.","description":"Lists the metric attribute keys hosts report, for building\nhost filters — each with its data type and whether it is a materialized\ncolumn.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the keys must appear on.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the keys to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many keys come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeKeysOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/hosts/attribute_values":{"get":{"operationId":"get_o11y_hosts_attribute_values","summary":"Lists the values one host attribute key has taken, for building host filters — string, number and bool values in their own lists.","description":"Lists the values one host attribute key has taken, for\nbuilding host filters — string, number and bool values in their own lists.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the values must appear on.","schema":{"type":"string"}},{"name":"attributeKey","in":"query","required":false,"description":"AttributeKey is the key whose values to list.","schema":{"type":"string"}},{"name":"filterAttributeKeyDataType","in":"query","required":false,"description":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the values to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the search to one kind of key — tag or resource.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many values come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeValuesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/hosts/list":{"post":{"operationId":"post_o11y_hosts_list","summary":"Lists monitored hosts over a time range, each with its CPU, memory, I/O wait and 15-minute load, whether it is actively reporting, its OS and its attributes; filterable, groupable and paginated.","description":"Lists monitored hosts over a time range, each with its CPU,\nmemory, I/O wait and 15-minute load, whether it is actively reporting, its\nOS and its attributes; filterable, groupable and paginated. The answer also\nsays whether any host metrics were received at all and which clusters and\nnodes sent them, so an empty page is distinguishable from a fleet that never\nreported.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.HostListRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yHostListOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/infra_monitoring/checks":{"get":{"operationId":"get_o11y_infra_monitoring_checks","summary":"Reports whether the metrics and attributes an infra-monitoring section needs are being received — for each collector receiver or processor involved, what is present and what is missing, with a user-facing message and a docs link per missing piece.","description":"Reports whether the metrics and attributes an infra-monitoring\nsection needs are being received — for each collector receiver or processor\ninvolved, what is present and what is missing, with a user-facing message\nand a docs link per missing piece. Ready is true only when nothing is\nmissing.","tags":["o11y"],"parameters":[{"name":"type","in":"query","required":true,"description":"Type is the section to check — hosts, processes, pods, nodes,\ndeployments, daemonsets, statefulsets, jobs, namespaces, clusters or\nvolumes. Required.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraChecksOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/infra_monitoring/clusters":{"post":{"operationId":"post_o11y_infra_monitoring_clusters","summary":"Lists Kubernetes clusters with CPU and memory usage against allocatable capacity summed over their nodes, plus per-group node readiness and pod phase counts.","description":"Lists Kubernetes clusters with CPU and memory usage against\nallocatable capacity summed over their nodes, plus per-group node readiness\nand pod phase counts. Rows answer as 'list' under the default\nk8s.cluster.name grouping or 'grouped_list' under a custom groupBy; a metric\nwith no data in the window answers -1. Filterable by expression, orderable\nby usage or allocatable, paginated by offset and limit.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.PostableClusters"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraClustersOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/infra_monitoring/daemonsets":{"post":{"operationId":"post_o11y_infra_monitoring_daemonsets","summary":"Lists Kubernetes daemonsets with the CPU and memory their pods used against request and limit, the latest desired and current scheduled NODE counts (node counts, not pod counts), and per-group pod phase counts.","description":"Lists Kubernetes daemonsets with the CPU and memory their\npods used against request and limit, the latest desired and current\nscheduled NODE counts (node counts, not pod counts), and per-group pod phase\ncounts. Rows answer as 'list' under the default k8s.daemonset.name grouping\nor 'grouped_list' under a custom groupBy; a metric with no data in the\nwindow answers -1. Filterable by expression, orderable by the pod metrics or\nthe node counts, paginated by offset and limit.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.PostableDaemonSets"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraDaemonSetsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/infra_monitoring/deployments":{"post":{"operationId":"post_o11y_infra_monitoring_deployments","summary":"Lists Kubernetes deployments with the CPU and memory their pods used against request and limit, the latest desired and available replica counts, and per-group pod phase counts.","description":"Lists Kubernetes deployments with the CPU and memory their\npods used against request and limit, the latest desired and available\nreplica counts, and per-group pod phase counts. Rows answer as 'list' under\nthe default k8s.deployment.name grouping or 'grouped_list' under a custom\ngroupBy; a metric with no data in the window answers -1. Filterable by\nexpression, orderable by the pod metrics or the replica counts, paginated by\noffset and limit.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.PostableDeployments"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraDeploymentsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/infra_monitoring/hosts":{"post":{"operationId":"post_o11y_infra_monitoring_hosts","summary":"Lists hosts with key infrastructure metrics — CPU, memory, I/O wait and disk usage percentages and 15-minute load — plus an active/inactive status from whether the host reported in the last ten minutes.","description":"Lists hosts with key infrastructure metrics — CPU, memory, I/O\nwait and disk usage percentages and 15-minute load — plus an\nactive/inactive status from whether the host reported in the last ten\nminutes. Rows answer as 'list' under the default host.name grouping or\n'grouped_list' under a custom groupBy; a metric with no data in the window\nanswers -1. Filterable by expression and by status, orderable by any of the\nfive metrics, paginated by offset and limit.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.PostableHosts"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraHostsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/infra_monitoring/jobs":{"post":{"operationId":"post_o11y_infra_monitoring_jobs","summary":"Lists Kubernetes jobs with the CPU and memory their pods used against request and limit, the latest desired-successful, active, failed and successful pod counters, and per-group pod phase counts — the phase counts are current state while the counters are cumulative over the job's life.","description":"Lists Kubernetes jobs with the CPU and memory their pods used\nagainst request and limit, the latest desired-successful, active, failed and\nsuccessful pod counters, and per-group pod phase counts — the phase counts\nare current state while the counters are cumulative over the job's life.\nRows answer as 'list' under the default k8s.job.name grouping or\n'grouped_list' under a custom groupBy; a metric with no data in the window\nanswers -1. Filterable by expression, orderable by the pod metrics or the\njob counters, paginated by offset and limit.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.PostableJobs"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraJobsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/infra_monitoring/namespaces":{"post":{"operationId":"post_o11y_infra_monitoring_namespaces","summary":"Lists Kubernetes namespaces with the CPU and memory their pods used and per-group pod phase counts.","description":"Lists Kubernetes namespaces with the CPU and memory their\npods used and per-group pod phase counts. Rows answer as 'list' under the\ndefault k8s.namespace.name grouping or 'grouped_list' under a custom\ngroupBy, aggregating pods either way; a metric with no data in the window\nanswers -1. Filterable by expression, orderable by cpu or memory, paginated\nby offset and limit.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.PostableNamespaces"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraNamespacesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/infra_monitoring/nodes":{"post":{"operationId":"post_o11y_infra_monitoring_nodes","summary":"Lists Kubernetes nodes with CPU and memory usage against allocatable capacity, per-group readiness counts and per-group phase counts for the pods scheduled on them.","description":"Lists Kubernetes nodes with CPU and memory usage against\nallocatable capacity, per-group readiness counts and per-group phase counts\nfor the pods scheduled on them. Rows answer as 'list' under the default\nk8s.node.name grouping (each row one node with its readiness condition) or\n'grouped_list' under a custom groupBy; a metric with no data in the window\nanswers -1. Filterable by expression, orderable by usage or allocatable,\npaginated by offset and limit.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.PostableNodes"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraNodesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/infra_monitoring/pods":{"post":{"operationId":"post_o11y_infra_monitoring_pods","summary":"Lists Kubernetes pods with CPU and memory usage against request and limit, the pod's phase and its age, plus its namespace, node, owning workload and cluster attributes.","description":"Lists Kubernetes pods with CPU and memory usage against request\nand limit, the pod's phase and its age, plus its namespace, node, owning\nworkload and cluster attributes. Rows answer as 'list' under the default\nk8s.pod.uid grouping (each row one pod) or 'grouped_list' under a custom\ngroupBy (each row aggregating its pods with per-phase counts); a metric with\nno data in the window answers -1. Filterable by expression, orderable by the\nsix pod metrics, paginated by offset and limit.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.PostablePods"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraPodsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/infra_monitoring/pvcs":{"post":{"operationId":"post_o11y_infra_monitoring_pvcs","summary":"Lists Kubernetes persistent volume claims with available, capacity and used bytes and inode counts, plus the claim's pod, namespace, node, statefulset and cluster attributes.","description":"Lists Kubernetes persistent volume claims with available,\ncapacity and used bytes and inode counts, plus the claim's pod, namespace,\nnode, statefulset and cluster attributes. Rows answer as 'list' under the\ndefault k8s.persistentvolumeclaim.name grouping or 'grouped_list' under a\ncustom groupBy; a metric with no data in the window answers -1. Filterable\nby expression, orderable by the six volume metrics, paginated by offset and\nlimit.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.PostableVolumes"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraVolumesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/infra_monitoring/statefulsets":{"post":{"operationId":"post_o11y_infra_monitoring_statefulsets","summary":"Lists Kubernetes statefulsets with the CPU and memory their pods used against request and limit, the latest desired and current replica counts, and per-group pod phase counts.","description":"Lists Kubernetes statefulsets with the CPU and memory\ntheir pods used against request and limit, the latest desired and current\nreplica counts, and per-group pod phase counts. Rows answer as 'list' under\nthe default k8s.statefulset.name grouping or 'grouped_list' under a custom\ngroupBy; a metric with no data in the window answers -1. Filterable by\nexpression, orderable by the pod metrics or the replica counts, paginated by\noffset and limit.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.PostableStatefulSets"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraStatefulSetsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/infra_onboarding/k8s/status":{"get":{"operationId":"get_o11y_infra_onboarding_k8s_status","summary":"Reports how far Kubernetes infra onboarding has progressed: which metric families have arrived and, per pod, which required metadata labels are present.","description":"Reports how far Kubernetes infra onboarding has progressed:\nwhich metric families have arrived and, per pod, which required metadata\nlabels are present.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yOnboardingOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/integrations":{"get":{"operationId":"ListIntegrations","summary":"Lists the available integrations and whether each is installed in the caller's org, optionally narrowed to installed or not-installed.","description":"Lists the available integrations and whether each is\ninstalled in the caller's org, optionally narrowed to installed or\nnot-installed. Viewer gate.","tags":["o11y"],"parameters":[{"name":"is_installed","in":"query","required":false,"description":"IsInstalled, when \"true\" or \"false\", keeps only integrations in that\ninstalled state; empty lists them all.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yIntegrationsListOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/integrations/install":{"post":{"operationId":"InstallIntegration","summary":"Installs an integration into the caller's org from its id and configuration, answering with the installed catalog item.","description":"Installs an integration into the caller's org from its id\nand configuration, answering with the installed catalog item. Viewer gate.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.InstallIntegrationRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInstallOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/integrations/uninstall":{"post":{"operationId":"UninstallIntegration","summary":"Removes an integration from the caller's org by id.","description":"Removes an integration from the caller's org by id.\nViewer gate.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.UninstallIntegrationRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yIntegrationAck"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/integrations/{integrationId}":{"get":{"operationId":"GetIntegration","summary":"Returns one integration's full detail — its overview, configuration steps, collected data and assets — together with its installation record when the org has installed it.","description":"Returns one integration's full detail — its overview,\nconfiguration steps, collected data and assets — together with its\ninstallation record when the org has installed it. Viewer gate.","tags":["o11y"],"parameters":[{"name":"integrationId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yIntegrationOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/integrations/{integrationId}/connection_status":{"get":{"operationId":"GetIntegrationConnectionStatus","summary":"Reports whether the integration's logs and metrics have been received over the lookback window, so the console can show a live connection state.","description":"Reports whether the integration's logs and\nmetrics have been received over the lookback window, so the console can show\na live connection state. An integration that is not installed answers with an\nempty status rather than an error. Viewer gate.","tags":["o11y"],"parameters":[{"name":"integrationId","in":"path","required":true,"schema":{"type":"string"}},{"name":"lookback_seconds","in":"query","required":false,"description":"LookbackSeconds is how far back to look for received telemetry, in\nseconds.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yConnectionStatusOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/jobs/attribute_keys":{"get":{"operationId":"get_o11y_jobs_attribute_keys","summary":"Lists the metric attribute keys Kubernetes jobs report, for building job filters.","description":"Lists the metric attribute keys Kubernetes jobs report, for\nbuilding job filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the keys must appear on.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the keys to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many keys come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeKeysOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/jobs/attribute_values":{"get":{"operationId":"get_o11y_jobs_attribute_values","summary":"Lists the values one job attribute key has taken, for building job filters.","description":"Lists the values one job attribute key has taken, for\nbuilding job filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the values must appear on.","schema":{"type":"string"}},{"name":"attributeKey","in":"query","required":false,"description":"AttributeKey is the key whose values to list.","schema":{"type":"string"}},{"name":"filterAttributeKeyDataType","in":"query","required":false,"description":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the values to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the search to one kind of key — tag or resource.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many values come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeValuesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/jobs/list":{"post":{"operationId":"post_o11y_jobs_list","summary":"Lists Kubernetes jobs over a time range, each with the CPU and memory its pods used against request and limit, desired-successful, active, failed and successful pod counts, restarts and attributes; filterable, groupable and paginated.","description":"Lists Kubernetes jobs over a time range, each with the CPU and\nmemory its pods used against request and limit, desired-successful, active,\nfailed and successful pod counts, restarts and attributes; filterable,\ngroupable and paginated.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.JobListRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yJobListOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/licenses":{"get":{"operationId":"get_o11y_licenses","summary":"Lists the org's licenses.","description":"Lists the org's licenses. This build has no enterprise edition, so\nthe list is intentionally empty.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLicensesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/licenses/active":{"get":{"operationId":"get_o11y_licenses_active","summary":"Activates the enterprise license.","description":"Activates the enterprise license. This build has no\nenterprise edition, so the licensing provider refuses it as unsupported.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLicenseActiveOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/listErrors":{"post":{"operationId":"post_o11y_listerrors","summary":"Lists the grouped exceptions in the query window — each an exception type with its message, count, service and first/last-seen — for the caller's org.","description":"Lists the grouped exceptions in the query window — each an\nexception type with its message, count, service and first/last-seen — for the\ncaller's org.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yErrorsListIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/o11y.O11yListError"},"type":"array"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/livez":{"get":{"operationId":"get_o11y_livez","summary":"Liveness of the observability process","description":"Answers 200 unconditionally while the process is running, and asserts NOTHING about the telemetry stores behind it. That is what makes it a liveness probe: a container that answers this is worth leaving alive, and restarting on a store outage would only remove the thing reporting the outage.\n\nUNAUTHENTICATED by design, and one of exactly three /v1/o11y paths that are. It carries no tenant data, and gating it would break the k8s probes and the external health checks without protecting anything. Use the health probe, not this one, to ask whether the runtime can actually serve.","tags":["o11y"],"x-app":"o11y","x-public":true}},"/v1/o11y/llm/annotation":{"get":{"operationId":"ListLLMAnnotations","summary":"Lists human annotations on traces and observations, optionally scoped to one review queue.","description":"Lists human annotations on traces and observations,\noptionally scoped to one review queue.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"traceId","in":"query","required":false,"description":"TraceID narrows to annotations on one trace.","schema":{"type":"string"}},{"name":"queue","in":"query","required":false,"description":"Queue narrows to one review queue.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Status narrows to one review status, e.g. PENDING.","schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"description":"Offset is how many rows to skip, for paging.","schema":{"format":"int64","type":"integer"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many rows come back.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLLMAnnotationsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"CreateLLMAnnotation","summary":"Adds a human annotation to a trace or observation, optionally in a review queue.","description":"Adds a human annotation to a trace or observation,\noptionally in a review queue.\n\nCallers need the editor role; the runtime's own gate enforces it, and it\nvalidates the payload and stamps the annotation's author and org.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLLMIngestAnnotation"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLLMAnnotationOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/llm/observations":{"get":{"operationId":"ListLLMObservations","summary":"Lists gen_ai spans as LLM observations — each an LLM call with its model, token counts, cost and latency projected from gen_ai.* attributes, newest first, over the query window.","description":"Lists gen_ai spans as LLM observations — each an LLM call with\nits model, token counts, cost and latency projected from gen_ai.* attributes,\nnewest first, over the query window.\n\nCallers need the viewer role; the runtime's own gate enforces it, and scopes\nthe read to the caller's validated tenant.","tags":["o11y"],"parameters":[{"name":"start","in":"query","required":false,"description":"Start is the start of the window as a unix-millisecond epoch. Zero means\n24h before the end.","schema":{"format":"int64","type":"integer"}},{"name":"end","in":"query","required":false,"description":"End is the end of the window as a unix-millisecond epoch. Zero means now.","schema":{"format":"int64","type":"integer"}},{"name":"traceId","in":"query","required":false,"description":"TraceID narrows the view to one trace.","schema":{"type":"string"}},{"name":"sessionId","in":"query","required":false,"description":"SessionID narrows the view to one conversation.","schema":{"type":"string"}},{"name":"userId","in":"query","required":false,"description":"UserID narrows the view to one end user.","schema":{"type":"string"}},{"name":"name","in":"query","required":false,"description":"Name narrows the view to observations of one name.","schema":{"type":"string"}},{"name":"model","in":"query","required":false,"description":"Model narrows the view to one model.","schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"description":"Offset is how many rows to skip, for paging.","schema":{"format":"int64","type":"integer"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many rows come back.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLLMObservationsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/llm/score/{id}":{"delete":{"operationId":"DeleteLLMScore","summary":"Hard-deletes a score by id.","description":"Hard-deletes a score by id.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"get":{"operationId":"GetLLMScore","summary":"Returns a single score by id.","description":"Returns a single score by id.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLLMScoreOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/llm/scores":{"get":{"operationId":"ListLLMScores","summary":"Lists eval scores and human-feedback signals attached to traces and observations, newest first.","description":"Lists eval scores and human-feedback signals attached to traces\nand observations, newest first.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"traceId","in":"query","required":false,"description":"TraceID narrows to scores on one trace.","schema":{"type":"string"}},{"name":"observationId","in":"query","required":false,"description":"ObservationID narrows to scores on one observation.","schema":{"type":"string"}},{"name":"name","in":"query","required":false,"description":"Name narrows to scores of one name.","schema":{"type":"string"}},{"name":"source","in":"query","required":false,"description":"Source narrows to scores from one source, e.g. API, EVAL.","schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"description":"Offset is how many rows to skip, for paging.","schema":{"format":"int64","type":"integer"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many rows come back.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLLMScoresOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"CreateLLMScore","summary":"Attaches an eval score or human-feedback signal to a trace or a single observation.","description":"Attaches an eval score or human-feedback signal to a trace or a\nsingle observation.\n\nCallers need the editor role; the runtime's own gate enforces it, and it\nvalidates the payload and stamps the score's author and org.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLLMIngestScore"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLLMScoreOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/llm/sessions":{"get":{"operationId":"ListLLMSessions","summary":"Lists conversations — gen_ai spans grouped by session.id, with their trace and observation counts, tokens and cost.","description":"Lists conversations — gen_ai spans grouped by session.id, with\ntheir trace and observation counts, tokens and cost.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"start","in":"query","required":false,"description":"Start is the start of the window as a unix-millisecond epoch. Zero means\n24h before the end.","schema":{"format":"int64","type":"integer"}},{"name":"end","in":"query","required":false,"description":"End is the end of the window as a unix-millisecond epoch. Zero means now.","schema":{"format":"int64","type":"integer"}},{"name":"traceId","in":"query","required":false,"description":"TraceID narrows the view to one trace.","schema":{"type":"string"}},{"name":"sessionId","in":"query","required":false,"description":"SessionID narrows the view to one conversation.","schema":{"type":"string"}},{"name":"userId","in":"query","required":false,"description":"UserID narrows the view to one end user.","schema":{"type":"string"}},{"name":"name","in":"query","required":false,"description":"Name narrows the view to observations of one name.","schema":{"type":"string"}},{"name":"model","in":"query","required":false,"description":"Model narrows the view to one model.","schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"description":"Offset is how many rows to skip, for paging.","schema":{"format":"int64","type":"integer"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many rows come back.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLLMSessionsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/llm/traces":{"get":{"operationId":"ListLLMTraces","summary":"Lists LLM traces — gen_ai spans grouped by trace_id, with cost, tokens and latency rolled up across each trace.","description":"Lists LLM traces — gen_ai spans grouped by trace_id, with cost,\ntokens and latency rolled up across each trace.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"start","in":"query","required":false,"description":"Start is the start of the window as a unix-millisecond epoch. Zero means\n24h before the end.","schema":{"format":"int64","type":"integer"}},{"name":"end","in":"query","required":false,"description":"End is the end of the window as a unix-millisecond epoch. Zero means now.","schema":{"format":"int64","type":"integer"}},{"name":"traceId","in":"query","required":false,"description":"TraceID narrows the view to one trace.","schema":{"type":"string"}},{"name":"sessionId","in":"query","required":false,"description":"SessionID narrows the view to one conversation.","schema":{"type":"string"}},{"name":"userId","in":"query","required":false,"description":"UserID narrows the view to one end user.","schema":{"type":"string"}},{"name":"name","in":"query","required":false,"description":"Name narrows the view to observations of one name.","schema":{"type":"string"}},{"name":"model","in":"query","required":false,"description":"Model narrows the view to one model.","schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"description":"Offset is how many rows to skip, for paging.","schema":{"format":"int64","type":"integer"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many rows come back.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLLMTracesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/llm/users":{"get":{"operationId":"ListLLMUsers","summary":"Lists end users — gen_ai spans grouped by user.id, with their session, trace and observation counts, tokens and cost.","description":"Lists end users — gen_ai spans grouped by user.id, with their\nsession, trace and observation counts, tokens and cost.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"start","in":"query","required":false,"description":"Start is the start of the window as a unix-millisecond epoch. Zero means\n24h before the end.","schema":{"format":"int64","type":"integer"}},{"name":"end","in":"query","required":false,"description":"End is the end of the window as a unix-millisecond epoch. Zero means now.","schema":{"format":"int64","type":"integer"}},{"name":"traceId","in":"query","required":false,"description":"TraceID narrows the view to one trace.","schema":{"type":"string"}},{"name":"sessionId","in":"query","required":false,"description":"SessionID narrows the view to one conversation.","schema":{"type":"string"}},{"name":"userId","in":"query","required":false,"description":"UserID narrows the view to one end user.","schema":{"type":"string"}},{"name":"name","in":"query","required":false,"description":"Name narrows the view to observations of one name.","schema":{"type":"string"}},{"name":"model","in":"query","required":false,"description":"Model narrows the view to one model.","schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"description":"Offset is how many rows to skip, for paging.","schema":{"format":"int64","type":"integer"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many rows come back.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLLMUsersOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/llm_pricing_rules":{"get":{"operationId":"ListLLMPricingRules","summary":"Returns the LLM pricing rules for the caller's org, with pagination and an optional search and override filter.","description":"Returns the LLM pricing rules for the caller's org, with\npagination and an optional search and override filter.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"q","in":"query","required":false,"description":"Search matches rules by model or provider.","schema":{"type":"string"}},{"name":"isOverride","in":"query","required":false,"description":"IsOverride, when \"true\" or \"false\", narrows to user-pinned rules or to\nsynced ones; empty returns both. It is a string because a query param is a\nstring on the wire, and the runtime reads absent as \"no filter\".","schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"description":"Offset is how many rows to skip, for paging.","schema":{"format":"int64","type":"integer"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many rows come back.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLLMPricingRulesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"CreateOrUpdateLLMPricingRules","summary":"Writes the pricing-rule batch — the single write endpoint used by both the user and the Zeus sync job.","description":"Writes the pricing-rule batch — the single write\nendpoint used by both the user and the Zeus sync job. Per-rule match is by id,\nthen sourceId, then insert; an override row is fully preserved when the\nrequest omits isOverride, only its synced_at stamped.\n\nCallers need the admin role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLLMUpdatablePricingRules"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/llm_pricing_rules/{id}":{"delete":{"operationId":"DeleteLLMPricingRule","summary":"Hard-deletes a pricing rule by id.","description":"Hard-deletes a pricing rule by id. If the rule was\nauto-synced, the next sync cycle recreates it.\n\nCallers need the admin role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"get":{"operationId":"GetLLMPricingRule","summary":"Returns a single LLM pricing rule by id.","description":"Returns a single LLM pricing rule by id.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLLMPricingRuleOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/login":{"get":{"operationId":"get_o11y_login","summary":"Report why an observability sign-in did not complete","description":"Where a failed sign-in callback lands. The module builds that redirect with a path and no host, so it can only be same-origin, and its assumption is that the console lives beside the API. Here the console is a separate host, so this answers as the API it belongs to rather than redirecting onward — a hostname baked into a shared surface is how one brand's identity ends up in front of another brand's customer.\n\n401 with the provider's own reason, carried from the query the module already populated. Unauthenticated by necessity: it exists precisely for the case where no principal was established.","tags":["o11y"],"x-app":"o11y","x-public":true}},"/v1/o11y/logs":{"get":{"operationId":"get_o11y_logs","summary":"Returns the most recent log records in the query window, newest first — each record an open object carrying its nanosecond timestamp and whatever fields the record was ingested with.","description":"Returns the most recent log records in the query window, newest\nfirst — each record an open object carrying its nanosecond timestamp and\nwhatever fields the record was ingested with.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit caps how many records come back. Zero means the default of 100.","schema":{"format":"int64","type":"integer"}},{"name":"timestampStart","in":"query","required":false,"description":"TimestampStart is the start of the window as a nanosecond epoch. Zero\nmeans fifteen minutes before the end.","schema":{"format":"int64","type":"integer"}},{"name":"timestampEnd","in":"query","required":false,"description":"TimestampEnd is the end of the window as a nanosecond epoch. Zero means\nnow.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLogRecordsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/logs/aggregate":{"get":{"operationId":"get_o11y_logs_aggregate","summary":"Returns the logs aggregate buckets for the query window.","description":"Returns the logs aggregate buckets for the query window. The\nruntime currently answers the empty set; the shape is the contract.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLogAggregateOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/logs/fields":{"get":{"operationId":"get_o11y_logs_fields","summary":"Returns the log field catalog: the fields already selected as indexed columns, and the interesting ones seen in the data that could be.","description":"Returns the log field catalog: the fields already selected as\nindexed columns, and the interesting ones seen in the data that could be.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFieldCatalogOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"post_o11y_logs_fields","summary":"Changes how one log field is stored — selects or deselects it as a materialized column and tunes its index — and echoes the setting back.","description":"Changes how one log field is stored — selects or deselects it\nas a materialized column and tunes its index — and echoes the setting back.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFieldSetting"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFieldSetting"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/logs/livetail":{"get":{"operationId":"get_o11y_logs_livetail","summary":"Follow log records as they arrive","description":"Streams matching log records continuously instead of answering once, so a console tail shows lines as they land rather than at the end of a window.\n\nIt is a STREAM, which is why it is not a typed operation: there is no single complete value to name, and a generated client that waited for one would hang on the first tail. Read the bounded window with the log read instead when you want an answer rather than a feed.\n\nA validated, org-scoped principal is required and the feed carries that principal's own tenant only.","tags":["o11y"],"x-app":"o11y","x-public":true}},"/v1/o11y/logs/pipelines":{"post":{"operationId":"post_o11y_logs_pipelines","summary":"Saves the given log parsing pipelines as the new config version for the caller's org and starts deploying it.","description":"Saves the given log parsing pipelines as the new config\nversion for the caller's org and starts deploying it. The set REPLACES the\ncurrent one: a pipeline left out of the request is dropped from the new\nversion, and an empty set drops them all.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLogPipelineCreateIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLogPipelinesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/logs/pipelines/preview":{"post":{"operationId":"post_o11y_logs_pipelines_preview","summary":"Runs the given log parsing pipelines over the given sample records without saving anything, and returns the transformed records plus whatever the collector logged while simulating them.","description":"Runs the given log parsing pipelines over the given\nsample records without saving anything, and returns the transformed records\nplus whatever the collector logged while simulating them.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLogPipelinePreviewIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLogPipelinePreviewOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/logs/pipelines/{version}":{"get":{"operationId":"get_o11y_logs_pipelines_by_version","summary":"Returns the caller's org's log parsing pipelines at one config version — \"latest\" for the newest — along with that version's deployment record and the recent version history.","description":"Returns the caller's org's log parsing pipelines at one config\nversion — \"latest\" for the newest — along with that version's deployment\nrecord and the recent version history.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"version","in":"path","required":true,"description":"Version is the config version to read — a positive number, or \"latest\".","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLogPipelinesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/logs/promote_paths":{"get":{"operationId":"get_o11y_logs_promote_paths","summary":"Lists the log body paths already promoted or indexed, with the indexes each carries.","description":"Lists the log body paths already promoted or indexed, with the\nindexes each carries.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLogPromotedOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"post_o11y_logs_promote_paths","summary":"Promotes and indexes log body paths: each named path is lifted out of the JSON body into its own column, with the indexes the caller asked for.","description":"Promotes and indexes log body paths: each named path is lifted\nout of the JSON body into its own column, with the indexes the caller asked\nfor. Paths must start with \"body.\".\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/o11y.O11yLogPromotePath"},"type":"array"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLogPromoteOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/messaging-queues/kafka/consumer-lag/consumer-details":{"post":{"operationId":"post_o11y_messaging-queues_kafka_consumer-lag_consumer-details","summary":"Returns the consumer side of a consumer-lag view: the consumer groups reading the topic/partition named in variables, with their throughput and latency over the window.","description":"Returns the consumer side of a consumer-lag view: the\nconsumer groups reading the topic/partition named in variables, with their\nthroughput and latency over the window.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueueIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueryRangeOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/messaging-queues/kafka/consumer-lag/network-latency":{"post":{"operationId":"post_o11y_messaging-queues_kafka_consumer-lag_network-latency","summary":"Returns consumer network latency correlated per client: a throughput pass over the window finds the consumer clients, then their fetch latency joins in as a latency column per client/instance/service.","description":"Returns consumer network latency correlated per client:\na throughput pass over the window finds the consumer clients, then their\nfetch latency joins in as a latency column per client/instance/service.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueueIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueryRangeOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/messaging-queues/kafka/consumer-lag/producer-details":{"post":{"operationId":"post_o11y_messaging-queues_kafka_consumer-lag_producer-details","summary":"Returns the producer side of a consumer-lag view: the producers writing to the topic/partition named in variables, with their throughput and latency over the window.","description":"Returns the producer side of a consumer-lag view: the\nproducers writing to the topic/partition named in variables, with their\nthroughput and latency over the window.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueueIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueryRangeOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/messaging-queues/kafka/onboarding/consumers":{"post":{"operationId":"post_o11y_messaging-queues_kafka_onboarding_consumers","summary":"Checks whether the spans the Kafka consumer views need are arriving, row for row like producersOnboarding.","description":"Checks whether the spans the Kafka consumer views need\nare arriving, row for row like producersOnboarding.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueueIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueueChecksOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/messaging-queues/kafka/onboarding/kafka":{"post":{"operationId":"post_o11y_messaging-queues_kafka_onboarding_kafka","summary":"Checks whether Kafka's own metrics — consumer lag and partition telemetry — are arriving, so the lag views can be lit up.","description":"Checks whether Kafka's own metrics — consumer lag and\npartition telemetry — are arriving, so the lag views can be lit up.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueueIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueueChecksOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/messaging-queues/kafka/onboarding/producers":{"post":{"operationId":"post_o11y_messaging-queues_kafka_onboarding_producers","summary":"Checks whether the spans the Kafka producer views need are arriving — one row per required span attribute, with a pass/fail status and, on failure, what is missing from the instrumentation.","description":"Checks whether the spans the Kafka producer views need\nare arriving — one row per required span attribute, with a pass/fail status\nand, on failure, what is missing from the instrumentation.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueueIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueueChecksOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/messaging-queues/kafka/partition-latency/consumer":{"post":{"operationId":"post_o11y_messaging-queues_kafka_partition-latency_consumer","summary":"Returns the consumer-group latency detail for the topic and partition named in the request's variables.","description":"Returns the consumer-group latency detail for the\ntopic and partition named in the request's variables.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueueIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueryRangeOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/messaging-queues/kafka/partition-latency/overview":{"post":{"operationId":"post_o11y_messaging-queues_kafka_partition-latency_overview","summary":"Returns the per-partition latency overview for the window — each topic/partition with its throughput and latency profile.","description":"Returns the per-partition latency overview for the window —\neach topic/partition with its throughput and latency profile.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueueIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueryRangeOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/messaging-queues/kafka/span/evaluation":{"post":{"operationId":"post_o11y_messaging-queues_kafka_span_evaluation","summary":"Correlates producer and consumer spans over the evaluation window (eval_time bounds the scan) and returns the pairings with their end-to-end delay — the check that messages produced are being consumed.","description":"Correlates producer and consumer spans over the evaluation\nwindow (eval_time bounds the scan) and returns the pairings with their\nend-to-end delay — the check that messages produced are being consumed.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueueIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueryRangeOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/messaging-queues/kafka/topic-throughput/consumer":{"post":{"operationId":"post_o11y_messaging-queues_kafka_topic-throughput_consumer","summary":"Returns the consumer topic-throughput overview for the window — what each consumer group read, per topic.","description":"Returns the consumer topic-throughput overview for the\nwindow — what each consumer group read, per topic.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueueIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueryRangeOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/messaging-queues/kafka/topic-throughput/consumer-details":{"post":{"operationId":"post_o11y_messaging-queues_kafka_topic-throughput_consumer-details","summary":"Breaks one consumer topic's throughput down using the topic and service named in variables.","description":"Breaks one consumer topic's throughput down using\nthe topic and service named in variables.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueueIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueryRangeOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/messaging-queues/kafka/topic-throughput/producer":{"post":{"operationId":"post_o11y_messaging-queues_kafka_topic-throughput_producer","summary":"Returns the producer topic-throughput overview for the window — what each producer service wrote, per topic.","description":"Returns the producer topic-throughput overview for the\nwindow — what each producer service wrote, per topic.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueueIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueryRangeOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/messaging-queues/kafka/topic-throughput/producer-details":{"post":{"operationId":"post_o11y_messaging-queues_kafka_topic-throughput_producer-details","summary":"Breaks one producer topic's throughput down using the topic and service named in variables.","description":"Breaks one producer topic's throughput down using\nthe topic and service named in variables.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueueIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueryRangeOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/messaging-queues/queue-overview":{"post":{"operationId":"post_o11y_messaging-queues_queue-overview","summary":"Lists the messaging destinations observed in the window — one row per queue/destination/service combination with its throughput and latency columns.","description":"Lists the messaging destinations observed in the window — one\nrow per queue/destination/service combination with its throughput and\nlatency columns. Filters narrow by queue system, destination, service or any\nspan attribute.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueueListIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueueRowsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/metric/metric_metadata":{"get":{"operationId":"get_o11y_metric_metric_metadata","summary":"Serves the OLDER /metric/metric_metadata route.","description":"Serves the OLDER /metric/metric_metadata route. It is\nNOT the same op as metrics.go's metricMetadata (/metrics/metadata): different\npath, different input (this one also scopes by service). Two slices named one\nGo function for two routes; the route is the identity, so the name follows it.\nRenamed rather than merged — collapsing them would silently drop the service\nscope this one accepts.\nIt returns one metric's metadata — its type, unit, description,\ntemporality, monotonicity and histogram buckets — optionally scoped to the\nmetric as one service reports it.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"metricName","in":"query","required":false,"description":"MetricName is the metric to read.","schema":{"type":"string"}},{"name":"serviceName","in":"query","required":false,"description":"ServiceName scopes the metadata to the metric as one service reports it.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yMetricMetadataOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/metric_reduction_rules":{"get":{"operationId":"ListMetricReductionRules","summary":"Lists the org's metric volume-control (label reduction) rules, pageable and sortable by name, volume or recency.","description":"Lists the org's metric volume-control (label reduction)\nrules, pageable and sortable by name, volume or recency.","tags":["o11y"],"parameters":[{"name":"orderBy","in":"query","required":false,"description":"OrderBy sorts the page: metric, ingested_volume, reduced_volume or\nlast_updated. Unset means ingested_volume.","schema":{"type":"string"}},{"name":"order","in":"query","required":false,"description":"Order is asc or desc. Unset means desc.","schema":{"type":"string"}},{"name":"search","in":"query","required":false,"description":"Search narrows the page to rules whose metric name contains it.","schema":{"type":"string"}},{"name":"metricName","in":"query","required":false,"description":"MetricName narrows the page to one metric's rule.","schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"description":"Offset is how many rules to skip, for paging.","schema":{"format":"int64","type":"integer"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many rules come back, at most 1000. Unset means 10.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yReductionRuleListOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"CreateMetricReductionRule","summary":"Creates a volume-control rule for a metric and returns it with its id; a metric that already has a rule is refused.","description":"Creates a volume-control rule for a metric and returns\nit with its id; a metric that already has a rule is refused.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yReductionRuleCreateIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yReductionRuleOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/metric_reduction_rules/preview":{"post":{"operationId":"PreviewMetricReductionRule","summary":"Estimates the series reduction and the dashboards and alerts a candidate volume-control rule would touch, without persisting it.","description":"Estimates the series reduction and the dashboards and\nalerts a candidate volume-control rule would touch, without persisting it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yReductionRulePreviewIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yReductionRulePreviewOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/metric_reduction_rules/stats":{"get":{"operationId":"GetMetricReductionRuleStats","summary":"Returns total ingested vs retained series and samples and the estimated monthly savings across all volume-control rules.","description":"Returns total ingested vs retained series and samples and\nthe estimated monthly savings across all volume-control rules.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yReductionStatsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/metric_reduction_rules/timeseries":{"get":{"operationId":"GetMetricReductionRuleTimeseries","summary":"Returns ingested vs retained series over time across all volume-control rules, in hourly buckets, in the query-range time-series response shape.","description":"Returns ingested vs retained series over time across\nall volume-control rules, in hourly buckets, in the query-range time-series\nresponse shape.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yReductionSeriesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/metric_reduction_rules/{id}":{"delete":{"operationId":"DeleteMetricReductionRuleByID","summary":"Deletes a volume-control rule by its id.","description":"Deletes a volume-control rule by its id.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the rule's id.","schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"get":{"operationId":"GetMetricReductionRuleByID","summary":"Returns one volume-control rule by its id.","description":"Returns one volume-control rule by its id.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the rule's id.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yReductionRuleOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"UpdateMetricReductionRuleByID","summary":"Updates the match type and labels of a volume-control rule by its id; the metric name is immutable.","description":"Updates the match type and labels of a volume-control rule\nby its id; the metric name is immutable.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the rule's id.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yReductionRuleSaveIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yReductionRuleOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/metrics":{"get":{"operationId":"ListMetrics","summary":"Lists the distinct metric names seen in a time range, each with its description, type, unit, temporality and monotonicity.","description":"Lists the distinct metric names seen in a time range, each with\nits description, type, unit, temporality and monotonicity.","tags":["o11y"],"parameters":[{"name":"start","in":"query","required":false,"description":"Start is the start of the window as a Unix timestamp in milliseconds.","schema":{"format":"int64","type":"integer"}},{"name":"end","in":"query","required":false,"description":"End is the end of the window as a Unix timestamp in milliseconds.","schema":{"format":"int64","type":"integer"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many metrics come back; unset means 100, at most 5000.","schema":{"format":"int64","type":"integer"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the page to metric names containing it.","schema":{"type":"string"}},{"name":"source","in":"query","required":false,"description":"Source narrows the page by ingestion source.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yMetricListOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/metrics/alerts":{"get":{"operationId":"GetMetricAlerts","summary":"Lists the alert rules that reference a metric.","description":"Lists the alert rules that reference a metric.","tags":["o11y"],"parameters":[{"name":"metricName","in":"query","required":true,"description":"MetricName is the metric's name; it may contain slashes, e.g.\nrun.googleapis.com/request_latencies. Required.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yMetricAlertsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/metrics/attributes":{"get":{"operationId":"GetMetricAttributes","summary":"Returns one metric's attribute keys, each with its unique values and their count.","description":"Returns one metric's attribute keys, each with its unique\nvalues and their count.","tags":["o11y"],"parameters":[{"name":"metricName","in":"query","required":true,"description":"MetricName is the metric's name; it may contain slashes. Required.","schema":{"type":"string"}},{"name":"start","in":"query","required":false,"description":"Start is the start of the window as a Unix timestamp in milliseconds.","schema":{"format":"int64","type":"integer"}},{"name":"end","in":"query","required":false,"description":"End is the end of the window as a Unix timestamp in milliseconds.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yMetricAttributesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/metrics/dashboards":{"get":{"operationId":"GetMetricDashboardsV2","summary":"Lists the dashboard panels that reference a metric.","description":"Lists the dashboard panels that reference a metric.","tags":["o11y"],"parameters":[{"name":"metricName","in":"query","required":true,"description":"MetricName is the metric's name; it may contain slashes, e.g.\nrun.googleapis.com/request_latencies. Required.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yMetricDashboardsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/metrics/highlights":{"get":{"operationId":"GetMetricHighlights","summary":"Returns one metric's headline numbers: data points, total and active time series, and when it was last received.","description":"Returns one metric's headline numbers: data points, total\nand active time series, and when it was last received.","tags":["o11y"],"parameters":[{"name":"metricName","in":"query","required":true,"description":"MetricName is the metric's name; it may contain slashes, e.g.\nrun.googleapis.com/request_latencies. Required.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yMetricHighlightsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/metrics/inspect":{"post":{"operationId":"InspectMetrics","summary":"Returns one metric's raw time series over a window of at most thirty minutes — each series with its labels and timestamp/value pairs.","description":"Returns one metric's raw time series over a window of at most\nthirty minutes — each series with its labels and timestamp/value pairs.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yMetricInspectIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yMetricInspectOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/metrics/metadata":{"get":{"operationId":"GetMetricMetadata","summary":"Returns one metric's metadata: description, type, unit, temporality and monotonicity.","description":"Returns one metric's metadata: description, type, unit,\ntemporality and monotonicity.","tags":["o11y"],"parameters":[{"name":"metricName","in":"query","required":true,"description":"MetricName is the metric's name; it may contain slashes, e.g.\nrun.googleapis.com/request_latencies. Required.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yMetricMetadataOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"UpdateMetricMetadata","summary":"Updates one metric's metadata — description, type, unit, temporality, monotonicity — and answers with the bare success envelope.","description":"Updates one metric's metadata — description, type, unit,\ntemporality, monotonicity — and answers with the bare success envelope.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yMetricMetadataSaveIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yMetricAckOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/metrics/onboarding":{"get":{"operationId":"GetMetricsOnboardingStatus","summary":"Reports whether any non-O11y metrics have been ingested — the lightweight check onboarding polls.","description":"Reports whether any non-O11y metrics have been ingested —\nthe lightweight check onboarding polls.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yMetricOnboardingOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/metrics/stats":{"post":{"operationId":"GetMetricsStats","summary":"Lists metrics with their sample and time-series counts for a time range — the volume view of the metrics explorer, pageable and sortable.","description":"Lists metrics with their sample and time-series counts for a\ntime range — the volume view of the metrics explorer, pageable and sortable.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yMetricStatsIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yMetricStatsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/metrics/treemap":{"post":{"operationId":"GetMetricsTreemap","summary":"Returns the proportional distribution of metrics by sample count or time-series count, as the entries of a treemap.","description":"Returns the proportional distribution of metrics by sample\ncount or time-series count, as the entries of a treemap.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yMetricTreemapIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yMetricTreemapOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/namespaces/attribute_keys":{"get":{"operationId":"get_o11y_namespaces_attribute_keys","summary":"Lists the metric attribute keys Kubernetes namespaces report, for building namespace filters.","description":"Lists the metric attribute keys Kubernetes namespaces\nreport, for building namespace filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the keys must appear on.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the keys to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many keys come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeKeysOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/namespaces/attribute_values":{"get":{"operationId":"get_o11y_namespaces_attribute_values","summary":"Lists the values one namespace attribute key has taken, for building namespace filters.","description":"Lists the values one namespace attribute key has\ntaken, for building namespace filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the values must appear on.","schema":{"type":"string"}},{"name":"attributeKey","in":"query","required":false,"description":"AttributeKey is the key whose values to list.","schema":{"type":"string"}},{"name":"filterAttributeKeyDataType","in":"query","required":false,"description":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the values to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the search to one kind of key — tag or resource.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many values come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeValuesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/namespaces/list":{"post":{"operationId":"post_o11y_namespaces_list","summary":"Lists Kubernetes namespaces over a time range, each with the CPU and memory its pods used, their phase counts and its attributes; filterable, groupable and paginated.","description":"Lists Kubernetes namespaces over a time range, each with the\nCPU and memory its pods used, their phase counts and its attributes;\nfilterable, groupable and paginated.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.NamespaceListRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yNamespaceListOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/nextPrevErrorIDs":{"get":{"operationId":"get_o11y_nextpreverrorids","summary":"Returns the ids of the exception instances immediately after and before a given one within its group — the paging cursor the error detail view walks.","description":"Returns the ids of the exception instances immediately after\nand before a given one within its group — the paging cursor the error detail\nview walks.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"timestamp","in":"query","required":true,"description":"Timestamp is the instance's time as a nanosecond epoch spelled as a\nstring. Required.","schema":{"type":"string"}},{"name":"groupID","in":"query","required":true,"description":"GroupID is the exception group the instance belongs to. Required.","schema":{"type":"string"}},{"name":"errorID","in":"query","required":false,"description":"ErrorID is the exception instance id. Required by errorFromErrorID and\nnextPrevErrorIDs; unused by errorFromGroupID.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yNextPrevErrorIDs"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/nodes/attribute_keys":{"get":{"operationId":"get_o11y_nodes_attribute_keys","summary":"Lists the metric attribute keys Kubernetes nodes report, for building node filters.","description":"Lists the metric attribute keys Kubernetes nodes report,\nfor building node filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the keys must appear on.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the keys to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many keys come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeKeysOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/nodes/attribute_values":{"get":{"operationId":"get_o11y_nodes_attribute_values","summary":"Lists the values one node attribute key has taken, for building node filters.","description":"Lists the values one node attribute key has taken, for\nbuilding node filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the values must appear on.","schema":{"type":"string"}},{"name":"attributeKey","in":"query","required":false,"description":"AttributeKey is the key whose values to list.","schema":{"type":"string"}},{"name":"filterAttributeKeyDataType","in":"query","required":false,"description":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the values to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the search to one kind of key — tag or resource.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many values come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeValuesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/nodes/list":{"post":{"operationId":"post_o11y_nodes_list","summary":"Lists Kubernetes nodes over a time range, each with its CPU and memory usage against allocatable capacity, readiness condition counts and attributes; filterable, groupable and paginated.","description":"Lists Kubernetes nodes over a time range, each with its CPU and\nmemory usage against allocatable capacity, readiness condition counts and\nattributes; filterable, groupable and paginated.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.NodeListRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yNodeListOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/org/preferences":{"get":{"operationId":"ListOrgPreferences","summary":"Lists every org-scoped preference, each with its current and default value.","description":"Lists every org-scoped preference, each with its current\nand default value. Admin gate.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yPreferencesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/org/preferences/{name}":{"get":{"operationId":"GetOrgPreference","summary":"Returns one org-scoped preference, by name.","description":"Returns one org-scoped preference, by name. Admin gate.","tags":["o11y"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yPreferenceOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"UpdateOrgPreference","summary":"Sets one org-scoped preference, by name.","description":"Sets one org-scoped preference, by name. Admin gate.","tags":["o11y"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yUpdatablePreference"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/orgs/me":{"get":{"operationId":"GetMyOrganization","summary":"Returns the caller's own organization.","description":"Returns the caller's own organization. Admin gate.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yOrganizationOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"UpdateMyOrganization","summary":"Rewrites the caller's own organization record — display name, name, alias — always addressed as \"me\", never by id.","description":"Rewrites the caller's own organization record — display name,\nname, alias — always addressed as \"me\", never by id. Admin gate.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yOrganization"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/orgs/me/filters":{"get":{"operationId":"GetQuickFilters","summary":"Returns the org's quick filters for every signal — the attribute shortlists its explorers offer as one-click filters.","description":"Returns the org's quick filters for every signal — the\nattribute shortlists its explorers offer as one-click filters. Viewer gate.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQuickFiltersOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"UpdateQuickFilters","summary":"Replaces the org's quick filters for one signal with the attribute list given.","description":"Replaces the org's quick filters for one signal with the\nattribute list given. Admin gate.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yUpdatableQuickFilters"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/orgs/me/filters/{signal}":{"get":{"operationId":"GetSignalFilters","summary":"Returns the org's quick filters for one signal — traces, logs, metrics, exceptions or api_monitoring.","description":"Returns the org's quick filters for one signal — traces,\nlogs, metrics, exceptions or api_monitoring. Viewer gate.","tags":["o11y"],"parameters":[{"name":"signal","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySignalFiltersOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/pods/attribute_keys":{"get":{"operationId":"get_o11y_pods_attribute_keys","summary":"Lists the metric attribute keys Kubernetes pods report, for building pod filters.","description":"Lists the metric attribute keys Kubernetes pods report, for\nbuilding pod filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the keys must appear on.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the keys to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many keys come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeKeysOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/pods/attribute_values":{"get":{"operationId":"get_o11y_pods_attribute_values","summary":"Lists the values one pod attribute key has taken, for building pod filters.","description":"Lists the values one pod attribute key has taken, for\nbuilding pod filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the values must appear on.","schema":{"type":"string"}},{"name":"attributeKey","in":"query","required":false,"description":"AttributeKey is the key whose values to list.","schema":{"type":"string"}},{"name":"filterAttributeKeyDataType","in":"query","required":false,"description":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the values to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the search to one kind of key — tag or resource.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many values come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeValuesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/pods/list":{"post":{"operationId":"post_o11y_pods_list","summary":"Lists Kubernetes pods over a time range, each with its CPU and memory usage against request and limit, restart count, phase counts and attributes; filterable, groupable and paginated.","description":"Lists Kubernetes pods over a time range, each with its CPU and\nmemory usage against request and limit, restart count, phase counts and\nattributes; filterable, groupable and paginated.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.PodListRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yPodListOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/processes/attribute_keys":{"get":{"operationId":"get_o11y_processes_attribute_keys","summary":"Lists the metric attribute keys processes report, for building process filters.","description":"Lists the metric attribute keys processes report, for\nbuilding process filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the keys must appear on.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the keys to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many keys come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeKeysOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/processes/attribute_values":{"get":{"operationId":"get_o11y_processes_attribute_values","summary":"Lists the values one process attribute key has taken, for building process filters.","description":"Lists the values one process attribute key has taken,\nfor building process filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the values must appear on.","schema":{"type":"string"}},{"name":"attributeKey","in":"query","required":false,"description":"AttributeKey is the key whose values to list.","schema":{"type":"string"}},{"name":"filterAttributeKeyDataType","in":"query","required":false,"description":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the values to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the search to one kind of key — tag or resource.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many values come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeValuesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/processes/list":{"post":{"operationId":"post_o11y_processes_list","summary":"Lists monitored processes over a time range, each with its name, PID, command line and CPU and memory usage; filterable, groupable and paginated.","description":"Lists monitored processes over a time range, each with its name,\nPID, command line and CPU and memory usage; filterable, groupable and\npaginated.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.ProcessListRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yProcessListOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/product/metrics":{"get":{"operationId":"get_o11y_product_metrics","summary":"Returns one product's RED series — request rate, errors, p50 and p95 latency — for the caller's org, plus that org's LLM usage rollup over the same window.","description":"Returns one product's RED series — request rate, errors, p50\nand p95 latency — for the caller's org, plus that org's LLM usage rollup over\nthe same window. The series come from org-tagged request spans, so a tenant\nonly ever aggregates its own traffic; a validated platform SuperAdmin sees the\nwhole product's RED, while usage stays the caller's own org either way. A\nwell-formed product with no backing workload answers empty series; a malformed\nslug is a 400.","tags":["o11y"],"parameters":[{"name":"product","in":"query","required":false,"description":"Product is the console product slug to read, e.g. \"kms\". Required.","schema":{"type":"string"},"example":"kms"},{"name":"range","in":"query","required":false,"description":"Range is the window in seconds. Default 3600, capped at 604800 (7d).","schema":{"format":"int64","type":"integer"},"example":3600},{"name":"stepSec","in":"query","required":false,"description":"StepSec is the bucket width in seconds, clamped to [30, 3600]. Absent\npicks ~60 buckets across the range.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.metricsResponse"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/public/dashboards/{id}":{"get":{"operationId":"GetPublicDashboardData","summary":"Returns the sanitized dashboard data for public access — the read a shared dashboard's public page makes.","description":"Returns the sanitized dashboard data for public access —\nthe read a shared dashboard's public page makes.\n\nAnonymous, scoped to the public dashboard's read scope; the runtime's own gate\nenforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource id from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yPublicDashboardDataOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/public/dashboards/{id}/widgets/{idx}/query_range":{"get":{"operationId":"GetPublicDashboardWidgetQueryRange","summary":"Returns the query-range result for one widget of a public dashboard.","description":"Returns the query-range result for one widget\nof a public dashboard. When the share fixes its own time range the caller's\nstartTime/endTime are ignored; otherwise they bound the window as millisecond\nepochs.\n\nAnonymous, scoped to the public dashboard's read scope; the runtime's own gate\nenforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the public dashboard id from the path.","schema":{"type":"string"}},{"name":"idx","in":"path","required":true,"description":"Idx is the widget's index from the path.","schema":{"type":"string"}},{"name":"startTime","in":"query","required":false,"description":"StartTime is the window start as a millisecond epoch. Used only when the\nshare enables a caller-chosen time range.","schema":{"type":"string"}},{"name":"endTime","in":"query","required":false,"description":"EndTime is the window end as a millisecond epoch. Used only when the share\nenables a caller-chosen time range.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yWidgetQueryRangeOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/pvcs/attribute_keys":{"get":{"operationId":"get_o11y_pvcs_attribute_keys","summary":"Lists the metric attribute keys persistent volume claims report, for building volume filters.","description":"Lists the metric attribute keys persistent volume claims\nreport, for building volume filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the keys must appear on.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the keys to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many keys come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeKeysOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/pvcs/attribute_values":{"get":{"operationId":"get_o11y_pvcs_attribute_values","summary":"Lists the values one persistent-volume-claim attribute key has taken, for building volume filters.","description":"Lists the values one persistent-volume-claim attribute\nkey has taken, for building volume filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the values must appear on.","schema":{"type":"string"}},{"name":"attributeKey","in":"query","required":false,"description":"AttributeKey is the key whose values to list.","schema":{"type":"string"}},{"name":"filterAttributeKeyDataType","in":"query","required":false,"description":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the values to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the search to one kind of key — tag or resource.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many values come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeValuesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/pvcs/list":{"post":{"operationId":"post_o11y_pvcs_list","summary":"Lists Kubernetes persistent volume claims over a time range, each with its available, capacity and used bytes, inode counts and attributes; filterable, groupable and paginated.","description":"Lists Kubernetes persistent volume claims over a time range, each\nwith its available, capacity and used bytes, inode counts and attributes;\nfilterable, groupable and paginated.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.VolumeListRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yPvcListOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/query":{"get":{"operationId":"get_o11y_query","summary":"Evaluates one instant PromQL query against the org's metrics and returns the result at a single point in time.","description":"Evaluates one instant PromQL query against the org's metrics and\nreturns the result at a single point in time.\n\nThe result is polymorphic by PromQL's own contract — a matrix, vector,\nscalar or string, discriminated by resultType — so it is carried verbatim\nrather than forced into one of its shapes.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"query","in":"query","required":true,"description":"Query is the PromQL expression to evaluate. Required.","schema":{"type":"string"}},{"name":"time","in":"query","required":false,"description":"Time is the evaluation timestamp — epoch seconds or RFC3339. Empty\nevaluates at now.","schema":{"type":"string"}},{"name":"stats","in":"query","required":false,"description":"Stats set to any non-empty value includes query statistics in the answer.","schema":{"type":"string"}},{"name":"timeout","in":"query","required":false,"description":"Timeout caps evaluation time, as a duration in seconds.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yPromQueryOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/query_filter/analyze":{"post":{"operationId":"post_o11y_query_filter_analyze","summary":"Analyzes a query and extracts the metric names it reads and the columns it groups by.","description":"Analyzes a query and extracts the metric names it reads\nand the columns it groups by.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yAnalyzeIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yAnalyzeOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/query_progress":{"get":{"operationId":"get_o11y_query_progress","summary":"Watch one running query's progress","description":"Reports how far a submitted query has got — rows scanned, bytes read, elapsed — and HOLDS the connection until the next update rather than answering immediately.\n\nONE ADDRESS, TWO PROTOCOLS. Send an Upgrade and this is a websocket carrying the same progress; send an ordinary GET and it is a long poll. The Upgrade is a property of the request, not of the address, so the read that used to answer at /ws/query_progress answers here.\n\nThe long poll is the whole point, and the reason this cannot be a typed operation: an answer that arrived only when the query finished would report progress on nothing, and an upgraded connection has no JSON response to declare.\n\nA validated, org-scoped principal is required; a query id belonging to another tenant is simply not found.","tags":["o11y"],"x-app":"o11y","x-public":true}},"/v1/o11y/query_range":{"get":{"operationId":"get_o11y_query_range","summary":"Runs a Prometheus-style range query over metrics — the legacy read that predates the v5 querier — and returns the matrix, vector or scalar the query resolved to.","description":"Runs a Prometheus-style range query over metrics — the\nlegacy read that predates the v5 querier — and returns the matrix, vector or\nscalar the query resolved to.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"start","in":"query","required":true,"description":"Start is the window start — a unix timestamp (seconds, with optional\nfraction) or an RFC 3339 time. Required.","schema":{"type":"string"}},{"name":"end","in":"query","required":true,"description":"End is the window end, in the same form as Start, and not before it.\nRequired.","schema":{"type":"string"}},{"name":"step","in":"query","required":true,"description":"Step is the query resolution, e.g. 60s, 1m, 1h — a positive duration.\nRequired.","schema":{"type":"string"}},{"name":"query","in":"query","required":true,"description":"Query is the PromQL expression to evaluate. Required.","schema":{"type":"string"}},{"name":"stats","in":"query","required":false,"description":"Stats, when \"all\", asks for query statistics alongside the result.","schema":{"type":"string"}},{"name":"timeout","in":"query","required":false,"description":"Timeout caps how long the query may run, e.g. 30s, 1m — a positive\nduration. Absent means the server default.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yMetricsQueryRangeOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"post_o11y_query_range","summary":"Executes a composite query over a time range: builder queries over traces, logs and metrics, formulas, trace operators, PromQL and Datastore SQL, answering time series, scalars or raw records as the request type asks.","description":"Executes a composite query over a time range: builder\nqueries over traces, logs and metrics, formulas, trace operators, PromQL and\nDatastore SQL, answering time series, scalars or raw records as the request\ntype asks.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.QueryRangeRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueryRangeOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/query_range/format":{"post":{"operationId":"post_o11y_query_range_format","summary":"Parses a builder query and echoes it back normalized to the v3 shape — the endpoint the UI uses to canonicalize a query without running it.","description":"Parses a builder query and echoes it back normalized to the\nv3 shape — the endpoint the UI uses to canonicalize a query without running\nit.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.QueryRangeParamsV3"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueryRangeFormatOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/query_range/preview":{"post":{"operationId":"post_o11y_query_range_preview","summary":"Validates a composite query and renders the Datastore statements it would run WITHOUT executing it — a dry run for agentic and tooling use.","description":"Validates a composite query and renders the Datastore\nstatements it would run WITHOUT executing it — a dry run for agentic and\ntooling use. verbose=false trades the rendered SQL and EXPLAIN for a\nlightweight per-query verdict.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueryRangePreviewIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yQueryRangePreviewOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/readyz":{"get":{"operationId":"get_o11y_readyz","summary":"Readiness of the observability runtime to serve","description":"Reports whether the runtime's registered services are healthy enough to take traffic, and answers 503 when they are not — which is what takes a booting or degraded replica out of the load balancer instead of letting it serve errors.\n\nUNAUTHENTICATED by design, like the other two probes. It reads the same service registry the health probe reads, so the two agree by construction; readiness is the question a router asks and health is the question an operator asks.","tags":["o11y"],"x-app":"o11y","x-public":true}},"/v1/o11y/reviews":{"get":{"operationId":"get_o11y_reviews","summary":"Returns a page of the caller org's human-review queues, newest first, narrowed to the caller's project.","description":"Returns a page of the caller org's human-review queues,\nnewest first, narrowed to the caller's project. Another org's queues are never\nvisible.","tags":["o11y"],"parameters":[{"name":"page","in":"query","required":false,"description":"Page is the 1-based page to read. Default 1.","schema":{"format":"int64","type":"integer"},"example":1},{"name":"limit","in":"query","required":false,"description":"Limit is how many rows to return. Default 20, capped at 100.","schema":{"format":"int64","type":"integer"},"example":20}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.annQueueList"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"post_o11y_reviews","summary":"Creates a human-review queue in the caller's org and project.","description":"Creates a human-review queue in the caller's org and\nproject. A name already used by another queue in the same project is a 409.","tags":["o11y"],"requestBody":{"content":{"application/json":{"example":{"name":"hallucination review","scoreConfigIds":["quality"]},"schema":{"$ref":"#/components/schemas/o11y.createQueueReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.annQueueView"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/reviews/{id}":{"delete":{"operationId":"delete_o11y_reviews_by_id","summary":"Removes one review queue and every item in it.","description":"Removes one review queue and every item in it. A queue\nid belonging to another org answers the same 404 an unknown id does, so a\nprobe learns nothing about what exists.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the annotation queue to act on, from the path.","schema":{"type":"string"},"example":"annq_1"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.annQueueDeleted"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"get":{"operationId":"get_o11y_reviews_by_id","summary":"Returns one review queue with its pending and completed counts and its first page of items.","description":"Returns one review queue with its pending and completed\ncounts and its first page of items. A queue id belonging to another org is a\n404, never a cross-tenant read.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the annotation queue to act on, from the path.","schema":{"type":"string"},"example":"annq_1"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.annQueueDetailView"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"patch":{"operationId":"patch_o11y_reviews_by_id","summary":"Changes a review queue's name, description or score-config set.","description":"Changes a review queue's name, description or\nscore-config set. A field the request omits is left alone. A name another\nqueue in the same project already uses is a 409; a queue id belonging to\nanother org is a 404.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the annotation queue to update, from the path.","schema":{"type":"string"},"example":"annq_1"}],"requestBody":{"content":{"application/json":{"example":{"id":"annq_1","name":"hallucination review v2"},"schema":{"$ref":"#/components/schemas/o11y.updateQueueIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.annQueueView"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/reviews/{id}/items":{"get":{"operationId":"get_o11y_reviews_by_id_items","summary":"Returns a page of one review queue's items, newest first, optionally filtered to PENDING or COMPLETED.","description":"Returns a page of one review queue's items, newest\nfirst, optionally filtered to PENDING or COMPLETED. A queue id belonging to\nanother org is a 404, never a cross-tenant list.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the annotation queue whose items to list, from the path.","schema":{"type":"string"},"example":"annq_1"},{"name":"status","in":"query","required":false,"description":"Status filters to PENDING or COMPLETED items. Absent returns both.","schema":{"type":"string"},"example":"PENDING"},{"name":"page","in":"query","required":false,"description":"Page is the 1-based page to read. Default 1.","schema":{"format":"int64","type":"integer"}},{"name":"limit","in":"query","required":false,"description":"Limit is how many rows to return. Default 20, capped at 100.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.annItemList"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"post_o11y_reviews_by_id_items","summary":"Enqueues traces, observations or sessions on a review queue.","description":"Enqueues traces, observations or sessions on a review\nqueue. Each item names exactly one object, either by traceId / observationId /\nsessionId or by objectType plus objectId; every item enters PENDING. A queue\nid belonging to another org is a 404.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the annotation queue to add to, from the path.","schema":{"type":"string"},"example":"annq_1"}],"requestBody":{"content":{"application/json":{"example":{"id":"annq_1","items":[{"traceId":"tr_1"}]},"schema":{"$ref":"#/components/schemas/o11y.addItemsIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.annItemsCreated"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/reviews/{id}/items/{itemId}":{"patch":{"operationId":"patch_o11y_reviews_by_id_items_by_itemid","summary":"Moves one queue item between PENDING and COMPLETED and sets its assignee.","description":"Moves one queue item between PENDING and COMPLETED\nand sets its assignee. Completing an item stamps its completedAt. An item that\nexists under a different queue answers the same 404 an unknown item does, and\nso does a queue belonging to another org.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the annotation queue the item belongs to, from the path.","schema":{"type":"string"},"example":"annq_1"},{"name":"itemId","in":"path","required":true,"description":"ItemID is the item to update, from the path.","schema":{"type":"string"},"example":"annqi_1"}],"requestBody":{"content":{"application/json":{"example":{"id":"annq_1","itemId":"annqi_1","status":"COMPLETED"},"schema":{"$ref":"#/components/schemas/o11y.updateItemIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.annItemView"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/roles":{"get":{"operationId":"ListRoles","summary":"Lists every role in the caller's org — the managed ones the platform seeds and the custom ones its admins created.","description":"Lists every role in the caller's org — the managed ones the\nplatform seeds and the custom ones its admins created.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRolesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"CreateRole","summary":"Creates a custom role in the caller's org from a name, an optional description and the transaction groups it grants, answering the new role's id.","description":"Creates a custom role in the caller's org from a name, an optional\ndescription and the transaction groups it grants, answering the new role's id.\n\nNames are lowercase letters and hyphens only, and may not start with the\nreserved managed-role prefix; the runtime refuses anything else.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRoleCreateIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRoleCreateOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/roles/{id}":{"delete":{"operationId":"DeleteRole","summary":"Deletes a custom role.","description":"Deletes a custom role. A role that still has user or\nservice-account assignees, or an auth-domain mapping, is refused; managed\nroles cannot be deleted.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"get":{"operationId":"GetRole","summary":"Returns one role with the transaction groups it grants.","description":"Returns one role with the transaction groups it grants.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRoleOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"UpdateRole","summary":"Replaces a custom role's description and transaction groups.","description":"Replaces a custom role's description and transaction groups.\nBoth fields are mandatory — send an empty string or an empty array to clear\none — and managed roles cannot be edited.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRoleUpdateIn"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/route_policies":{"get":{"operationId":"GetAllRoutePolicies","summary":"Lists the org's route policies.","description":"Lists the org's route policies. Viewer gate.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRoutePoliciesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"CreateRoutePolicy","summary":"Creates a route policy, answering with the stored policy.","description":"Creates a route policy, answering with the stored policy. Admin gate.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.PostableRoutePolicy"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRoutePolicyOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/route_policies/{id}":{"delete":{"operationId":"DeleteRoutePolicyByID","summary":"Removes a route policy, by id.","description":"Removes a route policy, by id. Admin gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"get":{"operationId":"GetRoutePolicyByID","summary":"Returns one route policy, by id.","description":"Returns one route policy, by id. Viewer gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRoutePolicyOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"UpdateRoutePolicy","summary":"Replaces a route policy, by id, answering with the stored policy.","description":"Replaces a route policy, by id, answering with the stored\npolicy. Admin gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRoutePolicyUpdateIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRoutePolicyOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/rules":{"get":{"operationId":"ListRules","summary":"Lists all alert rules with their current evaluation state.","description":"Lists all alert rules with their current evaluation state. Viewer gate.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRulesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"CreateRule","summary":"Creates a new alert rule and answers with the stored rule.","description":"Creates a new alert rule and answers with the stored rule. Editor gate.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRuleOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/rules/test":{"post":{"operationId":"TestRule","summary":"Fires a test notification for a rule definition without saving it, answering with how many series would alert.","description":"Fires a test notification for a rule definition without saving it,\nanswering with how many series would alert. Editor gate.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yTestRuleOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/rules/{id}":{"delete":{"operationId":"DeleteRuleByID","summary":"Removes an alert rule, by id.","description":"Removes an alert rule, by id. Editor gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"get":{"operationId":"GetRuleByID","summary":"Returns one alert rule with its evaluation state, by id.","description":"Returns one alert rule with its evaluation state, by id. Viewer gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRuleOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"patch":{"operationId":"PatchRuleByID","summary":"Applies a partial update to an alert rule, by id, answering with the stored rule — the common toggle for enabling or muting a rule.","description":"Applies a partial update to an alert rule, by id, answering\nwith the stored rule — the common toggle for enabling or muting a rule.\nEditor gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRuleOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"UpdateRuleByID","summary":"Replaces an alert rule's definition, by id.","description":"Replaces an alert rule's definition, by id. Editor gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/rules/{id}/history/filter_keys":{"get":{"operationId":"GetRuleHistoryFilterKeys","summary":"Returns the distinct label keys present in a rule's history entries over the selected range, for building history filters.","description":"Returns the distinct label keys present in a rule's\nhistory entries over the selected range, for building history filters. Viewer gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"startUnixMilli","in":"query","required":false,"description":"StartUnixMilli is the window start, unix milliseconds.","schema":{"format":"int64","type":"integer"}},{"name":"endUnixMilli","in":"query","required":false,"description":"EndUnixMilli is the window end, unix milliseconds.","schema":{"format":"int64","type":"integer"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the keys to those containing it.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many keys come back. Absent means 50, capped at 200.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRuleHistoryFilterKeysOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/rules/{id}/history/filter_values":{"get":{"operationId":"GetRuleHistoryFilterValues","summary":"Returns the distinct values a given label key has taken across a rule's history entries.","description":"Returns the distinct values a given label key has\ntaken across a rule's history entries. Viewer gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"startUnixMilli","in":"query","required":false,"description":"StartUnixMilli is the window start, unix milliseconds.","schema":{"format":"int64","type":"integer"}},{"name":"endUnixMilli","in":"query","required":false,"description":"EndUnixMilli is the window end, unix milliseconds.","schema":{"format":"int64","type":"integer"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the keys to those containing it.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many keys come back. Absent means 50, capped at 200.","schema":{"format":"int64","type":"integer"}},{"name":"name","in":"query","required":true,"description":"Name is the label key whose values to list. Required.","schema":{"type":"string"}},{"name":"existingQuery","in":"query","required":false,"description":"ExistingQuery is a filter expression scoping which values appear.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRuleHistoryFilterValuesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/rules/{id}/history/overall_status":{"get":{"operationId":"GetRuleHistoryOverallStatus","summary":"Returns the overall firing/inactive intervals for a rule over the selected range.","description":"Returns the overall firing/inactive intervals for\na rule over the selected range. Viewer gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"start","in":"query","required":false,"description":"Start is the window start, unix milliseconds. Required by the runtime.","schema":{"format":"int64","type":"integer"}},{"name":"end","in":"query","required":false,"description":"End is the window end, unix milliseconds. Required by the runtime.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRuleHistoryOverallStatusOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"GetOverallStateTransitions","summary":"Returns the overall firing/inactive windows for a rule, for the posted query range.","description":"Returns the overall firing/inactive windows for a\nrule, for the posted query range. Viewer gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRuleHistoryQueryIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yOverallStateTransitionsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/rules/{id}/history/stats":{"get":{"operationId":"GetRuleHistoryStats","summary":"Returns trigger and resolution statistics for a rule over the selected time range, current window against the prior one.","description":"Returns trigger and resolution statistics for a rule over\nthe selected time range, current window against the prior one. Viewer gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"start","in":"query","required":false,"description":"Start is the window start, unix milliseconds. Required by the runtime.","schema":{"format":"int64","type":"integer"}},{"name":"end","in":"query","required":false,"description":"End is the window end, unix milliseconds. Required by the runtime.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRuleHistoryStatsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"GetRuleStats","summary":"Returns trigger and resolution statistics for a rule, current window against the prior one, for the posted query range.","description":"Returns trigger and resolution statistics for a rule, current\nwindow against the prior one, for the posted query range. Viewer gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRuleHistoryQueryIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRuleStatsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/rules/{id}/history/timeline":{"get":{"operationId":"GetRuleHistoryTimeline","summary":"Returns paginated timeline entries for a rule's state transitions, filterable by state and a label expression, cursor-paginated.","description":"Returns paginated timeline entries for a rule's state\ntransitions, filterable by state and a label expression, cursor-paginated. Viewer gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"start","in":"query","required":false,"description":"Start is the window start, unix milliseconds. Required by the runtime.","schema":{"format":"int64","type":"integer"}},{"name":"end","in":"query","required":false,"description":"End is the window end, unix milliseconds. Required by the runtime.","schema":{"format":"int64","type":"integer"}},{"name":"state","in":"query","required":false,"description":"State keeps only entries in one alert state, e.g. firing or normal.","schema":{"type":"string"}},{"name":"filterExpression","in":"query","required":false,"description":"FilterExpression narrows entries to those whose labels match it.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many entries come back. Absent means 50.","schema":{"format":"int64","type":"integer"}},{"name":"order","in":"query","required":false,"description":"Order sorts by time, asc or desc.","schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"description":"Cursor resumes a previous page; opaque, returned as nextCursor.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRuleHistoryTimelineOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"GetRuleStateHistory","summary":"Returns a rule's state-transition timeline for the posted query range, each entry carrying its related-logs or related-traces link.","description":"Returns a rule's state-transition timeline for the posted\nquery range, each entry carrying its related-logs or related-traces link. Viewer gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRuleHistoryQueryIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRuleStateTimelineOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/rules/{id}/history/top_contributors":{"get":{"operationId":"GetRuleHistoryTopContributors","summary":"Returns the label combinations that contributed most to a rule firing over the selected range.","description":"Returns the label combinations that contributed\nmost to a rule firing over the selected range. Viewer gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"start","in":"query","required":false,"description":"Start is the window start, unix milliseconds. Required by the runtime.","schema":{"format":"int64","type":"integer"}},{"name":"end","in":"query","required":false,"description":"End is the window end, unix milliseconds. Required by the runtime.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRuleHistoryContributorsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"GetRuleStateHistoryTopContributors","summary":"Returns the label combinations that contributed most to a rule firing, for the posted query range.","description":"Returns the label combinations that\ncontributed most to a rule firing, for the posted query range. Viewer gate.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRuleHistoryQueryIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRuleStateContributorsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/sentinel/discover":{"post":{"operationId":"post_o11y_sentinel_discover","summary":"Aggregates a project's captured errors into a table — the caller names the filters, the groupings and the aggregations, and gets back the columns and rows they asked for.","description":"Aggregates a project's captured errors into a table — the caller\nnames the filters, the groupings and the aggregations, and gets back the\ncolumns and rows they asked for.\n\nThe project is mandatory and is checked against the caller's own org before it\nscopes anything, so a project id belonging to someone else reads as absent\nrather than as data.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDiscoverIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDiscoverOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/sentinel/events/{id}":{"get":{"operationId":"get_o11y_sentinel_events_by_id","summary":"Returns one captured error event of a project, by its id.","description":"Returns one captured error event of a project, by its id.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the event id.","schema":{"type":"string"}},{"name":"project","in":"query","required":true,"description":"Project is the project the event belongs to, by its id. Required.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySentryEventOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/sentinel/issues":{"get":{"operationId":"get_o11y_sentinel_issues","summary":"Lists the caller's org's grouped error issues, optionally narrowed to one project and one time window, and filtered by status, level, environment, service, a free-text query and a sort.","description":"Lists the caller's org's grouped error issues, optionally\nnarrowed to one project and one time window, and filtered by status, level,\nenvironment, service, a free-text query and a sort.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"status","in":"query","required":false,"description":"Status narrows to one lifecycle state: unresolved, resolved or ignored.","schema":{"type":"string"}},{"name":"level","in":"query","required":false,"description":"Level narrows to one severity, e.g. error, warning, info.","schema":{"type":"string"}},{"name":"environment","in":"query","required":false,"description":"Environment narrows to one deployment environment.","schema":{"type":"string"}},{"name":"serviceName","in":"query","required":false,"description":"ServiceName narrows to one reporting service.","schema":{"type":"string"}},{"name":"query","in":"query","required":false,"description":"Query narrows to issues whose text contains it.","schema":{"type":"string"}},{"name":"sort","in":"query","required":false,"description":"Sort orders the page, e.g. lastSeen, firstSeen, count.","schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"description":"Offset is how many issues to skip. Zero starts at the first.","schema":{"format":"int64","type":"integer"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many issues come back. Zero means the default.","schema":{"format":"int64","type":"integer"}},{"name":"project","in":"query","required":false,"description":"Project narrows the org's issues to one project, by its id.","schema":{"type":"string"}},{"name":"period","in":"query","required":false,"description":"Period is the window to read, relative to now — 1h, 24h, 7d, 14d, 30d.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yErrorIssuesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/sentinel/issues/{id}":{"get":{"operationId":"get_o11y_sentinel_issues_by_id","summary":"Returns one grouped issue of the caller's org with its latest occurrence sample.","description":"Returns one grouped issue of the caller's org with its latest\noccurrence sample.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the issue id.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yErrorGettableIssueOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"put_o11y_sentinel_issues_by_id","summary":"Changes an issue's lifecycle — resolve, ignore, reopen or assign — and returns the updated issue.","description":"Changes an issue's lifecycle — resolve, ignore, reopen or\nassign — and returns the updated issue. Fields left unset are left unchanged.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the issue id.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySentryUpdateIssueIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yErrorIssueOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/sentinel/issues/{id}/events":{"get":{"operationId":"get_o11y_sentinel_issues_by_id_events","summary":"Lists one issue's captured occurrences, scoped to a project — a project is an isolation unit, so the caller declares which project's occurrences to read.","description":"Lists one issue's captured occurrences, scoped to a project\n— a project is an isolation unit, so the caller declares which project's\noccurrences to read.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the issue id.","schema":{"type":"string"}},{"name":"project","in":"query","required":true,"description":"Project is the project whose occurrences to read, by its id. Required.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many occurrences come back. Zero means the default.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySentryIssueEventsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/sentinel/logs":{"get":{"operationId":"get_o11y_sentinel_logs","summary":"Lists a project's captured error events, newest first, optionally narrowed to those whose message or exception text contains a search string.","description":"Lists a project's captured error events, newest first, optionally\nnarrowed to those whose message or exception text contains a search string.","tags":["o11y"],"parameters":[{"name":"project","in":"query","required":true,"description":"Project is the project to read, as its id. Required.","schema":{"type":"string"}},{"name":"query","in":"query","required":false,"description":"Query narrows the page to events whose text contains it.","schema":{"type":"string"}},{"name":"period","in":"query","required":false,"description":"Period is the window to read, relative to now — 1h, 24h, 7d, 14d, 30d.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many events come back.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yLogsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/sentinel/projects":{"get":{"operationId":"get_o11y_sentinel_projects","summary":"Lists the caller's org's Sentry projects — one per product that has reported an error, plus any created by hand.","description":"Lists the caller's org's Sentry projects — one per product\nthat has reported an error, plus any created by hand.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySentryProjectsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"post_o11y_sentinel_projects","summary":"Creates a Sentry project under the caller's org and returns it.","description":"Creates a Sentry project under the caller's org and\nreturns it. Only the name, and optionally a slug and platform, are the caller's\nto set; the org and id are server-assigned. The slug is the product name the\nevent plane stores, so a project reads that product's errors.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySentryPostableProject"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySentryProjectOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/sentinel/projects/{id}":{"delete":{"operationId":"delete_o11y_sentinel_projects_by_id","summary":"Deletes one Sentry project of the caller's org; retained events are not touched.","description":"Deletes one Sentry project of the caller's org; retained\nevents are not touched. Answers 204.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the project id.","schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"get":{"operationId":"get_o11y_sentinel_projects_by_id","summary":"Returns one Sentry project of the caller's org.","description":"Returns one Sentry project of the caller's org.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the project id.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySentryProjectOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/sentinel/stats":{"get":{"operationId":"get_o11y_sentinel_stats","summary":"Returns a project's event-rate timeseries: one bucket per interval over the requested period, counting the events in it.","description":"Returns a project's event-rate timeseries: one bucket per interval over\nthe requested period, counting the events in it.","tags":["o11y"],"parameters":[{"name":"project","in":"query","required":true,"description":"Project is the project to read, as its id. Required.","schema":{"type":"string"}},{"name":"field","in":"query","required":false,"description":"Field is the dimension to count over. Empty counts all events.","schema":{"type":"string"}},{"name":"period","in":"query","required":false,"description":"Period is the window to read, relative to now — 1h, 24h, 7d, 14d, 30d.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yStatsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/sentinel/traces":{"get":{"operationId":"get_o11y_sentinel_traces","summary":"Lists the traces a project's captured errors reference, each with how many errors landed on it, when they started and stopped, and the latest message seen — the entry point for \"which requests are failing\".","description":"Lists the traces a project's captured errors reference, each with how\nmany errors landed on it, when they started and stopped, and the latest\nmessage seen — the entry point for \"which requests are failing\".","tags":["o11y"],"parameters":[{"name":"project","in":"query","required":true,"description":"Project is the project to read, as its id. Required.","schema":{"type":"string"}},{"name":"period","in":"query","required":false,"description":"Period is the window to read, relative to now — 1h, 24h, 7d, 14d, 30d.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many traces come back.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yTracesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/sentinel/traces/{id}":{"get":{"operationId":"get_o11y_sentinel_traces_by_id","summary":"Returns one trace's captured errors for a project — every error event that carried the trace id, in the order the events plane holds them.","description":"Returns one trace's captured errors for a project — every error event\nthat carried the trace id, in the order the events plane holds them.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the trace id.","schema":{"type":"string"}},{"name":"project","in":"query","required":true,"description":"Project is the project the trace's errors belong to. Required.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yTraceOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/service/entry_point_operations":{"post":{"operationId":"post_o11y_service_entry_point_operations","summary":"Returns one service's entry-point operations with the same latency and error profile topOperations reports.","description":"Returns one service's entry-point operations with the\nsame latency and error profile topOperations reports.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yOperationsIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yOperationsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/service/top_level_operations":{"post":{"operationId":"post_o11y_service_top_level_operations","summary":"Maps each service to its entry-point span names — for the one service named in the request, or for every service when none is.","description":"Maps each service to its entry-point span names — for the\none service named in the request, or for every service when none is.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yTopLevelOpsIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/service/top_operations":{"post":{"operationId":"post_o11y_service_top_operations","summary":"Returns one service's heaviest operations in the window, each with p50/p95/p99 latency, how often it ran and how often it errored.","description":"Returns one service's heaviest operations in the window, each\nwith p50/p95/p99 latency, how often it ran and how often it errored.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yOperationsIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yOperationsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/service_accounts":{"get":{"operationId":"ListServiceAccounts","summary":"Lists the caller's org's service accounts.","description":"Lists the caller's org's service accounts.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yServiceAccountsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"CreateServiceAccount","summary":"Creates a service account in the caller's org, answering its id.","description":"Creates a service account in the caller's org,\nanswering its id. The name — a lowercase letter followed by lowercase\nletters, digits or hyphens — becomes the account's email local part.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yServiceAccountCreateIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yServiceAccountCreateOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/service_accounts/me":{"get":{"operationId":"GetMyServiceAccount","summary":"Returns the calling service account itself, with the roles it holds — the self-inspection read for a key-authenticated caller.","description":"Returns the calling service account itself, with the\nroles it holds — the self-inspection read for a key-authenticated caller.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yServiceAccountOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"UpdateMyServiceAccount","summary":"Renames the calling service account.","description":"Renames the calling service account.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yMyServiceAccountUpdateIn"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/service_accounts/{id}":{"delete":{"operationId":"DeleteServiceAccount","summary":"Deletes a service account and revokes every key it holds.","description":"Deletes a service account and revokes every key it\nholds.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"get":{"operationId":"GetServiceAccount","summary":"Returns one service account with the roles it holds.","description":"Returns one service account with the roles it holds.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yServiceAccountOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"UpdateServiceAccount","summary":"Renames a service account.","description":"Renames a service account.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yServiceAccountUpdateIn"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/service_accounts/{id}/keys":{"get":{"operationId":"ListServiceAccountKeys","summary":"Lists a service account's API keys — metadata only, never the secrets.","description":"Lists a service account's API keys — metadata only,\nnever the secrets.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yAPIKeysOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"CreateServiceAccountKey","summary":"Mints an API key for a service account and answers the key's id and its secret — the one time the secret is ever shown.","description":"Mints an API key for a service account and answers\nthe key's id and its secret — the one time the secret is ever shown.\n\nExpiresAt is a unix timestamp in seconds; zero means the key never expires,\nand a timestamp in the past is refused.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yAPIKeyCreateIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yAPIKeyCreateOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/service_accounts/{id}/keys/{fid}":{"delete":{"operationId":"RevokeServiceAccountKey","summary":"Revokes an API key.","description":"Revokes an API key. Revocation is immediate and\npermanent.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"fid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"UpdateServiceAccountKey","summary":"Renames an API key or moves its expiry.","description":"Renames an API key or moves its expiry.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"fid","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yAPIKeyUpdateIn"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/service_accounts/{id}/roles":{"get":{"operationId":"GetServiceAccountRoles","summary":"Lists the roles a service account holds.","description":"Lists the roles a service account holds.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yServiceAccountRolesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"CreateServiceAccountRole","summary":"Assigns a role, named by its id, to a service account.","description":"Assigns a role, named by its id, to a service\naccount.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"RoleID is the id of the role to assign. Required.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yServiceAccountRoleGrantIn"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/service_accounts/{id}/roles/{rid}":{"delete":{"operationId":"DeleteServiceAccountRole","summary":"Removes a role from a service account.","description":"Removes a role from a service account.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"rid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/services":{"post":{"operationId":"post_o11y_services","summary":"Lists the instrumented services seen in the window, each with the request profile of its entry-point spans: p99 and average latency, call and error rates, and the entry-point operations the numbers were computed over.","description":"Lists the instrumented services seen in the window, each with the\nrequest profile of its entry-point spans: p99 and average latency, call and\nerror rates, and the entry-point operations the numbers were computed over.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yServicesIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yServicesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/services/list":{"get":{"operationId":"get_o11y_services_list","summary":"Lists the name of every service the trace store holds, with no window applied — the complete catalog, for pickers and autocomplete.","description":"Lists the name of every service the trace store holds, with no\nwindow applied — the complete catalog, for pickers and autocomplete.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"type":"string"},"type":"array"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/sessions":{"get":{"operationId":"get_o11y_sessions","summary":"List the caller org's LLM sessions","description":"Answers the caller org's LLM-observability sessions — traces grouped by session id on the gen_ai span plane — paged by limit and offset, in the runtime's own envelope, passed through unchanged.\n\nAn org-less caller is refused HERE, at the cloud boundary, before the request reaches the runtime, and the org the runtime then scopes on is that SAME validated tenant. The two cannot disagree: the tenant is minted from the principal's own claim at ingress and a client copy never survives it.\n\nThere is deliberately no session-detail route to pair with this. The runtime serves the list only; detail is composed client-side from this list plus the traces filtered by session, so a caller looking for one is looking for something that was never served rather than something that broke.","tags":["o11y"],"x-app":"o11y","x-public":true}},"/v1/o11y/settings/apdex":{"get":{"operationId":"get_o11y_settings_apdex","summary":"Returns apdex settings for the named services.","description":"Returns apdex settings for the named services.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"services","in":"query","required":false,"description":"Services are the service names, comma separated.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yApdexOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"post_o11y_settings_apdex","summary":"Sets one service's apdex threshold and the status codes excluded from its score.","description":"Sets one service's apdex threshold and the status codes excluded\nfrom its score.\n\nAdmin only, as the mux tree has always gated it (AdminAccess); the runtime's\nown gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yApdexSetIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yApdexSetOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/settings/ttl":{"get":{"operationId":"get_o11y_settings_ttl","summary":"Returns the org's current retention policy: default TTL, custom per-label rules, and cold-storage settings where configured.","description":"Returns the org's current retention policy: default TTL, custom\nper-label rules, and cold-storage settings where configured.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRetentionOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"post_o11y_settings_ttl","summary":"Sets the org's retention policy for one signal: the default TTL in days, ordered per-label retention rules, and optional cold-storage settings.","description":"Sets the org's retention policy for one signal: the default TTL\nin days, ordered per-label retention rules, and optional cold-storage\nsettings.\n\nAdmin only, as the mux tree has always gated it (AdminAccess); the runtime's\nown gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRetentionSetIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yRetentionSetOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/span_mapper_groups":{"get":{"operationId":"ListSpanMapperGroups","summary":"Lists the caller's org's mapping groups, optionally only the enabled ones.","description":"Lists the caller's org's mapping groups, optionally only the\nenabled ones.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"enabled","in":"query","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySpanMapperGroupsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"CreateSpanMapperGroup","summary":"Creates a mapping group: the name it is known by, the span and resource attributes whose presence selects a span into it, and whether it is on.","description":"Creates a mapping group: the name it is known by, the\nspan and resource attributes whose presence selects a span into it, and\nwhether it is on.\n\nCallers need the admin role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.PostableSpanMapperGroup"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySpanMapperGroupOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/span_mapper_groups/{groupId}":{"delete":{"operationId":"DeleteSpanMapperGroup","summary":"Deletes a mapping group and every mapper under it.","description":"Deletes a mapping group and every mapper under it.\n\nCallers need the admin role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"groupId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"patch":{"operationId":"UpdateSpanMapperGroup","summary":"Changes a group's name, condition or enabled state.","description":"Changes a group's name, condition or enabled state.\nEvery field is optional and only the ones sent are applied.\n\nCallers need the admin role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"groupId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySpanMapperGroupUpdateIn"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/span_mapper_groups/{groupId}/span_mappers":{"get":{"operationId":"ListSpanMappers","summary":"Lists the mappers belonging to one group, in the order they are applied.","description":"Lists the mappers belonging to one group, in the order they are\napplied.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"groupId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySpanMappersOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"CreateSpanMapper","summary":"Adds a mapper to a group: which field context it reads, the move or copy it performs, and whether it is on.","description":"Adds a mapper to a group: which field context it reads, the\nmove or copy it performs, and whether it is on.\n\nCallers need the admin role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"groupId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySpanMapperCreateIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySpanMapperOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/span_mapper_groups/{groupId}/span_mappers/{mapperId}":{"delete":{"operationId":"DeleteSpanMapper","summary":"Deletes one mapper from a group.","description":"Deletes one mapper from a group.\n\nCallers need the admin role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"groupId","in":"path","required":true,"schema":{"type":"string"}},{"name":"mapperId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"patch":{"operationId":"UpdateSpanMapper","summary":"Changes a mapper's field context, config or enabled state.","description":"Changes a mapper's field context, config or enabled state.\nEvery field is optional and only the ones sent are applied.\n\nCallers need the admin role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"groupId","in":"path","required":true,"schema":{"type":"string"}},{"name":"mapperId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySpanMapperUpdateIn"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/span_percentile":{"post":{"operationId":"post_o11y_span_percentile","summary":"Places one span's duration among its peers: the p50/p90/p99 durations of like spans, and the percentile the given duration lands at.","description":"Places one span's duration among its peers: the p50/p90/p99\ndurations of like spans, and the percentile the given duration lands at.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySpanPercentileIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySpanPercentileOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/statefulsets/attribute_keys":{"get":{"operationId":"get_o11y_statefulsets_attribute_keys","summary":"Lists the metric attribute keys Kubernetes statefulsets report, for building statefulset filters.","description":"Lists the metric attribute keys Kubernetes\nstatefulsets report, for building statefulset filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the keys must appear on.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the keys to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many keys come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeKeysOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/statefulsets/attribute_values":{"get":{"operationId":"get_o11y_statefulsets_attribute_values","summary":"Lists the values one statefulset attribute key has taken, for building statefulset filters.","description":"Lists the values one statefulset attribute key\nhas taken, for building statefulset filters.","tags":["o11y"],"parameters":[{"name":"dataSource","in":"query","required":false,"description":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","schema":{"type":"string"}},{"name":"aggregateOperator","in":"query","required":false,"description":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","schema":{"type":"string"}},{"name":"aggregateAttribute","in":"query","required":false,"description":"AggregateAttribute is the metric the values must appear on.","schema":{"type":"string"}},{"name":"attributeKey","in":"query","required":false,"description":"AttributeKey is the key whose values to list.","schema":{"type":"string"}},{"name":"filterAttributeKeyDataType","in":"query","required":false,"description":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","schema":{"type":"string"}},{"name":"searchText","in":"query","required":false,"description":"SearchText narrows the values to those containing it.","schema":{"type":"string"}},{"name":"tagType","in":"query","required":false,"description":"TagType narrows the search to one kind of key — tag or resource.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many values come back. Absent means 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yInfraAttributeValuesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/statefulsets/list":{"post":{"operationId":"post_o11y_statefulsets_list","summary":"Lists Kubernetes statefulsets over a time range, each with the CPU and memory its pods used against request and limit, desired and available replica counts, restarts and attributes; filterable, groupable and paginated.","description":"Lists Kubernetes statefulsets over a time range, each with\nthe CPU and memory its pods used against request and limit, desired and\navailable replica counts, restarts and attributes; filterable, groupable and\npaginated.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.StatefulSetListRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yStatefulSetListOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/stats":{"get":{"operationId":"get_o11y_stats","summary":"Returns the collected usage statistics for the caller's org, as the stats reporter aggregates them — a map whose keys are the reporter's own counter names.","description":"Returns the collected usage statistics for the caller's org, as the\nstats reporter aggregates them — a map whose keys are the reporter's own\ncounter names.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yOrgStatsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/status":{"get":{"operationId":"get_o11y_status","summary":"Reports whether a product's service is live: an in-cluster health probe with its measured latency, fused with the per-replica up inventory.","description":"Reports whether a product's service is live: an in-cluster\nhealth probe with its measured latency, fused with the per-replica up\ninventory. Infra health is not tenant-partitioned — a service is up or down\nfor everyone — so any validated caller is served, but an unvalidated one is\nrefused. A product with no backing workload answers down/unknown-service\nwithout probing anything; a malformed slug is a 400.","tags":["o11y"],"parameters":[{"name":"product","in":"query","required":false,"description":"Product is the console product slug to probe, e.g. \"kms\". Required.","schema":{"type":"string"},"example":"kms"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.statusResult"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/substitute_vars":{"post":{"operationId":"post_o11y_substitute_vars","summary":"Substitutes a query's variables and returns the resolved request, without running it — what a dashboard does before it queries.","description":"Substitutes a query's variables and returns the\nresolved request, without running it — what a dashboard does before it\nqueries.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.QueryRangeRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11ySubstituteVarsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/summary":{"get":{"operationId":"get_o11y_summary","summary":"Reports whether the platform is up.","description":"Reports whether the platform is up. It returns the public status\ndocument: the incidents currently open against Hanzo's own services, derived\nfrom the fleet health probes, plus the address of the human status page. No\nauthentication is required and no tenant data is involved — the answer is the\nsame for every caller.\n\nA service that fails its health probe becomes one incident naming that service.\nWhen the availability source itself cannot be read the endpoint answers 503\nrather than an empty incident list, because \"we cannot tell\" and \"everything is\nfine\" are different answers and only one of them is true.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.StatusSummary"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/testChannel":{"post":{"operationId":"TestChannelDeprecated","summary":"Sends a test notification to the posted receiver.","description":"Sends a test notification to the posted receiver. The\nlegacy path; prefer /channels/test. Editor gate.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.alertmanagertypes.Receiver"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/testRule":{"post":{"operationId":"TestRuleNotification","summary":"Fires a test notification for the posted rule definition and answers with how many series alerted and a status message.","description":"Fires a test notification for the posted rule definition\nand answers with how many series alerted and a status message. The legacy\npath; prefer /rules/test. Editor gate.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yTestNotificationOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/third-party-apis/overview/domain":{"post":{"operationId":"post_o11y_third-party-apis_overview_domain","summary":"Returns one external domain's endpoint-level breakdown — each endpoint with its rate, error and latency columns over the window.","description":"Returns one external domain's endpoint-level breakdown — each\nendpoint with its rate, error and latency columns over the window.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDomainsIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDomainsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/third-party-apis/overview/list":{"post":{"operationId":"post_o11y_third-party-apis_overview_list","summary":"Lists the external domains the instrumented services call, with request rate, error percentage and latency per domain.","description":"Lists the external domains the instrumented services call, with\nrequest rate, error percentage and latency per domain. Rows whose domain is\na bare IP address are dropped unless show_ip asks for them.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDomainsIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDomainsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/trace-funnels/analytics/error-traces":{"post":{"operationId":"GetDraftFunnelErrorTraces","summary":"Returns the errored traces through a step transition of a funnel described inline.","description":"Returns the errored traces through a step transition of\na funnel described inline.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDraftFunnelIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelRowsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/trace-funnels/analytics/overview":{"post":{"operationId":"GetDraftFunnelOverview","summary":"Returns the conversion overview of a funnel described inline.","description":"Returns the conversion overview of a funnel described\ninline.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDraftFunnelIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelRowsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/trace-funnels/analytics/slow-traces":{"post":{"operationId":"GetDraftFunnelSlowTraces","summary":"Returns the slowest traces through a step transition of a funnel described inline.","description":"Returns the slowest traces through a step transition of\na funnel described inline.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDraftFunnelIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelRowsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/trace-funnels/analytics/steps":{"post":{"operationId":"GetDraftFunnelStepMetrics","summary":"Returns the per-step metrics of a funnel described inline.","description":"Returns the per-step metrics of a funnel described inline.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDraftFunnelIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelRowsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/trace-funnels/analytics/steps/overview":{"post":{"operationId":"GetDraftFunnelStepOverview","summary":"Returns the conversion between two steps of a funnel described inline.","description":"Returns the conversion between two steps of a funnel\ndescribed inline.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDraftFunnelIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelRowsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/trace-funnels/analytics/validate":{"post":{"operationId":"ValidateDraftFunnelTraces","summary":"Lists the traces that match a funnel described inline — the builder's \"try this\" before anything is saved.","description":"Lists the traces that match a funnel described inline —\nthe builder's \"try this\" before anything is saved.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDraftFunnelIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelRowsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/trace-funnels/list":{"get":{"operationId":"ListTraceFunnels","summary":"Lists the caller's org's funnels, each with its steps and who last touched it.","description":"Lists the caller's org's funnels, each with its steps and who last\ntouched it.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/trace-funnels/new":{"post":{"operationId":"CreateTraceFunnel","summary":"Creates an empty funnel with a name, answering the funnel it created.","description":"Creates an empty funnel with a name, answering the funnel it\ncreated. Steps are added afterwards with the steps update.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelCreateIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/trace-funnels/steps/update":{"put":{"operationId":"UpdateTraceFunnelSteps","summary":"Replaces a funnel's steps — the funnel is named in the body rather than the path — and answers the funnel as it now stands.","description":"Replaces a funnel's steps — the funnel is named in the body\nrather than the path — and answers the funnel as it now stands. A name or\ndescription sent alongside is applied too; an empty one leaves it as it was.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelStepsUpdateIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/trace-funnels/{funnel_id}":{"delete":{"operationId":"DeleteTraceFunnel","summary":"Deletes a funnel.","description":"Deletes a funnel. The answer carries no data — the runtime\nacknowledges with the success envelope alone, which is what this Out says.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"funnel_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelDeleteOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"get":{"operationId":"GetTraceFunnel","summary":"Returns one funnel with its steps.","description":"Returns one funnel with its steps.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"funnel_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"UpdateTraceFunnel","summary":"Renames a funnel or rewrites its description, answering the funnel as it now stands.","description":"Renames a funnel or rewrites its description, answering the\nfunnel as it now stands.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"funnel_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelUpdateIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/trace-funnels/{funnel_id}/analytics/error-traces":{"post":{"operationId":"GetTraceFunnelErrorTraces","summary":"Returns the errored traces through a step transition of a saved funnel — the entry point for \"why is this step failing\".","description":"Returns the errored traces through a step transition of a\nsaved funnel — the entry point for \"why is this step failing\".","tags":["o11y"],"parameters":[{"name":"funnel_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelStepWindowIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelRowsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/trace-funnels/{funnel_id}/analytics/overview":{"post":{"operationId":"GetTraceFunnelOverview","summary":"Returns a saved funnel's conversion overview over a window: how many entered, how many converted, the rate and the latency.","description":"Returns a saved funnel's conversion overview over a window:\nhow many entered, how many converted, the rate and the latency.","tags":["o11y"],"parameters":[{"name":"funnel_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelStepWindowIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelRowsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/trace-funnels/{funnel_id}/analytics/slow-traces":{"post":{"operationId":"GetTraceFunnelSlowTraces","summary":"Returns the slowest traces through a step transition of a saved funnel — the entry point for \"why is this step slow\".","description":"Returns the slowest traces through a step transition of a\nsaved funnel — the entry point for \"why is this step slow\".","tags":["o11y"],"parameters":[{"name":"funnel_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelStepWindowIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelRowsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/trace-funnels/{funnel_id}/analytics/steps":{"post":{"operationId":"GetTraceFunnelStepMetrics","summary":"Returns a saved funnel's per-step metrics over a window — the counts and latencies at each step, in step order.","description":"Returns a saved funnel's per-step metrics over a window — the\ncounts and latencies at each step, in step order.","tags":["o11y"],"parameters":[{"name":"funnel_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelWindowIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelRowsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/trace-funnels/{funnel_id}/analytics/steps/overview":{"post":{"operationId":"GetTraceFunnelStepOverview","summary":"Returns the conversion between two named steps of a saved funnel — the step-to-step drill-down behind the overview.","description":"Returns the conversion between two named steps of a saved\nfunnel — the step-to-step drill-down behind the overview.","tags":["o11y"],"parameters":[{"name":"funnel_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelStepWindowIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelRowsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/trace-funnels/{funnel_id}/analytics/validate":{"post":{"operationId":"ValidateTraceFunnelTraces","summary":"Lists the traces that match a saved funnel over a window — the read that answers \"is this funnel finding anything at all\".","description":"Lists the traces that match a saved funnel over a window — the\nread that answers \"is this funnel finding anything at all\".","tags":["o11y"],"parameters":[{"name":"funnel_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelWindowIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFunnelRowsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/traces":{"get":{"operationId":"get_o11y_traces","summary":"Lists the caller org's recent traces — one row per trace with its span count and wall-clock duration, most recently active first.","description":"Lists the caller org's recent traces — one row per trace with\nits span count and wall-clock duration, most recently active first. This is\nthe trace SEARCH: it is where a trace id comes from, and the spans behind any\nrow are then read from GET /v1/o11y/traces/{traceId}. Every row belongs to the\ncaller's own org — the tenant is the validated principal, never an input, and\nthere is no administrator widening, because a trace list is a tenant's records\nrather than a rollup over them. An unreachable telemetry store answers 503\nrather than an empty page, because \"no traces\" and \"cannot see the traces\" are\ndifferent facts and only one of them is about the caller's system.","tags":["o11y"],"parameters":[{"name":"range","in":"query","required":false,"description":"Range is the window in seconds, counted back from now over each trace's\nlast activity. Default 3600, capped at 604800 (7d).","schema":{"format":"int64","type":"integer"},"example":3600},{"name":"limit","in":"query","required":false,"description":"Limit is how many traces to return. Default 50, capped at 500.","schema":{"format":"int64","type":"integer"},"example":50},{"name":"minDurationMs","in":"query","required":false,"description":"MinDurationMs keeps only traces that lasted at least this many\nmilliseconds. Zero or absent keeps every trace in the window.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.tracesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/traces/fields":{"get":{"operationId":"GetTraceFields","summary":"Returns the trace field catalog: the span fields already selected as indexed columns, and the interesting ones seen in the data that could be.","description":"Returns the trace field catalog: the span fields already selected\nas indexed columns, and the interesting ones seen in the data that could be.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFieldCatalogOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"post":{"operationId":"UpdateTraceField","summary":"Changes how one span field is stored — selects or deselects it as a materialized column and tunes its index — and echoes the setting back.","description":"Changes how one span field is stored — selects or deselects\nit as a materialized column and tunes its index — and echoes the setting back.\n\nCallers need the editor role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFieldSetting"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yFieldSetting"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/traces/{traceId}":{"get":{"operationId":"SearchTraces","summary":"Returns one trace's spans as a column/row table, optionally centred on a span and walked a fixed number of levels up and down from it — the read the trace explorer opens a trace with.","description":"Returns one trace's spans as a column/row table, optionally\ncentred on a span and walked a fixed number of levels up and down from it —\nthe read the trace explorer opens a trace with.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"traceId","in":"path","required":true,"schema":{"type":"string"}},{"name":"spanId","in":"query","required":false,"schema":{"type":"string"}},{"name":"levelUp","in":"query","required":false,"schema":{"format":"int64","type":"integer"}},{"name":"levelDown","in":"query","required":false,"schema":{"format":"int64","type":"integer"}},{"name":"spanRenderLimit","in":"query","required":false,"schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/o11y.O11yTraceSpanWindow"},"type":"array"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/traces/{traceId}/aggregations":{"post":{"operationId":"GetTraceAggregations","summary":"Computes span aggregations over one trace — span count, duration or share of execution time — grouped by the resource field each aggregation names.","description":"Computes span aggregations over one trace — span count,\nduration or share of execution time — grouped by the resource field each\naggregation names.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"traceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yTraceAggregationsIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yTraceAggregationsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/traces/{traceId}/flamegraph":{"post":{"operationId":"GetFlamegraph","summary":"Returns a trace's flamegraph: spans bucketed by depth level, each level ordered as it is drawn, around the selected span.","description":"Returns a trace's flamegraph: spans bucketed by depth level,\neach level ordered as it is drawn, around the selected span.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"traceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yTraceFlamegraphIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yTraceFlamegraphOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/traces/{traceId}/waterfall":{"post":{"operationId":"GetWaterfallV4","summary":"Returns a trace's waterfall: every span when the trace is small enough, a capped window around the selected span when it is not, with the uncollapsed subtrees the caller asked to keep open.","description":"Returns a trace's waterfall: every span when the trace is\nsmall enough, a capped window around the selected span when it is not, with\nthe uncollapsed subtrees the caller asked to keep open.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"traceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yTraceWaterfallIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yTraceWaterfallOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/usage":{"get":{"operationId":"get_o11y_usage","summary":"Returns ingestion usage counts bucketed over the requested window, optionally narrowed to one service.","description":"Returns ingestion usage counts bucketed over the requested window,\noptionally narrowed to one service.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"start","in":"query","required":true,"description":"Start is the window start, as epoch nanoseconds. Required.","schema":{"type":"string"}},{"name":"end","in":"query","required":true,"description":"End is the window end, as epoch nanoseconds. Required.","schema":{"type":"string"}},{"name":"step","in":"query","required":false,"description":"Step is the bucket width in seconds. The runtime requires it.","schema":{"format":"int64","type":"integer"}},{"name":"service","in":"query","required":false,"description":"Service narrows usage to one service. Empty covers all.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/o11y.O11yUsageItem"},"type":"array"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/user/preferences":{"get":{"operationId":"ListUserPreferences","summary":"Lists every preference of the calling user, each with its current and default value.","description":"Lists every preference of the calling user, each with\nits current and default value. Viewer gate.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yPreferencesOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/user/preferences/{name}":{"get":{"operationId":"GetUserPreference","summary":"Returns one preference of the calling user, by name.","description":"Returns one preference of the calling user, by name.\nViewer gate.","tags":["o11y"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yPreferenceOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"UpdateUserPreference","summary":"Sets one preference of the calling user, by name.","description":"Sets one preference of the calling user, by name.\nViewer gate.","tags":["o11y"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yUpdatablePreference"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/users/me":{"get":{"operationId":"GetMyUser","summary":"Returns the calling user together with every role they hold.","description":"Returns the calling user together with every role they hold. Open\nto any authenticated caller.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yUserOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/users/me/dashboards":{"get":{"operationId":"ListDashboardsForUserV2","summary":"Is dashboardListV2 personalized for the calling user: each dashboard carries the caller's pinned state, and pinned dashboards float to the top of the requested ordering.","description":"Is dashboardListV2 personalized for the calling user:\neach dashboard carries the caller's pinned state, and pinned dashboards float to\nthe top of the requested ordering. Supports the same filter DSL, sort, order and\npagination.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"query","in":"query","required":false,"description":"Query is the filter DSL over dashboard columns and tags, e.g.\n`name:cpu source:user`. Empty lists everything.","schema":{"type":"string"}},{"name":"sort","in":"query","required":false,"description":"Sort is the sort field: updated_at, created_at or name. Empty sorts by\nupdated_at.","schema":{"type":"string"}},{"name":"order","in":"query","required":false,"description":"Order is the sort direction: asc or desc. Empty orders desc.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many dashboards come back. Zero means the default of 20;\nthe runtime caps it at 200.","schema":{"format":"int64","type":"integer"}},{"name":"offset","in":"query","required":false,"description":"Offset is how many dashboards to skip for pagination.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDashboardListForUserOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/users/me/dashboards/{id}/pins":{"delete":{"operationId":"UnpinDashboardV2","summary":"Removes the caller's pin for a dashboard.","description":"Removes the caller's pin for a dashboard. Idempotent —\nunpinning a dashboard that was not pinned still succeeds.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource id from the path.","schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"PinDashboardV2","summary":"Pins a dashboard for the calling user.","description":"Pins a dashboard for the calling user. A user can pin at most ten\ndashboards; pinning at the limit refuses with the runtime's conflict. Re-pinning\nan already-pinned dashboard is a no-op success. Pinning mutates only the caller's\npin list, not the dashboard, so a viewer may pin what a viewer may read.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource id from the path.","schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/variables/query":{"post":{"operationId":"post_o11y_variables_query","summary":"Evaluates a dashboard variable query and returns the values the variable may take.","description":"Evaluates a dashboard variable query and returns the values the\nvariable may take.\n\nCallers need the viewer role; the runtime's own gate enforces it.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDashboardVarsIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yDashboardVarsOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/version":{"get":{"operationId":"get_o11y_version","summary":"Reports the running build: its version, whether an enterprise edition is present (\"N\" in this build), and whether first-user setup has completed.","description":"Reports the running build: its version, whether an enterprise\nedition is present (\"N\" in this build), and whether first-user setup has\ncompleted.\n\nOpen by design; the runtime's own gate is OpenAccess.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yVersionOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/zeus/hosts":{"get":{"operationId":"GetHosts","summary":"Returns the deployment's host info from Zeus.","description":"Returns the deployment's host info from Zeus. Viewer gate.","tags":["o11y"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.O11yGettableHostOut"}}},"description":"ok"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true},"put":{"operationId":"PutHost","summary":"Records the deployment's host in Zeus, overwriting any prior one.","description":"Records the deployment's host in Zeus, overwriting any prior one.\nAdmin gate.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.PostableHost"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/o11y/zeus/profiles":{"put":{"operationId":"PutProfile","summary":"Records the deployment's profile in Zeus — how the team uses observability today and what they plan — overwriting any prior one.","description":"Records the deployment's profile in Zeus — how the team uses\nobservability today and what they plan — overwriting any prior one. Admin\ngate.","tags":["o11y"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/o11y.PostableProfile"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approval"}}},"description":"held for approval"},"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"o11y","x-public":true,"x-tool":true}},"/v1/openapi.json":{"get":{"operationId":"get_openapi.json","summary":"The API description this SDK was generated from","description":"Serves the OpenAPI document for the routes this process actually answers — generated from the live router at request time, not from a checked-in file that can disagree with it.\n\nOn an app it is that app's own surface; on the fleet's public endpoint it is the composed document for every mounted app. Unauthenticated by design: a client has to be able to read the contract before it holds a credential, and the document grants nothing.\n\nRendered once and served as bytes thereafter, so the route table's immutability is what makes a repeat request a memcpy rather than a re-encode of a megabyte document.\n\nThe whole document is megabytes, so ask for less. ?capability=\u003cname\u003e returns only that capability's operations and the schemas they reach (?tag=\u003cname\u003e is the same filter); ?operation=\u003coperationId\u003e returns one operation; ?path=\u003cprefix\u003e returns the operations whose address starts with that prefix. They combine. A slice is a valid document on its own. GET /v1 lists the capabilities and GET /v1/\u003cname\u003e lists one capability's operations, so a reader can walk from the index down to a single schema without fetching the rest. A query nothing matches is 404.","tags":["openapi"],"security":[],"x-app":"openapi","x-public":true}},"/v1/openapi/commands":{"get":{"operationId":"get_openapi_commands","summary":"Every operation this API answers, as a command","description":"The command projection of the OpenAPI document at /v1/openapi.json — each operation reduced to what running it by name needs: its service and command token, its method and path, the prose lifted from the handler, its path parameters as positional arguments and its remaining inputs as typed flags.\n\nIt is a separate address for one measured reason: the fleet document is megabytes and a command palette cannot load it, while this projection of the same operations is several times smaller because it carries no schemas, responses or components.\n\nUnauthenticated by design, exactly as the document it derives from: a client has to be able to read the contract before it holds a credential, and a list of operation names grants nothing. The list is TOTAL and is never filtered by caller — what you may run is decided per request by the authorizer, on the decoded input, so a filtered list would be a second claim about permission that is free to be wrong.\n\nRendered once and served as bytes thereafter, under a strong ETag.","tags":["openapi"],"security":[],"x-app":"openapi","x-public":true}},"/v1/patent/approvals":{"get":{"operationId":"get_patent_approvals","summary":"Returns the decision trail — each person's current word on each disclosure.","description":"Returns the decision trail — each person's current word on\neach disclosure. ?disclosure= narrows to one document.","tags":["patent"],"parameters":[{"name":"disclosure","in":"query","required":false,"description":"Disclosure narrows to the decisions on one document.","schema":{"type":"string"}},{"name":"project","in":"query","required":false,"description":"Project narrows to one project.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patent.approvalsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patent","x-public":true,"x-tool":true},"post":{"operationId":"post_patent_approvals","summary":"Appends one person's decision about one disclosure.","description":"Appends one person's decision about one disclosure. The\napprover is the validated principal and nothing else, so no caller records a\nsign-off on someone else's behalf — which is the only way this field would be\nworth reading.","tags":["patent"],"requestBody":{"content":{"application/json":{"example":{"approvals":[{"comment":"research log reviewed, the mechanism is ours","decision":"approved","disclosure_id":"router-v2","role":"cto"}]},"schema":{"$ref":"#/components/schemas/patent.approvalBatch"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patent.patentWriteOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patent","x-public":true,"x-tool":true}},"/v1/patent/disclosures":{"get":{"operationId":"get_patent_disclosures","summary":"Returns the canonical disclosures, each carrying its current approvals.","description":"Returns the canonical disclosures, each carrying its\ncurrent approvals.","tags":["patent"],"parameters":[{"name":"id","in":"query","required":false,"description":"ID reads one disclosure.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Status narrows to one status.","schema":{"type":"string"}},{"name":"project","in":"query","required":false,"description":"Project narrows to one project.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patent.discsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patent","x-public":true,"x-tool":true},"post":{"operationId":"post_patent_disclosures","summary":"Appends the assembled document and the record ids it rests on.","description":"Appends the assembled document and the record ids it\nrests on. The document is a rendering of what the log already holds, and its\ncitations are what let a reader check it instead of taking it.","tags":["patent"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patent.disclosureBatch"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patent.patentWriteOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patent","x-public":true,"x-tool":true}},"/v1/patent/grants":{"post":{"operationId":"post_patent_grants","summary":"Makes the decision a recording never implied: whether an idea, implementation or disclosure stays private to its author's project, opens to the org, or goes public.","description":"Makes the decision a recording never implied: whether an\nidea, implementation or disclosure stays private to its author's project, opens\nto the org, or goes public. Publication of a conception entry is a\ndisclosure under 35 U.S.C. §102 in every jurisdiction that reads it that way,\nso it is always a separate call and never a side effect of writing one down.","tags":["patent"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patent.grantIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patent.patentGrantOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patent","x-public":true,"x-tool":true}},"/v1/patent/health":{"get":{"operationId":"get_patent_health","summary":"Reports what this deployment actually guarantees about the records it keeps, in honest states.","description":"Reports what this deployment actually guarantees about the\nrecords it keeps, in honest states. Anchored and durable are the two that\nchange what a record is worth, and an unwired one reads as unwired rather than\nas a green light.","tags":["patent"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patent.patentHealth"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patent","x-public":true,"x-tool":true}},"/v1/patent/ideas":{"get":{"operationId":"get_patent_ideas","summary":"Returns the caller org's canonical conception entries, oldest appended first, which is the order the log says they were thought.","description":"Returns the caller org's canonical conception entries, oldest\nappended first, which is the order the log says they were thought. ?id= narrows\nto one, ?kind= to one kind, ?project= to one project.","tags":["patent"],"parameters":[{"name":"id","in":"query","required":false,"description":"ID reads one entry, which is how a single idea is addressed — there is no\nsecond route for it.","schema":{"type":"string"}},{"name":"kind","in":"query","required":false,"description":"Kind narrows to one kind of conception entry.","schema":{"type":"string"}},{"name":"project","in":"query","required":false,"description":"Project narrows to one project; empty reads the org's whole set.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patent.ideasOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patent","x-public":true,"x-tool":true},"post":{"operationId":"post_patent_ideas","summary":"Appends conception entries.","description":"Appends conception entries. A write states the idea and\nnothing else: the project, the author, the clock, the append order and the\ncontent digest are all the server's, and a correction appends a version rather\nthan editing the entry — which is the property that makes any of it usable as\nevidence at all.","tags":["patent"],"requestBody":{"content":{"application/json":{"example":{"ideas":[{"id":"route-by-queue-depth","kind":"mechanism","statement":"..."}]},"schema":{"$ref":"#/components/schemas/patent.ideaBatch"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patent.patentWriteOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patent","x-public":true,"x-tool":true}},"/v1/patent/implementations":{"get":{"operationId":"get_patent_implementations","summary":"Returns the canonical implementation records with their citations.","description":"Returns the canonical implementation records with\ntheir citations. ?idea= is the query the record exists to answer: which\nartifacts rest on this one conception entry.","tags":["patent"],"parameters":[{"name":"id","in":"query","required":false,"description":"ID reads one implementation.","schema":{"type":"string"}},{"name":"idea","in":"query","required":false,"description":"Idea narrows to implementations citing one conception entry — which is\nhow a correction finds every artifact built on the idea it invalidates.","schema":{"type":"string"}},{"name":"project","in":"query","required":false,"description":"Project narrows to one project.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patent.implsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patent","x-public":true,"x-tool":true},"post":{"operationId":"post_patent_implementations","summary":"Appends the machine's half of the record, and the idea citation is the load-bearing field: it is what lets a reader see that the conception came first.","description":"Appends the machine's half of the record, and the\nidea citation is the load-bearing field: it is what lets a reader see that the\nconception came first. An entry citing no idea is refused rather than filed.","tags":["patent"],"requestBody":{"content":{"application/json":{"example":{"implementations":[{"git_sha":"...","id":"router-v2","idea_ids":["route-by-queue-depth"],"model":"zen6-coder"}]},"schema":{"$ref":"#/components/schemas/patent.implBatch"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patent.patentWriteOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patent","x-public":true,"x-tool":true}},"/v1/patent/proof":{"get":{"operationId":"get_patent_proof","summary":"Folds the caller's record set and answers the ordering question over it.","description":"Folds the caller's record set and answers the ordering question\nover it.\n\n?disclosure= proves one document's set, ?idea= proves one entry and everything\nciting it, and neither proves the whole org. The answer is computed per request\nand writes nothing.","tags":["patent"],"parameters":[{"name":"disclosure","in":"query","required":false,"description":"Disclosure folds the record set one document rests on, and reports on\nthat set alone — which is what an attorney asks for.","schema":{"type":"string"}},{"name":"idea","in":"query","required":false,"description":"Idea narrows to the one entry and the artifacts citing it.","schema":{"type":"string"}},{"name":"project","in":"query","required":false,"description":"Project narrows inside the org; empty reads the caller's scope.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patent.PatentProof"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patent","x-public":true,"x-tool":true}},"/v1/patent/timeline":{"get":{"operationId":"get_patent_timeline","summary":"Returns every retained version of one entry, in append order.","description":"Returns every retained version of one entry, in append\norder. ?id= names it and ?kind= says which log; a retraction is shown as the\nwithdrawal it is rather than hidden.","tags":["patent"],"parameters":[{"name":"id","in":"query","required":false,"description":"ID is the entry's stable id. Required.","schema":{"type":"string"}},{"name":"kind","in":"query","required":false,"description":"Kind is idea, implementation or disclosure — which log to read.","schema":{"type":"string"}},{"name":"project","in":"query","required":false,"description":"Project narrows inside the org; empty is the caller's own scope.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patent.PatentTimeline"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patent","x-public":true,"x-tool":true}},"/v1/patrol/alarm":{"post":{"operationId":"post_patrol_alarm","summary":"Takes one activation.","description":"Takes one activation. It records the activation whatever happens, then\nmatches a site — the one the caller named, else the one whose account number\nreported — and on a match opens an incident in state received with that site's\ntier and SLA, puts the site into alarm, raises a red feed row and tells the\ncontrollers. An activation that matches no site is still recorded, raises an\namber row, and answers 202: an activation is never dropped.\n\nIt admits the receiving centre's own credential and a controller keying one in\nby hand. The centre holds the `centre` role its tenant granted it, which posts\nan activation and reads nothing, like every other identity here.\n\nThe centre's own reference identifies the activation while the response it\nopened is still running, so a redelivery is answered with that response rather\nthan dispatching a second unit. Centres recycle references, so once the\nresponse has closed the same one is the next activation.","tags":["patrol"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolAlarmIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolAlarmOut"}}},"description":"created"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolAlarmOut"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/camera":{"get":{"operationId":"get_patrol_camera","summary":"Lists the cameras a caller may OPEN.","description":"Lists the cameras a caller may OPEN. A row somebody can never reach is\na catalogue of a customer's premises and nothing else, so the admission the\nstream enforces is asked here too rather than left to differ from it.\n\nThe stream credential is not part of a camera row — it is a KMS path the\ndocument store never holds — so what comes back says where a camera is and\nnever how to reach it.","tags":["patrol"],"parameters":[{"name":"site","in":"query","required":false,"description":"Site narrows the list to one site by document name. Empty lists every\ncamera.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolCameraList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/camera/{name}/stream":{"get":{"operationId":"get_patrol_camera_by_name_stream","summary":"Mints a short-lived way in to one camera.","description":"Mints a short-lived way in to one camera.\n\nThe credential is kept in KMS, at the one place a camera's credential is kept\n— the org's own patrol namespace, named for the camera — and what comes back\nis minted from it rather than being it: the camera's address with the user and\npassword removed, bounded by an expiry, and signed so that whatever opens the\ncamera can tell a live ticket from a made-up one. The caller receives\nsomething that opens one camera for five minutes and says nothing about how.\n\nA camera whose row points anywhere but its own place, and one with no\ncredential registered, is 404.","tags":["patrol"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the camera's document name, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolStreamOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/camera/{name}/stream/{ticket}":{"get":{"operationId":"get_patrol_camera_by_name_stream_by_ticket","summary":"Redeems a minted ticket for what opens the camera.","description":"Redeems a minted ticket for what opens the camera.\n\nThe mint is the operation's — staff only — and it hands back the camera's\naddress with the credential stripped out of it. This is where the holder of\nthat address gets what actually dials the camera, and it asks for no\ncredential of its own: whatever opens a camera is a relay, not a member of the\noperation, and a check only the issuer could perform checks nothing.\n\nThe ticket IS the authority. It names one camera, it covers one moment, and it\nis tagged with a key nobody but this deployment holds, so holding a live one is\nthe right to open that camera until it runs out — which is the whole of what\nwas issued, and the reason issuing one is staff-only and five minutes long.\n\nA tag that does not verify is 404 — the route is no oracle on which tenants or\ncameras exist, or which tickets were ever issued — and one that verifies but\nhas passed its moment is 410, because that ticket was real and is over.","tags":["patrol"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the camera's document name, from the path.","schema":{"type":"string"}},{"name":"ticket","in":"path","required":true,"description":"Ticket is the tag the minted address carries, from the path.","schema":{"type":"string"}},{"name":"expires","in":"query","required":false,"description":"Expires is the moment the tag covers, as the seconds the minted address\ncarries in its `expires` parameter.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolTicketOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/event":{"get":{"operationId":"get_patrol_event","summary":"Lists the feed, newest first.","description":"Lists the feed, newest first. It is the same rows the live stream\ncarries, read back for a screen that has just opened — so the window is the\nnewest rows, or a screen that reloads reads a feed that stopped on the day the\ntenant was installed.","tags":["patrol"],"parameters":[{"name":"level","in":"query","required":false,"description":"Level narrows the list to red, amber, green or cyan. Empty lists every\nlevel.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many rows are returned. Anything that is not a positive\ninteger uses 80, and higher values are clamped to 80.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolEventList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true},"post":{"operationId":"post_patrol_event","summary":"Writes one feed row by hand and pushes it to every screen watching.","description":"Writes one feed row by hand and pushes it to every screen watching.\nIt is how a controller puts something on the record that no automatic write\nwould have produced.","tags":["patrol"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolEventIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolEventOut"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/feed":{"get":{"operationId":"get_patrol_feed","summary":"Watch the live feed","description":"Holds a Server-Sent Events connection open and writes every change in the picture as it happens: a unit's position, an incident moving, a feed row, a checkpoint confirmed. Each record is one `data:` line carrying a JSON frame whose `kind` says which of the four it is, terminated by a blank line; a comment line arrives every 25 seconds so an idle connection stays open.\n\nIt carries the caller's own org and no other. ?since=\u003cYYYY-MM-DD HH:MM:SS\u003e replays the feed rows written at or after that moment before the stream goes live, so a reader that reconnected misses nothing it can still see. The list routes are the truth and the stream is a live hint: a dropped frame costs one refresh.","tags":["patrol"],"x-app":"patrol","x-public":true}},"/v1/patrol/incident":{"get":{"operationId":"get_patrol_incident","summary":"Lists responses.","description":"Lists responses. ?open=1 narrows it to the ones still running.","tags":["patrol"],"parameters":[{"name":"open","in":"query","required":false,"description":"Open lists only the incidents that are not closed when it is 1.","schema":{"format":"int64","type":"integer"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many are returned. Anything that is not a positive integer\nuses 50, and higher values are clamped to 50.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolIncidentList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true},"post":{"operationId":"post_patrol_incident","summary":"Records a response by hand, in state received and carrying the site's tier and SLA.","description":"Records a response by hand, in state received and carrying the\nsite's tier and SLA. It is what a controller calls when an activation arrives\nby phone rather than over the intake.","tags":["patrol"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolIncidentIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolIncidentOut"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/incident/{name}":{"get":{"operationId":"get_patrol_incident_by_name","summary":"Returns one response whole: the incident, every act performed on it, and the SLA clocks those acts settled.","description":"Returns one response whole: the incident, every act performed on it,\nand the SLA clocks those acts settled. The clocks are derived from the stamps\nand stored nowhere.","tags":["patrol"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the incident's document name, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolIncidentOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/incident/{name}/step":{"post":{"operationId":"post_patrol_incident_by_name_step","summary":"Performs one act on an incident: it stamps the act's time, moves the state, appends the act to the trail, and runs what the act sets in motion — a unit assigned, a site secured, a report filed, a controller told.","description":"Performs one act on an incident: it stamps the act's time, moves\nthe state, appends the act to the trail, and runs what the act sets in motion —\na unit assigned, a site secured, a report filed, a controller told.\n\nThe states run forward only. An act from a state it does not leave is 409\nnaming the state the incident is in, and a caller without the act's roles is\nrefused.","tags":["patrol"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the incident's document name, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolIncidentAct"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolIncidentOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/key":{"get":{"operationId":"get_patrol_key","summary":"Lists the key register.","description":"Lists the key register. Neither the officer nor the client reaches it:\npatrol.key is its own DocType and its permissions name neither, so there is no\nkey row for either to read.","tags":["patrol"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolKeyList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/key/{name}":{"get":{"operationId":"get_patrol_key_by_name","summary":"Returns one key set from the register.","description":"Returns one key set from the register.","tags":["patrol"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the key set's reference, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolKeyOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/key/{name}/move":{"post":{"operationId":"post_patrol_key_by_name_move","summary":"Records a key set leaving, returning, or being counted, and moves the register row to match.","description":"Records a key set leaving, returning, or being counted, and moves the\nregister row to match. The register says where a set is now and the movements\nsay how it got there, so a movement is written once and never edited.\n\nWho signed for the move is the caller, stamped from the request. A body that\nnamed the signer would make the chain of custody a value the signer chose.","tags":["patrol"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the key set's reference, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolMoveIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolKeyOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/note":{"get":{"operationId":"get_patrol_note","summary":"Lists internal remarks.","description":"Lists internal remarks. The client never reaches them: patrol.note is\nits own DocType and its permissions do not name the client, so there is no\nnote row for a customer to read.","tags":["patrol"],"parameters":[{"name":"subject","in":"query","required":false,"description":"Subject narrows the list to one subject by exact match. Empty lists every\nnote.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolNoteList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true},"post":{"operationId":"post_patrol_note","summary":"Records an internal remark, stamped with who wrote it.","description":"Records an internal remark, stamped with who wrote it.","tags":["patrol"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolNoteIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolNoteOut"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/point/{name}/confirm":{"post":{"operationId":"post_patrol_point_by_name_confirm","summary":"Records presence at a checkpoint: who confirmed it, the method, where they stood, and the photo key if one was taken.","description":"Records presence at a checkpoint: who confirmed it, the method, where\nthey stood, and the photo key if one was taken. A confirmation after the\nwindow shuts is recorded late rather than refused — the visit happened, and a\nreport that hides it is worth nothing.\n\nAn officer confirms their own round and no other, by the same rule a position\nreport and every incident act are held to: the checkpoint belongs to a tour,\nthe tour names a unit, and the unit names its officer. The record carries the\nactor, so it says who claimed the visit and not merely that somebody did.","tags":["patrol"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the checkpoint's document name, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolConfirmIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolCheckpointOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/report":{"post":{"operationId":"post_patrol_report","summary":"Composes and files a report from one estate read, so the same figures read the same a month later.","description":"Composes and files a report from one estate read, so the same\nfigures read the same a month later. The text is stored on the document; the\nPDF is produced on read at /v1/patrol/report/{name}.\n\nA client report naming a customer is an account of that customer's estate and\nis theirs to download; naming none covers every customer, which is an account\nof the operation.","tags":["patrol"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolReportIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolReportOut"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/report/{name}":{"get":{"operationId":"get_patrol_report_by_name","summary":"Download a filed report","description":"Renders a filed report as a PDF and answers with the bytes under an attachment filename. ?format=text answers the stored text verbatim under text/plain, which is what a copy button reads.\n\nEveryone but the customer may read every report; a client reads only a report about a site of their own, and anything else is 404 rather than a refusal, so the route is no existence oracle. A report whose text cannot be set answers that text rather than failing, because the account is the thing being asked for.","tags":["patrol"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"patrol","x-public":true}},"/v1/patrol/site":{"get":{"operationId":"get_patrol_site","summary":"Lists the estate.","description":"Lists the estate. A client sees only the sites their own customer\nrecord owns, filtered from their role rather than from anything they sent.","tags":["patrol"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit caps how many sites are returned. Anything that is not a positive\ninteger uses 500, and higher values are clamped to 500.","schema":{"format":"int64","type":"integer"}},{"name":"status","in":"query","required":false,"description":"Status narrows the list to ok, fault, alarm or offline. Empty lists every\nstatus.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolSiteList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/site/{name}":{"get":{"operationId":"get_patrol_site_by_name","summary":"Returns one site whole: the register row plus the panel's zones and the standing hazards, which ride inside the document.","description":"Returns one site whole: the register row plus the panel's zones and the\nstanding hazards, which ride inside the document. A client asking for a site\nthat is not theirs is 404.","tags":["patrol"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the site's document name, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolSiteOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true},"put":{"operationId":"put_patrol_site_by_name","summary":"Changes a site's contract and brief fields.","description":"Changes a site's contract and brief fields. It leaves absent fields\nas they stand, and it never moves the account number, the coordinates or the\ncustomer — those are register facts, changed through the framework surface.","tags":["patrol"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the site's document name, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolSiteEdit"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolSiteOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/snapshot":{"get":{"operationId":"get_patrol_snapshot","summary":"Returns the whole picture in one read: sites, units with their position trails, today's tours and checkpoints, the key register, the recent feed and the open incident.","description":"Returns the whole picture in one read: sites, units with their\nposition trails, today's tours and checkpoints, the key register, the recent\nfeed and the open incident. It replaces the five separate list calls the\nscreen used to make. A client sees only their own sites, and the key register\nis empty for anyone whose roles do not reach it.","tags":["patrol"],"parameters":[{"name":"events","in":"query","required":false,"description":"Events caps how many feed rows ride along. Anything that is not a positive\ninteger uses 80, and higher values are clamped to 80.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolSnapshotOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/tenant/{org}":{"get":{"operationId":"get_patrol_tenant_by_org","summary":"Returns one org's public face — brand, company, operations, features and terminology.","description":"Returns one org's public face — brand, company, operations, features\nand terminology. It is the one anonymous route here: the front end loads it\nbefore anyone signs in. It carries no contact list and nothing operational,\nand an org with no tenant document is 404.\n\nThe org is a name a stranger supplied, so the read asks whether the deployment\nalready holds that tenant before it opens anything. Resolving a store CREATES\none, and a caller naming a fresh org on every request would leave a database\nper name they invented.","tags":["patrol"],"parameters":[{"name":"org","in":"path","required":true,"description":"Org is the IAM org the tenant belongs to, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolTenantOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/tour":{"get":{"operationId":"get_patrol_tour","summary":"Lists patrol rounds with their checkpoints — the proof-of-presence record.","description":"Lists patrol rounds with their checkpoints — the proof-of-presence\nrecord. ?date=today narrows it to the current day.","tags":["patrol"],"parameters":[{"name":"date","in":"query","required":false,"description":"Date narrows the list to one day, as YYYY-MM-DD. \"today\" means today.\nEmpty lists every round held.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolTourList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/unit":{"get":{"operationId":"get_patrol_unit","summary":"Lists the fleet with each unit's position trail, which is what the map draws.","description":"Lists the fleet with each unit's position trail, which is what the map\ndraws. It is the operation's own: a unit names no site, so a customer reads\nnone of it — the officer crewing one is the company's staff, and the trail is\nwhere that person has been all shift.","tags":["patrol"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolUnitList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/unit/near":{"get":{"operationId":"get_patrol_unit_near","summary":"Answers which units can reach a site soonest.","description":"Answers which units can reach a site soonest. Distance is a great-circle\nhaversine over the units' last reported positions, and an available unit sorts\nahead of a busy one at any distance — a controller asking for the nearest unit\nis asking for the nearest free one.","tags":["patrol"],"parameters":[{"name":"site","in":"query","required":false,"description":"Site is the site to measure from, by document name.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps how many units come back. Anything that is not a positive\ninteger uses 3, and higher values are clamped to 10.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolNearList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/unit/{name}/fix":{"post":{"operationId":"post_patrol_unit_by_name_fix","summary":"Records where a unit is.","description":"Records where a unit is. It appends the position to the unit's trail,\nmoves the unit's own coordinates and last-seen stamp, and publishes one frame\nto every screen watching. An officer may report only their own unit; the\ncontrol room may report any.","tags":["patrol"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the unit's call sign, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolFixIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolFixOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/patrol/unit/{name}/state":{"post":{"operationId":"post_patrol_unit_by_name_state","summary":"Moves a unit between states — on shift, on a break, off, or in trouble.","description":"Moves a unit between states — on shift, on a break, off, or in\ntrouble. An officer may move only their own unit; the control room may move\nany.","tags":["patrol"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the unit's call sign, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolUnitStateIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/patrol.patrolUnitOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"patrol","x-public":true,"x-tool":true}},"/v1/plan":{"get":{"operationId":"get_plan","summary":"Returns the Hanzo cloud plan catalog: every cloud tier with its price, included capacity, limits and feature list, scoped to the caller's catalog.","description":"Returns the Hanzo cloud plan catalog: every cloud tier with its\nprice, included capacity, limits and feature list, scoped to the caller's\ncatalog. A reseller org sees its own overrides in place of the canonical\nrecords it has replaced, and the canonical record for every tier it has not.","tags":["plan"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/plan.planList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"plan","x-public":true,"x-tool":true}},"/v1/plan/blockchain":{"get":{"operationId":"get_plan_blockchain","summary":"Returns the blockchain RPC plan catalog: the tiers metered in monthly compute units, with their prices, limits and overage terms.","description":"Returns the blockchain RPC plan catalog: the tiers metered\nin monthly compute units, with their prices, limits and overage terms. It is\nthe canonical catalog for every caller — these plans carry no reseller\noverrides.","tags":["plan"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/plan.planList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"plan","x-public":true,"x-tool":true}},"/v1/plan/dns":{"get":{"operationId":"get_plan_dns","summary":"ListDNSPlans returns the DNS plan catalog: the tiers priced on zones, records per zone and queries per day.","description":"ListDNSPlans returns the DNS plan catalog: the tiers priced on zones, records\nper zone and queries per day. It is the canonical catalog for every caller —\nthese plans carry no reseller overrides.","tags":["plan"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/plan.planList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"plan","x-public":true,"x-tool":true}},"/v1/plan/entitlements/{id}":{"get":{"operationId":"get_plan_entitlements_by_id","summary":"Returns what one plan GRANTS and not what it costs: the canonical namespaced entitlement block and the flat license-feature list derived from it.","description":"Returns what one plan GRANTS and not what it costs: the\ncanonical namespaced entitlement block and the flat license-feature list\nderived from it. It is the entitlement half of ResolvePlan, over the same\ncatalog and the same 404 for an id no catalog holds — the read a licensing or\nquota gate makes.","tags":["plan"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the plan's catalog id or slug — \"dev\", \"max\", \"team\", \"rpc-growth\".\nBoth are matched, so a slug resolves the plan it names. A withdrawn id still\nresolves for a renewal, which is why this takes an id rather than a ladder\nposition.","schema":{"type":"string"},"example":"team"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/plan.planEntitlements"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"plan","x-public":true,"x-tool":true}},"/v1/plan/gpu":{"get":{"operationId":"get_plan_gpu","summary":"ListGPUTiers returns the rentable GPU configurations, each with its accelerator count and model, VRAM, vCPUs, host memory and hourly price.","description":"ListGPUTiers returns the rentable GPU configurations, each with its accelerator\ncount and model, VRAM, vCPUs, host memory and hourly price.","tags":["plan"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/plan.planTierList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"plan","x-public":true,"x-tool":true}},"/v1/plan/health":{"get":{"operationId":"get_plan_health","summary":"Reports that the plans subsystem is mounted and serving.","description":"Reports that the plans subsystem is mounted and serving. It answers from\nthe process itself and consults neither the catalog bundle nor the goja host,\nso it stays \"ok\" while either is degraded.","tags":["plan"],"responses":{"200":{"content":{"application/json":{"example":{"service":"plans","status":"ok"},"schema":{"$ref":"#/components/schemas/plan.planHealth"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"plan","x-public":true,"x-tool":true}},"/v1/plan/policy":{"get":{"operationId":"get_plan_policy","summary":"Returns the published pricing policy: whether pricing is transparent, the revenue-sharing terms (idle compute resale and the open-source share) and the principles the catalog is priced by.","description":"Returns the published pricing policy: whether pricing is\ntransparent, the revenue-sharing terms (idle compute resale and the open-source\nshare) and the principles the catalog is priced by.","tags":["plan"],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"plan","x-public":true,"x-tool":true}},"/v1/plan/regions":{"get":{"operationId":"get_plan_regions","summary":"Returns the regions cloud capacity is offered in, each with its display name and physical location.","description":"Returns the regions cloud capacity is offered in, each with its\ndisplay name and physical location.","tags":["plan"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/plan.planRegionList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"plan","x-public":true,"x-tool":true}},"/v1/plan/resolve/{id}":{"get":{"operationId":"get_plan_resolve_by_id","summary":"Resolves one plan to everything a consumer of the catalog needs at once: its canonical entitlement block, the flat license-feature list a signed license carries, its billing reference, and the catalog it came from.","description":"Resolves one plan to everything a consumer of the catalog needs at\nonce: its canonical entitlement block, the flat license-feature list a signed\nlicense carries, its billing reference, and the catalog it came from. The id\nmay be the plan's id or its slug, and it is resolved against the caller's\ncatalog, so a reseller's override wins over the canonical record. An id no\ncatalog holds answers 404.","tags":["plan"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the plan's catalog id or slug — \"dev\", \"max\", \"team\", \"rpc-growth\".\nBoth are matched, so a slug resolves the plan it names. A withdrawn id still\nresolves for a renewal, which is why this takes an id rather than a ladder\nposition.","schema":{"type":"string"},"example":"dev"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/plan.planResolution"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"plan","x-public":true,"x-tool":true}},"/v1/plan/schema":{"get":{"operationId":"get_plan_schema","summary":"Returns the two JSON Schema documents this surface speaks: entitlements.schema.json, which declares every entitlement key with its type, unit and enum, and plan.schema.json, which a catalog plan record conforms to.","description":"Returns the two JSON Schema documents this surface speaks:\nentitlements.schema.json, which declares every entitlement key with its type,\nunit and enum, and plan.schema.json, which a catalog plan record conforms to.","tags":["plan"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/plan.planSchemas"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"plan","x-public":true,"x-tool":true}},"/v1/plan/storage":{"get":{"operationId":"get_plan_storage","summary":"Returns the block-storage price block: the price per GB per month and the volume size bounds a cloud plan may attach.","description":"Returns the block-storage price block: the price per GB per\nmonth and the volume size bounds a cloud plan may attach.","tags":["plan"],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"plan","x-public":true,"x-tool":true}},"/v1/plan/subscriptions":{"get":{"operationId":"get_plan_subscriptions","summary":"Returns the subscription ladder — the personal and team tiers a customer buys to use the cloud, each with its monthly and annual price, seat rules, limits and billing reference.","description":"Returns the subscription ladder — the personal and team\ntiers a customer buys to use the cloud, each with its monthly and annual price,\nseat rules, limits and billing reference. Scoped to the caller's catalog.","tags":["plan"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/plan.planList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"plan","x-public":true,"x-tool":true}},"/v1/plan/tools":{"get":{"operationId":"get_plan_tools","summary":"Returns the per-use price of every metered tool — web search, code interpreter, image generation, speech — each with the unit it is billed in.","description":"Returns the per-use price of every metered tool — web search,\ncode interpreter, image generation, speech — each with the unit it is billed\nin.","tags":["plan"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/plan.planToolList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"plan","x-public":true,"x-tool":true}},"/v1/plan/vocab":{"get":{"operationId":"get_plan_vocab","summary":"Returns the entitlement key vocabulary: every key with its namespace, JSON type, nullability, unit, enum and title, the list of namespaces, and the engine features a license can grant.","description":"Returns the entitlement key vocabulary: every key with\nits namespace, JSON type, nullability, unit, enum and title, the list of\nnamespaces, and the engine features a license can grant. It is derived from\nentitlements.schema.json on every call, so it cannot fall behind the schema.","tags":["plan"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/plan.planVocab"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"plan","x-public":true,"x-tool":true}},"/v1/platform/apps":{"get":{"operationId":"get_platform_apps","summary":"Answers what this organisation has declared, joined with what the delivery plane has done about it.","description":"Answers what this organisation has declared, joined with what\nthe delivery plane has done about it.\n\nThe join is best-effort BY DESIGN and says so when it is missing: the\ndeclarations ARE the answer to \"what have I deployed\", so refusing the whole\nboard because the cluster is unreadable would lose the half that is readable.\nWhat must never happen is a silent null — an unreadable plane is reported as\n`cd.unavailable` carrying the reason, never as an app with no reconciliation,\nand a values file that does not parse is listed in `unreadable`, never dropped.","tags":["platform"],"parameters":[{"name":"org","in":"query","required":false,"description":"Org names the organisation whose declarations to read, defaulting to the\ncaller's own. Only a SuperAdmin may name one that is not theirs; anyone\nelse naming a foreign org is refused, so this widens nothing by itself.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.declaredResp"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true},"post":{"operationId":"post_platform_apps","summary":"Deploy an app through cd.hanzo.ai","description":"Builds a git repository into an image and writes the declaration that names it — a values file in `hanzoai/universe` under `charts/app/values/\u003cnamespace\u003e/\u003cname\u003e.yaml`, which the `fleet` ApplicationSet renders as one Application. That file IS the deployment: nothing else has to be applied.\n\n`repo` is a GitHub repository — `owner/name` or `https://github.com/owner/name` — or another https clone URL. A GitHub repository must be one the caller may see: their own connected GitHub, or the installations their org holds for an org admin (the same set `GET /v1/provider/github/repos` lists); anything else is 404. It is built at the name GitHub gives it now, from `ref`, which defaults to its default branch. Any other URL is an org admin's to build.\n\n`partOf` names the project the app belongs to, and defaults to the app's own name.\n\nEvery member of the org may deploy; WHERE it lands is the difference. An org admin commits to universe main and CD applies it — in one call, naming the tag its own build will push, which CD pulls once the build lands. Anyone else opens a review: the declaration is pushed to `deploy/\u003cnamespace\u003e/\u003cname\u003e/\u003ctag\u003e`, `declaration.review` is the link that opens the pull request, and nothing deploys until it is merged. `mode` may say `branch` to make an admin's deploy a review too; a non-admin naming `commit` is refused, never downgraded.\n\nA member's deploy is bounded by who asked: one build at a time and never the org's last build slot, which is kept for its admins; ten deploys an hour; five open review branches. Past a bound it answers 429. A review branch is deleted once main declares its tag, or after seven days unmerged; `notice` says so, and that the public `env` values the branch carries are cleartext in universe, where deleting the branch does not unpublish them.\n\nA release of an image an earlier call built (`tag` given) is proven pullable before main is pointed at it — a declaration naming an image the registry cannot serve is an ImagePullBackOff with no rollback path.\n\nOmit `tag` to build; give it to declare an image an earlier call already built, which is how a green build is released without rebuilding it. That release is an org admin's: a member's deploy always builds, and carries public `env` only — a sealed value would write the running app's secrets before the review is merged, so a member naming one is refused.\n\nAn org is its name: the values DIRECTORY, the destination NAMESPACE and the AppProject FENCE are all `\u003corg\u003e`, and the image is `\u003cregistry\u003e/\u003corg\u003e/\u003capp\u003e`. None of them is a request field — the directory decides what CD admits the sync under and the repository decides what the cluster pulls, so a caller who could name either could reach outside its own org.\n\n`org` is an ACT-AS, not a placement field: it defaults to the caller's own, and naming another requires SuperAdmin. So does naming a RESERVED org — the platform's own namespace family (the brands and their environments, the control and delivery planes, `admin`) — even when it is the caller's own, because an IAM org named `kube-system` does not own Kubernetes. Both refuse rather than downgrade, so an escape attempt is never indistinguishable from a normal request.\n\nThe app answers at `\u003cname\u003e.\u003csites host\u003e`, and its name is claimed in the one namespace app and site names share, first come first served across every org: a name held by another org, app or site is 409. Any other host under the sites host is refused, and a custom domain is claimed and verified first.","tags":["platform"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/declareReq"}}}},"responses":{"2XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/declareResp"}}},"description":"Success"}},"x-app":"platform","x-public":true}},"/v1/platform/apps/{app}":{"get":{"operationId":"get_platform_apps_by_app","summary":"Answers ONE declaration — what git says this app is, before the delivery plane has had any say in it.","description":"Answers ONE declaration — what git says this app is, before the\ndelivery plane has had any say in it.","tags":["platform"],"parameters":[{"name":"app","in":"path","required":true,"description":"App is the DNS-1123 label of the declaration. The URL is the addressing\nauthority — a path segment binds after the body and after the query — so\nthe address decides which app is read whatever else is sent.","schema":{"type":"string"}},{"name":"org","in":"query","required":false,"description":"Org names the organisation the declaration lives in, defaulting to the\ncaller's own and subject to the same SuperAdmin rule as the listing.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.Declaration"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/apps/{app}/cd":{"get":{"operationId":"get_platform_apps_by_app_cd","summary":"Answers ONE app's reconciliation alone — the poll a deploy console makes while it waits, without re-reading the whole inventory each time.","description":"Answers ONE app's reconciliation alone — the poll a deploy\nconsole makes while it waits, without re-reading the whole inventory each time.","tags":["platform"],"parameters":[{"name":"app","in":"path","required":true,"description":"App is the DNS-1123 label of the declaration. The URL is the addressing\nauthority — a path segment binds after the body and after the query — so\nthe address decides which app is read whatever else is sent.","schema":{"type":"string"}},{"name":"org","in":"query","required":false,"description":"Org names the organisation the declaration lives in, defaulting to the\ncaller's own and subject to the same SuperAdmin rule as the listing.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.CDApp"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/apps/{app}/project":{"put":{"operationId":"put_platform_apps_by_app_project","summary":"Moves an app to a project.","description":"Moves an app to a project.\n\nIt sets the declaration's `partOf` — in its cluster overlay when the overlay\nsets the key, else in its values file — and nothing else. Naming a project\nnothing names yet creates it. `org` is the values directory the app lives in;\n`mode` as for create.","tags":["platform"],"parameters":[{"name":"app","in":"path","required":true,"description":"App is the declaration's name, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.appMove"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.projectWrite"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/builds":{"get":{"operationId":"get_platform_builds","summary":"Returns real build records for your org.","description":"Returns real build records for your org.\n\nIt lists the org's BuildKit build records — the git build step behind a deploy —\neach with the repo it built, the short commit, its status, when it started and\nhow long it took, followed by its site builds: a project in the org's own code\nworkspace built from its repository in a sandbox, newest first. These are real\nrecords or an honest empty list; a build appears here because one ran, never\nbecause a page needed a row. Requires a validated principal; 401 without one.","tags":["platform"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.buildBoard"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/cd":{"get":{"operationId":"get_platform_cd","summary":"Answers every Application the delivery plane holds.","description":"Answers every Application the delivery plane holds.\n\nScoped to the namespaces the caller's own validated org owns: the ROLE admits\nthe caller and the tenant boundary is applied inside, so an admin of one org\nnever observes another's.","tags":["platform"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.cdResp"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/environments":{"get":{"operationId":"get_platform_environments","summary":"Returns your deploy targets, and what is running on each.","description":"Returns your deploy targets, and what is running on each.\n\nIt returns the org's environments — the distinct deploy targets its applications\nname, `production` for anything that names none — each aggregating the apps that\ntarget it, a rolled-up status and when it last changed.\n\nAn environment is DERIVED, not stored: there is nothing to create or delete here,\nand an environment exists exactly as long as an app points at it. Requires a\nvalidated principal; 401 without one.","tags":["platform"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.environmentBoard"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/fleet":{"get":{"operationId":"get_platform_fleet","summary":"Returns the platform's own service tier, and where it has drifted.","description":"Returns the platform's own service tier, and where it has drifted.\n\nIt returns the board for the services the PLATFORM itself runs — iam, kms,\ngateway and the rest — as `{apps, summary}`: per service its environment, health,\nphase, the image tag its CR DECLARES, the tag actually running, and the drift\nbetween them, plus a summary counting the board green, yellow and red.\n\nThis is not a customer surface. `/v1/platform/projects/:project/apps` is a\ntenant's apps; this is the tier those tenants run ON, which is why the two are\nnamed differently rather than sharing a prefix.\n\nAdmission is scoped at the SCAN, before any CR is read: a platform SuperAdmin\nobserves the whole fleet, an org admin observes only their own org's namespaces,\nand an org that owns none gets an empty board — a non-super caller never even\nlists another org's services. Narrow further with `env`, `health`, `org`, or\n`drift=1` for only what has drifted.\n\nIt degrades honestly rather than failing whole: a namespace that does not exist\nis skipped, and a running-state read the caller cannot make leaves the running\ntag empty — an unknown, never a guess — while the declared, health and phase\ncolumns still render.","tags":["platform"],"parameters":[{"name":"env","in":"query","required":false,"description":"Env narrows to one lifecycle env: main, test or dev.","schema":{"type":"string"}},{"name":"health","in":"query","required":false,"description":"Health narrows to one health colour: green, yellow or red.","schema":{"type":"string"}},{"name":"org","in":"query","required":false,"description":"Org narrows to one image namespace.","schema":{"type":"string"}},{"name":"drift","in":"query","required":false,"description":"Drift is `1` or `true` to show only rows that have actually drifted. It is\na STRING and not a bool because those two spellings are exactly what the\nboard has always accepted, and a bool would silently widen that to `?drift`\nalone and to `TRUE` — a behaviour change wearing a type change's clothes.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.driftBoard"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/fleet/{app}":{"get":{"operationId":"get_platform_fleet_by_app","summary":"Returns one platform service, resolved to production by default.","description":"Returns one platform service, resolved to production by default.\n\nIt returns a single platform service by its CR name, with the same\ndeclared-versus-running and drift facts the board carries. The name must be a\nDNS-1123 label; anything else is 400.\n\nNamespaces are scanned in lifecycle order — main, then test, then dev — and the\nfirst match wins, so a bare name resolves to PRODUCTION. The scan covers only the\nnamespaces the caller is authorized for, so an org admin can never read a service\noutside their own org, and a name found in none of them is 404 rather than a leak.","tags":["platform"],"parameters":[{"name":"app","in":"path","required":true,"description":"App is the service's CR name, from the path. It must be a DNS-1123 label.","schema":{"type":"string"}},{"name":"env","in":"query","required":false,"description":"Env narrows the scan to one lifecycle env: main, test or dev. Omitted, the\nnamespaces are scanned in lifecycle order and the first match wins, so a\nbare name resolves to PRODUCTION.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.AppView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/health":{"get":{"operationId":"get_platform_health","summary":"Reports whether this control plane can actually deploy anything.","description":"Reports whether this control plane can actually deploy anything.\n\nA real probe, not a status page. It answers 200 only when the metadata store is\nopen AND the cluster is genuinely reachable — proved by LISTING the operator App\nCRD, which settles reachability and CRD presence in one bounded call, and which\nis the exact question every deploy depends on. Anything else is 503 carrying the\nreal reason and whether the CRD was found.\n\nA constructed cluster client proves nothing — it is built from a kubeconfig, not\nfrom a reachable apiserver — so this deliberately spends a round trip rather than\nreporting `ok` while every deploy fails. Not admin-gated: liveness has to be\nprobe-able without a credential.","tags":["platform"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.readiness"}}},"description":"ok"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.readiness"}}},"description":"service unavailable"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/pipelines":{"get":{"operationId":"get_platform_pipelines","summary":"Returns one build-and-deploy pipeline per app, with its latest run.","description":"Returns one build-and-deploy pipeline per app, with its latest run.\n\nIt returns one pipeline per application in the caller's org — its repo or image\nsource, its current status, and when its most recent deployment ran and how long\nit took. A pipeline is a PROJECTION of an app plus its newest deployment, not a\nseparate record: it comes into existence with the app and is triggered only\nthrough /deploy, never here. Requires a validated principal; 401 without one.","tags":["platform"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.pipelineBoard"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/projects":{"get":{"operationId":"get_platform_projects","summary":"Answers every project the caller may see, with how its apps stand.","description":"Answers every project the caller may see, with how its apps\nstand.\n\nA project is the `partOf` its apps' values files name, so this is the\ndeclaration inventory grouped by that key, joined per app with CD's\nreconciliation, the pods the cluster runs and the newest release the registry\npublishes, and folded into counts: apps, namespaces, sync, health and drift.\nDeclarations that name no project are listed separately, because each one is\ndrift in git.\n\nA SuperAdmin sees every owner's projects, the platform's own among them; an\norg admin sees only its own org's. `org` narrows a SuperAdmin to one owner.\nA plane that cannot be read leaves its counts at unknown and says why in\ncdUnavailable or clusterUnavailable; it never empties the board. A values file\nthat does not parse is listed in unreadable and costs only its own row.","tags":["platform"],"parameters":[{"name":"org","in":"query","required":false,"description":"Org names whose projects to read. Omitted, a SuperAdmin reads every owner's\nand anyone else reads their own; naming another org is an act-as only a\nSuperAdmin has, and naming a platform directory reads the platform's own.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.projectBoard"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true},"post":{"operationId":"post_platform_projects","summary":"Creates a project from the apps it starts with.","description":"Creates a project from the apps it starts with.\n\nA project is the `partOf` its apps' values files name, so creating one names it\non the listed apps: one commit to `hanzoai/universe` that moves each file's\n`partOf` scalar and touches nothing else. There is no empty project; to start\none with a new app, create the app with `partOf` (POST /v1/platform/apps).\n\n`mode` is `branch` (the default: a review branch, nothing deploys) or `commit`\n(main). A `partOf` change relabels the app's pods, so the sync that applies it\nrolls them. 409 when the name already names apps — move apps into an existing\nproject with PUT /v1/platform/apps/{app}/project. An org admin changes its own\norg's projects; the platform's own, and another org's, are SuperAdmin.","tags":["platform"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.projectCreate"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.projectWrite"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/projects/{project}":{"delete":{"operationId":"delete_platform_projects_by_project","summary":"Folds a project into another.","description":"Folds a project into another.\n\nAn app always belongs to exactly one project, so a project ends by moving its\napps: `into` names the existing project they move to, and the project is gone\nonce no file names it. One commit to `hanzoai/universe`; `mode` as for create.\n404 when `into` is not a project.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project to delete, from the path.","schema":{"type":"string"}},{"name":"into","in":"query","required":false,"description":"Into is the existing project its apps move into. Required: an app always\nbelongs to exactly one project.","schema":{"type":"string"}},{"name":"org","in":"query","required":false,"description":"Org names the projects' owner, defaulting to the caller's own scope.","schema":{"type":"string"}},{"name":"mode","in":"query","required":false,"description":"Mode is `branch` (the default) or `commit`.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.projectWrite"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true},"get":{"operationId":"get_platform_projects_by_project","summary":"Answers one project and every app in it.","description":"Answers one project and every app in it.\n\nEach app carries its declaration — image, hosts, replicas, the KMS paths it\nreads (never a value) — together with the CD Application reconciling it, what\nits pods run, the newest release its registry publishes, and the drift between\nthose four. 404 when no declaration in the caller's scope names the project.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project's name, from the path.","schema":{"type":"string"}},{"name":"org","in":"query","required":false,"description":"Org names the project's owner, defaulting to the caller's own scope — which\nfor a SuperAdmin whose home is a brand org is the platform's.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.projectView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true},"put":{"operationId":"put_platform_projects_by_project","summary":"Renames a project.","description":"Renames a project.\n\nIt rewrites `partOf` on every declaration that names the project, in one commit\nto `hanzoai/universe`. 409 when the new name is already a project: fold into it\nwith DELETE /v1/platform/projects/{project}?into=. `mode` as for create.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project to rename, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.projectRename"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.projectWrite"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/projects/{project}/apps":{"get":{"operationId":"get_platform_projects_by_project_apps","summary":"Returns the applications in one project, with what the cluster says about them.","description":"Returns the applications in one project, with what the cluster says\nabout them.\n\nIt lists the caller org's applications under one project. Each row carries the\nstored record and, for an app that is live or deploying, the LIVE phase and\nhealth read from its operator Service CR; an app with sealed env also carries\nits secret-sync state. Those cluster reads are best-effort — an unreachable\ncluster leaves those fields empty and never blocks the listing.\n\nThe project must exist in IAM for this org, or the answer is 404; the `default`\nproject is implicit and always accepted, because it is part of what an org IS.\nRequires a validated principal; 401 without one.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project's name, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/platform.appOut"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true},"post":{"operationId":"post_platform_projects_by_project_apps","summary":"Creates an application from a git repo or a container image.","description":"Creates an application from a git repo or a container image.\n\nIt registers a new application under one of the caller org's projects and\nanswers 201 with it. Creating does NOT deploy: the app lands in `draft` and\nnothing reaches the cluster until /deploy.\n\n`source` is `git` — which requires `repo.url` — or `image`, which requires\n`image.repository`; anything else is 400. A git app builds with zero-config\n`pack` by default and may opt into `dockerfile`; an image app never builds. The\nrepo URL and Dockerfile path are validated here against the SAME allowlist the\nprivileged build enforces, so an unsafe source is refused before it is ever\npersisted.\n\nThe `slug` is the app's identity in the cluster: given or derived from `name`,\nit must match `^[a-z0-9]([a-z0-9-]{0,38}[a-z0-9])?$`, and a slug already used in\nthis project is 409. `replicas` and `storageGb` are clamped to the deployment's\nlimits rather than refused.\n\nEnv keys must match `^[A-Za-z_][A-Za-z0-9_]*$`. A variable marked `secret: true`\nis SEALED into KMS and its plaintext is never written to the database — and if\nKMS is unavailable the create fails 503 rather than falling back to storing a\nsecret in the clear.\n\nThe app is seeded with its canonical default host, so it has a working HTTPS URL\nthe moment it deploys. A bare custom domain cannot be attached here — it has to\ngo through add-domain and DNS verification first. Requires a validated\nprincipal; 401 without one, and every cluster object it will later create lands\nin that org's own `tenant-\u003corg\u003e` namespace.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project to create the application under, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.createAppReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.appOut"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/projects/{project}/apps/{app}":{"delete":{"operationId":"delete_platform_projects_by_project_apps_by_app","summary":"Deletes an application and tears down what it runs.","description":"Deletes an application and tears down what it runs.\n\nIt removes the application record and tears down what it owns in the org's\ntenant namespace — its operator Service CR and its KMSSecret — then answers 204.\nAn app this org and project do not have is 404, never a silent success.\n\nTeardown is best-effort by design: a cluster that refuses or is unreachable does\nnot block the delete, so the record cannot be left orphaned behind a broken\ncluster; the failure is logged for operators and the orphan reaper reconciles\nit. Requires a validated principal; 401 without one.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project the application lives under, from the path.","schema":{"type":"string"}},{"name":"app","in":"path","required":true,"description":"App is the application's slug, from the path.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true},"get":{"operationId":"get_platform_projects_by_project_apps_by_app","summary":"Returns one application, with its live phase, health and secret sync.","description":"Returns one application, with its live phase, health and secret sync.\n\nIt returns a single application of the caller's org together with what the\ncluster currently reports for it: the operator Service CR's phase and health,\nand whether its sealed env has synced. An app this org and project do not have\nis 404. Requires a validated principal; 401 without one.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project the application lives under, from the path.","schema":{"type":"string"}},{"name":"app","in":"path","required":true,"description":"App is the application's slug, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.appOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/projects/{project}/apps/{app}/deploy":{"post":{"operationId":"post_platform_projects_by_project_apps_by_app_deploy","summary":"Deploys the app — building it first if it comes from git.","description":"Deploys the app — building it first if it comes from git.\n\nIt starts a new, monotonically versioned deployment of the app and answers 202\nwith the deployment record. A 202 is an ACCEPTED deployment, not a live one.\n\nAn IMAGE app deploys the tag you name (falling back to the app's tag, then\n`latest`) by writing its operator Service CR; the operator reconciles it to\nrunning. A GIT app launches an in-cluster BuildKit Job at `commit` — or the app's\nbranch — and comes back in `building`; the Service CR is applied later, by the\nreconciler, once the Job succeeds. The reconciler is restart-safe, so a build in\nflight survives a cloud restart.\n\nDeploys are bounded per org: over the concurrent-deploy cap is 429 and NOTHING is\nrecorded, so a rejected deploy leaves no phantom in the history. An unreachable\ncluster is 503 but still records an honest `error` deployment, because a deploy\nthat was attempted and failed must not be indistinguishable from one never made.\nEvery other failure is likewise recorded in its real terminal state.\n\nThis is metered work: a git build is billed to the org's ledger in wall-clock\nbuild minutes once the Job finishes, and the running deployment is billed for its\ncompute per tick for as long as it stays live. Requires a validated principal; 401\nwithout one, and everything is written into that org's own `tenant-\u003corg\u003e`\nnamespace.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project the application lives under, from the path.","schema":{"type":"string"}},{"name":"app","in":"path","required":true,"description":"App is the application's slug, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.deployReq"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.deploymentView"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/projects/{project}/apps/{app}/deployments":{"get":{"operationId":"get_platform_projects_by_project_apps_by_app_deployments","summary":"Returns an app's deployment history.","description":"Returns an app's deployment history.\n\nIt lists every deployment recorded for one of the caller org's applications,\nnewest version first, each with its version, status, source, commit and image.\nFailed and superseded attempts are included — that is the point of a history.\nRequires a validated principal; 401 without one.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project the application lives under, from the path.","schema":{"type":"string"}},{"name":"app","in":"path","required":true,"description":"App is the application's slug, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/platform.deploymentView"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/projects/{project}/apps/{app}/deployments/{id}":{"get":{"operationId":"get_platform_projects_by_project_apps_by_app_deployments_by_id","summary":"Returns one deployment of one app.","description":"Returns one deployment of one app.\n\nIt returns a single deployment by id, scoped to the named application of the\ncaller's org — so an id belonging to another app or another tenant is 404, not a\nread. Requires a validated principal; 401 without one.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project the application lives under, from the path.","schema":{"type":"string"}},{"name":"app","in":"path","required":true,"description":"App is the application's slug, from the path.","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"description":"ID is the deployment's id, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.deploymentView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/projects/{project}/apps/{app}/deployments/{id}/logs":{"get":{"operationId":"get_platform_projects_by_project_apps_by_app_deployments_by_id_logs","summary":"Returns real logs for a deployment — the build's, then the app's.","description":"Returns real logs for a deployment — the build's, then the app's.\n\nIt returns the deployment's recorded status timeline together with LIVE pod logs\npulled from the cluster: the build pod's output while a git build is running, and\nthe running app's output once it is deployed. The `source` field says which of\nthe two the body is — `build`, `app` or `none` — so a console can label the pane\nhonestly.\n\nIt never fabricates log content. When no pod exists yet, or the cluster is\nunreachable, it degrades to the recorded timeline and says so. Every cluster read\nis confined to the caller org's own namespaces and time-boxed. Requires a\nvalidated principal; 401 without one.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project the application lives under, from the path.","schema":{"type":"string"}},{"name":"app","in":"path","required":true,"description":"App is the application's slug, from the path.","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"description":"ID is the deployment's id, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.deployLogs"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/projects/{project}/apps/{app}/domains":{"get":{"operationId":"get_platform_projects_by_project_apps_by_app_domains","summary":"Returns every hostname this app answers on.","description":"Returns every hostname this app answers on.\n\nIt lists the app's hosts: the permanent default host it was born with, and\nevery custom host claimed for it with its\nverification state and, while pending, the DNS challenge records to publish. Live\nendpoint status for each host is observed from the cluster. Requires a validated\nprincipal; 401 without one.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project the application lives under, from the path.","schema":{"type":"string"}},{"name":"app","in":"path","required":true,"description":"App is the application's slug, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/platform.domainView"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true},"post":{"operationId":"post_platform_projects_by_project_apps_by_app_domains","summary":"Attaches a hostname — instantly if you already own it, otherwise with a DNS challenge.","description":"Attaches a hostname — instantly if you already own it, otherwise with a\nDNS challenge.\n\nIt attaches a bring-your-own `host` to the app: the host is claimed as PENDING\nand answers 201 with the DNS challenge records to publish. It is NOT rendered\ninto the app's ingress until /verify passes.\n\nClaims are globally unique. A host already claimed by another organization is\n409, and so is one claimed by a different app in your own; re-adding this app's\nOWN claim is idempotent and answers its current state at 200. The default host is\nalways attached and re-adding it is 409. Any other host under the platform's\nshared apex is 403: a name there is an app's own, taken when that app was\ncreated, and is never claimed through the custom path.\n\n`host` must be a valid DNS hostname; anything else is 400. Requires a validated\nprincipal; 401 without one.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project the application lives under, from the path.","schema":{"type":"string"}},{"name":"app","in":"path","required":true,"description":"App is the application's slug, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.addDomainReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.domainView"}}},"description":"ok"},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.domainView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/projects/{project}/apps/{app}/domains/{host}":{"delete":{"operationId":"delete_platform_projects_by_project_apps_by_app_domains_by_host","summary":"Detaches a hostname and releases the claim.","description":"Detaches a hostname and releases the claim.\n\nIt drops the host from the app's ingress and releases any custom claim on it, so\nthe name becomes claimable again — by this org or any other. Answers 204.\n\nThe default host is permanent and cannot be removed: that is 400, not 404. A host\nthat is neither attached nor claimed here is 404. Requires a validated principal;\n401 without one.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project the application lives under, from the path.","schema":{"type":"string"}},{"name":"app","in":"path","required":true,"description":"App is the application's slug, from the path.","schema":{"type":"string"}},{"name":"host","in":"path","required":true,"description":"Host is the hostname, from the path.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/projects/{project}/apps/{app}/domains/{host}/verify":{"post":{"operationId":"post_platform_projects_by_project_apps_by_app_domains_by_host_verify","summary":"Checks a custom domain's DNS and turns it on if it passes.","description":"Checks a custom domain's DNS and turns it on if it passes.\n\nIt runs the DNS challenge check for a pending custom host and, when it passes,\nmarks the host verified and renders it into the app's ingress so it starts\nserving.\n\nA check that RAN and did not pass is not an error: it answers 200 with the host\nstill pending and the reason in `detail`, so a console can show the operator what\nDNS is actually returning. An already-verified host answers as-is without\nre-checking. A host not claimed by this app is 404. Requires a validated\nprincipal; 401 without one.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project the application lives under, from the path.","schema":{"type":"string"}},{"name":"app","in":"path","required":true,"description":"App is the application's slug, from the path.","schema":{"type":"string"}},{"name":"host","in":"path","required":true,"description":"Host is the hostname, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.domainView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/projects/{project}/apps/{app}/env":{"put":{"operationId":"put_platform_projects_by_project_apps_by_app_env","summary":"Replaces an app's environment variables.","description":"Replaces an app's environment variables.\n\nIt writes the app's whole environment set and answers the updated application.\nThis is the one post-create write path for env, and it REPLACES rather than\nmerges: a variable absent from the body is gone, and a secret dropped from the\nset leaves the app's Secret on its next deploy.\n\nKeys must match `^[A-Za-z_][A-Za-z0-9_]*$`. A value marked `secret: true` is\nsealed into KMS and blanked in the database, so plaintext is never persisted —\nand the write fails 503 if KMS is unavailable rather than storing one in the\nclear.\n\nThe rule worth knowing: this does not restart anything. Once the app has been\ndeployed the secret sync is re-declared immediately so the operator\nre-materialises the Secret, but RUNNING pods keep the environment they started\nwith until their next deploy or restart. Requires a validated principal; 401\nwithout one.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project the application lives under, from the path.","schema":{"type":"string"}},{"name":"app","in":"path","required":true,"description":"App is the application's slug, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.setEnvReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.appOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/projects/{project}/apps/{app}/preview":{"post":{"operationId":"post_platform_projects_by_project_apps_by_app_preview","summary":"Puts a branch on its own URL.","description":"Puts a branch on its own URL.\n\nIt deploys an already-built `image` to a per-branch preview and answers its URL,\nthe branch, the preview's slug and the deployment. The preview is a FIRST-CLASS\napplication named `\u003capp\u003e-\u003cbranch\u003e` in the same project and tenant namespace, with\nits own default host — so it is completely isolated from production while reusing\nthe same deploy mechanic. Re-previewing a branch converges that same target in\nplace rather than stacking another one.\n\nIt carries NO environment variables, deliberately: a preview never inherits\nproduction's secrets. It also does not build — `image` is required and must\nalready exist, and `branch` defaults to the parent app's. A branch that does not\nresolve to a valid slug distinct from the parent's is 400. Requires a validated\nprincipal; 401 without one.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project the parent application lives under, from the path.","schema":{"type":"string"}},{"name":"app","in":"path","required":true,"description":"App is the parent application's slug, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.previewReq"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.previewView"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/projects/{project}/apps/{app}/promote":{"post":{"operationId":"post_platform_projects_by_project_apps_by_app_promote","summary":"Promotes an already-built release to the app.","description":"Promotes an already-built release to the app.\n\nIt redeploys an image that already exists — named either by `deploymentId`, which\npromotes that deployment's exact built image, or by `tag`, resolved the same way\na deploy resolves one. One of the two is required; neither is 400.\n\nPromotion never builds. A deployment that carries no built image cannot be\npromoted and is 400, and a deployment id outside this app is 404. It runs through\nthe same deploy core as everything else, so it takes a NEW version number and is\nsubject to the same per-org concurrency cap. Requires a validated principal; 401\nwithout one.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project the application lives under, from the path.","schema":{"type":"string"}},{"name":"app","in":"path","required":true,"description":"App is the application's slug, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.promoteReq"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.deploymentView"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/projects/{project}/apps/{app}/rollback":{"post":{"operationId":"post_platform_projects_by_project_apps_by_app_rollback","summary":"Goes back to the previous release.","description":"Goes back to the previous release.\n\nIt redeploys a prior image: the one named by `deploymentId`, or — with no body —\nthe newest earlier deployment that carries a real built image and did not error,\nskipping the release currently live. An app with nothing earlier to return to is\n400.\n\nA rollback is a deploy of an old image, not a rewind: it takes a NEW version\nnumber and appends to the history rather than erasing what came after. Both\nlookups are scoped to this app and org, so another tenant's image can never be\nrolled in. Requires a validated principal; 401 without one.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project the application lives under, from the path.","schema":{"type":"string"}},{"name":"app","in":"path","required":true,"description":"App is the application's slug, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.rollbackReq"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.deploymentView"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/projects/{project}/apps/{app}/start":{"post":{"operationId":"post_platform_projects_by_project_apps_by_app_start","summary":"Starts a stopped app back up.","description":"Starts a stopped app back up.\n\nIt scales the app's Service back to its configured replica count and marks it\nlive, answering the updated application. It does not redeploy: the image already\non the Service CR is what comes back.\n\nThe billing watermark is reset to now as part of starting, so the org is charged\nfor THIS live span and never for the gap the app spent stopped. An app with no\nService CR is 404, an unreachable cluster is 503, and a cluster that refuses the\nscale is 502. Requires a validated principal; 401 without one.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project the application lives under, from the path.","schema":{"type":"string"}},{"name":"app","in":"path","required":true,"description":"App is the application's slug, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.appOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/projects/{project}/apps/{app}/stop":{"post":{"operationId":"post_platform_projects_by_project_apps_by_app_stop","summary":"Stops an app without deleting it.","description":"Stops an app without deleting it.\n\nIt scales the app's Service to zero replicas and marks it stopped, answering the\nupdated application. Nothing else is removed — the record, its env, its domains\nand its deployment history all survive, and /start brings it back at the same\nreplica count.\n\nAn app that is not deployed has no Service CR to scale and is 404. An\nunreachable cluster is 503 and a cluster that refuses the scale is 502. Because\nthe pods stop, so does the compute metering. Requires a validated principal; 401\nwithout one.","tags":["platform"],"parameters":[{"name":"project","in":"path","required":true,"description":"Project is the project the application lives under, from the path.","schema":{"type":"string"}},{"name":"app","in":"path","required":true,"description":"App is the application's slug, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.appOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/releases":{"get":{"operationId":"get_platform_releases","summary":"Returns the versions that actually reached the cluster.","description":"Returns the versions that actually reached the cluster.\n\nIt lists the org's releases: the deployments that were genuinely applied to the\ncluster, with the app they belong to, their version, environment, status and when\nthey were released. A deployment that failed or is still building is NOT a\nrelease and is excluded — reaching the cluster is what makes one. Requires a\nvalidated principal; 401 without one.","tags":["platform"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.releaseBoard"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/platform/run":{"post":{"operationId":"post_platform_run","summary":"Runs a container image and gives back a URL.","description":"Runs a container image and gives back a URL.\n\nThe one-call shortcut over project → app → deploy: give it a `name` and an\n`image` and it creates or updates an image-source application in your org's\nDEFAULT project, deploys it through the same operator Service-CR writer\neverything else uses, and answers its id, name, live URL, status and shape.\nRe-running the same name UPDATES it in place, so the call is idempotent by name.\n\nWhat it produces is a first-class application, not a special object: it is\nlistable, stoppable and redeployable through the /v1/platform routes like any\nother app.\n\n`minScale` is the replica floor. `maxScale` above it declares an autoscaling\nceiling; `maxScale: 0` means no autoscaler at all — a fixed run at the floor.\nBoth are clamped to the deployment's limits. `runtime` and `shape` are accepted\nfor the client contract and echoed back: the image is the runtime unit and sizing\nis the operator's default.\n\nIt is BILLING-GATED before it touches the cluster: a flat per-run fee is\nauthorized against the org's own prepaid balance first, so an org that cannot pay\nis refused without anything being created. An unreachable cluster is 503 — a run\nnever reports a URL it did not create. Secret env is sealed into KMS and fails\nclosed without it.\n\nRequires a validated principal; 401 without one. The org is resolved from that\nvalidated identity and is what both pays and owns the namespace — it is never\nread from the body.","tags":["platform"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.runReq"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/platform.runView"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"platform","x-public":true,"x-tool":true}},"/v1/pref":{"get":{"operationId":"get_pref","summary":"Returns the signed-in caller's OWN preference document — the theme, density and pinned nav that follow them across every Hanzo surface.","description":"Returns the signed-in caller's OWN preference document — the theme,\ndensity and pinned nav that follow them across every Hanzo surface. There is no\npath to another user's preferences: not for an org admin, not for a platform\nSuperAdmin, because the subject is built from the validated credential and is the\nmandatory predicate on the read. A caller who has never saved anything gets an\nempty document at 200, never a 404, so the user menu always renders.","tags":["pref"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pref.prefsView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pref","x-public":true,"x-tool":true},"patch":{"operationId":"patch_pref","summary":"Save the preference keys your surface owns, leaving every other key alone","description":"Merges a JSON object key-wise into the signed-in caller's OWN preference document and answers with the whole document after the merge, so a surface saves `theme` without having to send back the `density` another surface owns. The merge is SHALLOW and the key space is open: an unnamed key is left untouched, a named key is replaced whole, and a key sent with a `null` value is DELETED. The subject is the `\u003cowner\u003e/\u003cname\u003e` identity built from the validated credential and is the mandatory predicate on the write, so there is no path to another user's preferences — not for an org admin, not for a platform SuperAdmin. Fails closed: no validated principal is 403; an empty body or a literal `null` is 400; and a patch or a resulting document over 16 KiB or 128 keys is 413.","tags":["pref"],"x-app":"pref","x-public":true}},"/v1/pricing":{"get":{"operationId":"get_pricing","summary":"Returns the whole pricing catalog in one document: Zen and third-party models, providers, model families, the free-model list, plan and infrastructure pricing.","description":"Returns the whole pricing catalog in one document: Zen and\nthird-party models, providers, model families, the free-model list, plan and\ninfrastructure pricing. Every model and provider it names is filtered to what\nthe caller's org may see — the same gate the leaf routes apply, so this can\nnever be an un-gated second source for what they hide.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/base":{"get":{"operationId":"get_pricing_base","summary":"Returns the Hanzo Base plans — the managed-instance tiers, each with its monthly and annual price, storage and request allowances and feature list.","description":"Returns the Hanzo Base plans — the managed-instance tiers,\neach with its monthly and annual price, storage and request allowances and\nfeature list.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pricing.pricingPlanList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/blockchain":{"get":{"operationId":"get_pricing_blockchain","summary":"Returns the blockchain access plans — the RPC and node tiers, each with its monthly price, compute-unit allowance and feature list.","description":"Returns the blockchain access plans — the RPC and node\ntiers, each with its monthly price, compute-unit allowance and feature list.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pricing.pricingPlanList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/cloud":{"get":{"operationId":"get_pricing_cloud","summary":"Returns the public cloud section of the catalog in one document: its instance plans, its regions and its block-storage prices.","description":"Returns the public cloud section of the catalog in one\ndocument: its instance plans, its regions and its block-storage prices. The\nsection's internal half — the provider costs Hanzo pays and the plan-to-\nprovider routing table — is stripped before it is served, so this is what a\ncustomer may see and nothing more.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/cloud/plans":{"get":{"operationId":"get_pricing_cloud_plans","summary":"Returns just the cloud instance plans — each with its vCPU, memory, disk, CPU type, VM allowance, feature list and monthly and hourly price.","description":"Returns just the cloud instance plans — each with its vCPU,\nmemory, disk, CPU type, VM allowance, feature list and monthly and hourly\nprice. It is the plans of the cloud section on their own.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pricing.pricingPlanList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/cloud/regions":{"get":{"operationId":"get_pricing_cloud_regions","summary":"Returns the regions a cloud instance can be placed in, each with its id, display name and physical location.","description":"Returns the regions a cloud instance can be placed in, each\nwith its id, display name and physical location. It is the regions of the\ncloud section on their own.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pricing.pricingRegionList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/cloud/storage":{"get":{"operationId":"get_pricing_cloud_storage","summary":"Returns the block-storage prices of the cloud section: the per-GB monthly rate and the volume size bounds a caller may ask for.","description":"Returns the block-storage prices of the cloud\nsection: the per-GB monthly rate and the volume size bounds a caller may ask\nfor.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/compute":{"get":{"operationId":"get_pricing_compute","summary":"Returns the compute section of the catalog: the cloud provider and region the prices are quoted for, the monthly markup applied to them, the full instance-size tier list and the named presets.","description":"Returns the compute section of the catalog: the cloud\nprovider and region the prices are quoted for, the monthly markup applied to\nthem, the full instance-size tier list and the named presets. It is the\nwhole section as the pricing source records it, un-gated — no model or\nprovider identity appears in it.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/compute/presets":{"get":{"operationId":"get_pricing_compute_presets","summary":"Returns just the named compute sizes — the short, human-labelled list (\"Starter\", \"Pro\") a size picker renders, each carrying its provider slug, vCPU, memory, disk and price.","description":"Returns just the named compute sizes — the short,\nhuman-labelled list (\"Starter\", \"Pro\") a size picker renders, each carrying\nits provider slug, vCPU, memory, disk and price. It is the presets of the\ncompute section on their own, for a caller that does not need the full tier\ntable.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pricing.pricingPresetList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/datastore":{"get":{"operationId":"get_pricing_datastore","summary":"Returns the Hanzo Datastore rate card: the tier list, the per-GB storage and egress usage rates, the annual discount and the trial.","description":"Returns the Hanzo Datastore rate card: the tier list, the\nper-GB storage and egress usage rates, the annual discount and the trial. It is\nthe section as authored, un-gated — no provider identity appears in it.\n\nThe route was missing while the data existed, so this 404d and every visitor to\nhanzo.ai's Infrastructure tab was told pricing was \"temporarily unavailable\".","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/enablement":{"get":{"operationId":"get_pricing_enablement","summary":"Returns what the caller can actually use: every managed item with its global state and whether it is effective for this caller — a beta item is, while the platform's `beta` switch is on for it.","description":"Returns what the caller can actually use: every managed item\nwith its global state and whether it is effective for this caller — a beta\nitem is, while the platform's `beta` switch is on for it. Read-only and safe\nfor any caller: one without a validated principal sees the generally-available\nitems, never another org's view.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pricing.enablementBoard"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/featured":{"get":{"operationId":"get_pricing_featured","summary":"Returns the models the catalog highlights, filtered to what the caller's org may see.","description":"Returns the models the catalog highlights, filtered to what\nthe caller's org may see. It is the same catalog as ListModels narrowed to\nentries the pricing source marks featured.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pricing.pricingModelList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/free":{"get":{"operationId":"get_pricing_free","summary":"Returns the models that cost nothing to call, filtered to what the caller's org may see.","description":"Returns the models that cost nothing to call, filtered to what\nthe caller's org may see. It is the same catalog as ListModels narrowed to\nentries the pricing source marks free.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pricing.pricingModelList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/gpu":{"get":{"operationId":"get_pricing_gpu","summary":"ListGPUTiers returns the rentable GPU configurations, each with its accelerator count and model, VRAM, vCPU, host memory and hourly price.","description":"ListGPUTiers returns the rentable GPU configurations, each with its\naccelerator count and model, VRAM, vCPU, host memory and hourly price.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pricing.pricingTierList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/health":{"get":{"operationId":"get_pricing_health","summary":"Reports that the pricing subsystem is mounted and serving.","description":"Reports that the pricing subsystem is mounted and serving. It answers\nfrom the process itself and consults neither the catalog bundle nor the\nenablement store, so it stays \"ok\" while either is degraded.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"example":{"service":"pricing","status":"ok"},"schema":{"$ref":"#/components/schemas/pricing.pricingHealth"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/iam":{"get":{"operationId":"get_pricing_iam","summary":"ListIAMPlans returns the identity plans — the Hanzo IAM tiers, each with its monthly and annual price, monthly-active-user allowance and feature list.","description":"ListIAMPlans returns the identity plans — the Hanzo IAM tiers, each with its\nmonthly and annual price, monthly-active-user allowance and feature list.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pricing.pricingPlanList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/model/{name}":{"get":{"operationId":"get_pricing_model_by_name","summary":"Returns one model's catalog entry — its pricing, context window and capabilities as the pricing source records them.","description":"Returns one model's catalog entry — its pricing, context window and\ncapabilities as the pricing source records them. A model hidden for the\ncaller's org answers the same 404 an unknown name does, so a disabled model\ngets no existence oracle.","tags":["pricing"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the model's name or its slugged id (\"zen4\",\n\"acme/some-model-1\"), matched case-insensitively. It comes from\nthe path: the URL is the addressing authority.","schema":{"type":"string"},"example":"zen4"}],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/models":{"get":{"operationId":"get_pricing_models","summary":"Returns the whole model catalog — every model the gateway serves, Zen and third-party alike — filtered to what the caller may see.","description":"Returns the whole model catalog — every model the gateway serves,\nZen and third-party alike — filtered to what the caller may see. A model an\nadmin has disabled is absent; one in beta appears only for a caller the\nplatform's `beta` switch is on for. A SuperAdmin sees every model, each\nannotated with its enablement state.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pricing.pricingModelList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/paas":{"get":{"operationId":"get_pricing_paas","summary":"ListPaaSPlans returns the application-hosting plans — the deploy-and-host tiers, each with its monthly and annual price, app and memory allowances and feature list.","description":"ListPaaSPlans returns the application-hosting plans — the deploy-and-host\ntiers, each with its monthly and annual price, app and memory allowances and\nfeature list.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pricing.pricingPlanList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/policy":{"get":{"operationId":"get_pricing_policy","summary":"Returns the pricing policy document: the revenue-sharing terms (the idle-resale share and the open-source share, each with its percentage and who is eligible) and the commitments Hanzo makes about how it bills — no hidden fees, no egress charges, no surprise bills.","description":"Returns the pricing policy document: the revenue-sharing\nterms (the idle-resale share and the open-source share, each with its\npercentage and who is eligible) and the commitments Hanzo makes about how it\nbills — no hidden fees, no egress charges, no surprise bills.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/providers":{"get":{"operationId":"get_pricing_providers","summary":"Returns the model providers the catalog knows, each with its info object, filtered to what the caller's org may see.","description":"Returns the model providers the catalog knows, each with its\ninfo object, filtered to what the caller's org may see. A provider an admin\nhas disabled is absent — and so are its models everywhere else on this\nsurface, because a provider's state cascades to what it serves.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pricing.pricingProviderList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/services":{"get":{"operationId":"get_pricing_services","summary":"Returns the managed-service rate cards — Search, Crawl, Vector, Console and Managed Services — each with its own tiers, and some with usage rates or a comparison table.","description":"Returns the managed-service rate cards — Search, Crawl,\nVector, Console and Managed Services — each with its own tiers, and some with\nusage rates or a comparison table. It is the section as authored, un-gated.\n\nThese are DISPLAY rate cards: what a product costs, not what a plan grants. No\nentitlement or limit fields ride here, so nothing can bill off them.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/subscriptions":{"get":{"operationId":"get_pricing_subscriptions","summary":"Returns the API subscription plans — the account-level tiers a customer subscribes to, each with its monthly and annual price, included credit, rate limits and feature list.","description":"Returns the API subscription plans — the account-level\ntiers a customer subscribes to, each with its monthly and annual price,\nincluded credit, rate limits and feature list.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pricing.pricingPlanList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/summary":{"get":{"operationId":"get_pricing_summary","summary":"Returns the catalog's headline statistics — model counts by family and the provider directory.","description":"Returns the catalog's headline statistics — model counts by\nfamily and the provider directory. The provider sub-object is filtered to what\nthe caller's org may see, so a disabled provider's name never leaks; the\naggregate counts are the catalog's own, over everything it holds. A SuperAdmin's\nsummary adds `enso`: the day's Enso answers, the arms that failed first, the share\nOpenRouter's credit bought (fallbacks), the margin the fixed prices made, the\nanswers that stated no cost and every loss, by model, arm and vendor.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/tariff":{"get":{"operationId":"get_pricing_tariff","summary":"Returns the platform's rate card: what a bill is made of, what each part costs, and the completion windows a request may ask for.","description":"Returns the platform's rate card: what a bill is made of, what each\npart costs, and the completion windows a request may ask for.\n\nFOUR COMPONENTS, and every charge is one of them — model inference, computer,\nweb tools and media generation. Two are quoted before they run, so an agent is\nrefused before it breaches its budget; two are booked from what they used,\nbecause neither a provider's charge nor a render's cost is knowable in advance.\n\nEVERY AMOUNT IS INTEGER MICRO-USD (1 USD = 1,000,000), stated once in `unit`,\nand each rate says what one unit of it is in `per`. The compute rates are per\nHOUR because that is the unit a span is priced in — rate × seconds / 3600 — and\nbecause a GiB-second is four and a half micro-USD, which no integer holds.\n\nThe rates are the ones the ledger books: each is resolved through the same\nauthority the metering path reads, falling back to the same compiled floor. A\nrate of zero is a price and not an absence — a paused computer, a computer's\ncreation, the interfaces and a seat all cost nothing by design.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pricing.Card"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/pricing/tools":{"get":{"operationId":"get_pricing_tools","summary":"Returns the per-use tool prices — web search, web fetch, code interpreter, file storage, image generation, speech-to-text and text-to-speech — each with the unit it is billed by and its price in that unit.","description":"Returns the per-use tool prices — web search, web fetch, code\ninterpreter, file storage, image generation, speech-to-text and\ntext-to-speech — each with the unit it is billed by and its price in that\nunit.\n\nThe two WEB rows are priced from the rate card rather than from the catalog,\nbecause those are the rows the platform charges by the call and a published\nnumber that is also a charged one has exactly one home (see tariff.go). Read\nthem as integer micro-USD at /v1/pricing/tariff; the decimal here is the\ndisplay this list has always carried.","tags":["pricing"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pricing.pricingToolList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pricing","x-public":true,"x-tool":true}},"/v1/principal":{"get":{"operationId":"get_principal","summary":"Returns the caller's org as an economic principal, composed from the apps that own each fact: its legal entity and founders' identity verification (company), the W-9 or W-8 it certified (tax), its wallets (wallet), the agents that answer to it — spawned ones with the agent that spawned them — (agents), its screening against the OFAC, UN, EU and UK sanctions lists and the embargoed jurisdictions, run now, and what it still lacks to pay and be paid.","description":"Returns the caller's org as an economic principal, composed from the apps that\nown each fact: its legal entity and founders' identity verification (company),\nthe W-9 or W-8 it certified (tax), its wallets (wallet), the agents that answer\nto it — spawned ones with the agent that spawned them — (agents), its screening\nagainst the OFAC, UN, EU and UK sanctions lists and the embargoed jurisdictions,\nrun now, and what it still lacks to pay and be paid. The read changes nothing:\na possible match it finds is recorded for a platform reviewer when a payment to\nor from the org is cleared.\n\nAny member reads it. The detail behind a verdict — founders' names and\nstatuses, masked tax numbers, treaty claims, sanctions matches — is answered to\nthe org's admins only. An owning app this deployment does not run is named in\nsources as absent rather than read as empty.","tags":["principal"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/principal.View"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"principal","x-public":true,"x-tool":true}},"/v1/principal/agents/{ref}":{"get":{"operationId":"get_principal_agents_by_ref","summary":"Attests which principal one of the caller's agents answers to: the org, the chain of agents that spawned it, and the same signed with the platform's key as a JWS (EdDSA) a verifier checks offline against GET /v1/principal/keys.","description":"Attests which principal one of the caller's agents answers to: the org, the\nchain of agents that spawned it, and the same signed with the platform's key as\na JWS (EdDSA) a verifier checks offline against GET /v1/principal/keys. Any\nmember of the agent's org.\n\nAn agent of another org is not found. A spawned agent answers to its parent's\norg, which is its own: a parent is resolved only in the org the agent is created\nin. The statement is valid for 24 hours.","tags":["principal"],"parameters":[{"name":"ref","in":"path","required":true,"description":"Ref is the agent's id or its name in the caller's org.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/principal.Attestation"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"principal","x-public":true,"x-tool":true}},"/v1/principal/clearance":{"get":{"operationId":"get_principal_clearance","summary":"Lists the caller org's clearances, newest first, 200 at most; a payee narrows them.","description":"Lists the caller org's clearances, newest first, 200 at most; a payee narrows\nthem. Any member of the paying org.","tags":["principal"],"parameters":[{"name":"payee","in":"query","required":false,"description":"Payee narrows to one payee.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/principal.clearanceList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"principal","x-public":true,"x-tool":true},"post":{"operationId":"post_principal_clearance","summary":"Decides whether the caller's org may pay another org, BEFORE the payment: what must happen first, what must be withheld and why, what must be reported, by whom and when, and how the payment may settle net of withholding.","description":"Decides whether the caller's org may pay another org, BEFORE the payment: what\nmust happen first, what must be withheld and why, what must be reported, by\nwhom and when, and how the payment may settle net of withholding. Any member of\nthe paying org; the decision is recorded and on the audit trail in one\ntransaction.\n\nThe rules, each cited on the answer: payer's and payee's founders identity-verified\n(Hanzo policy); payer and payee screened clear of the OFAC, UN, EU and UK lists\nand the embargoed jurisdictions — a confirmed match blocks, a possible one waits\non a Hanzo platform reviewer, and lists that are not loaded and fresh clear\nnobody; the payee's status is what the form the payee granted the payer says,\nand until it grants one the payee furnishes it; a U.S. payee with no TIN on\nfile owes its W-9, and paid without one 24% backup withholding applies (IRC\n§3406); a foreign payee on a valid W-8BEN or W-8BEN-E is withheld on at 30% on\nU.S.-source income (IRC §1441, §1442), reduced by a treaty rate the form\nclaims; a service performed outside the United States is foreign-source and\nnot withheld on; Form 1099 by the payer for a reportable U.S. payee at the\nyear's threshold, Forms 1042-S and 1042 for U.S.-source income to a foreign\nperson, and platform-operator reports (EU DAC7, UK, Canada, Australia) where\nthe payer is the payee's platform. Every filer named is an org, never Hanzo.\n\nNothing of the payee is answered but what the payer must know to act: that the\npayment clears, what the payee must furnish, or that it cannot clear and the\npayer should contact support — never why, and never the payee's status before\nthe payee grants its form. A payer asks about at most 50 new payees a day and\n120 payments an hour.","tags":["principal"],"requestBody":{"content":{"application/json":{"example":{"amount":"5000.00","category":"services","payee":"globex","performed":"DE"},"schema":{"$ref":"#/components/schemas/principal.clearIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/principal.Clearance"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"principal","x-public":true,"x-tool":true}},"/v1/principal/clearance/{id}":{"get":{"operationId":"get_principal_clearance_by_id","summary":"Reads one of the caller org's clearances, as it was decided.","description":"Reads one of the caller org's clearances, as it was decided. Any member of the\npaying org; another org's clearance is not found.","tags":["principal"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the clearance, \"clr_\"-prefixed.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/principal.Clearance"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"principal","x-public":true,"x-tool":true}},"/v1/principal/keys":{"get":{"operationId":"get_principal_keys","summary":"Publishes the keys attestations are signed with, as a JSON Web Key Set (RFC 7517; Ed25519 keys as RFC 8037 writes them).","description":"Publishes the keys attestations are signed with, as a JSON Web Key Set (RFC\n7517; Ed25519 keys as RFC 8037 writes them). Open to anyone: a verifier\nverifying an agent's statement fetches this once and verifies offline.\n\nA key a rotation retired stays here and signs nothing, so a statement signed\nbefore the rotation verifies until it expires.","tags":["principal"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/principal.JWKS"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"security":[],"x-app":"principal","x-public":true,"x-tool":true}},"/v1/principal/statements/{id}":{"get":{"operationId":"get_principal_statements_by_id","summary":"Reads whether one statement the platform signed about an agent still stands: live, expired, or revoked and when.","description":"Reads whether one statement the platform signed about an agent still stands:\nlive, expired, or revoked and when. Open to anyone — a verifier holding a\nTaxPrincipalCredential checks it here after checking its signature offline\nagainst GET /v1/principal/keys. The answer names nothing the statement itself\ndoes not.","tags":["principal"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the statement's jti, as its JWS carries it.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/principal.Statement"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"security":[],"x-app":"principal","x-public":true,"x-tool":true}},"/v1/project":{"get":{"operationId":"get_project","summary":"Returns every project your org owns.","description":"Returns every project your org owns.\n\nEach row carries the slug, name, framework, visibility, status and live URL —\nthe same rows console and the builder render, because there is only one store\nbehind both. It requires a validated principal (401 without one) and is keyed\nby that principal's org, so it never contains another tenant's project.","tags":["project"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/project.projectsProject"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true},"post":{"operationId":"post_project","summary":"Creates a project — the handle a site is deployed and served under — and answers 201 with it in `draft`.","description":"Creates a project — the handle a site is deployed and served\nunder — and answers 201 with it in `draft`.\n\n`name` is required; `slug` is derived from the name when omitted and is the\nidentifier that matters — it becomes the S3 key segment, the public host\n`\u003cslug\u003e.hanzo.app`, and the handle every later call addresses, so it must\nmatch `^[a-z0-9]([a-z0-9-]{0,38}[a-z0-9])?$` and may not be a reserved label\nsuch as `api` or `admin`. `framework` is a build hint from a closed set,\ndefaulting to `static`; it never gates a deploy, it only tells CI how to build\na linked repo.\n\nTwo defaults are worth knowing: the analytics beacon is ON unless `analytics`\nis explicitly false, and `visibility` is `public` unless asked otherwise.\nPublishing publicly is free; PRIVATE is the paid feature, and an unfunded org\nasking for it is refused rather than quietly published as public. Creation\nalso provisions the project's data space and a canonical git repo, both\nbest-effort — neither can fail the create.\n\nScope: a validated principal is required (401 without one) and the project is\ncreated in THAT principal's org. The slug is unique per org, so a slug already\nused in the caller's own org is a 409 while the same slug in another org is\nirrelevant.","tags":["project"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsCreate"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsProject"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true}},"/v1/project/edge":{"get":{"operationId":"get_project_edge","summary":"health reports whether a publish reaches readers, rather than whether it was accepted.","description":"health reports whether a publish reaches readers, rather than whether it was\naccepted. Those are different questions and only the second one was ever\nvisible.\n\nIt asks the edge and nothing else. There is no live call to the provider here:\nConfigured is a local fact, it is the fact that was missing, and a health check\nthat spends a third-party API call is one an operator learns not to run.","tags":["project"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.edgeState"}}},"description":"ok"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.edgeState"}}},"description":"service unavailable"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true}},"/v1/project/fork":{"post":{"operationId":"post_project_fork","summary":"Creates a project seeded from a PUBLISHED EXAMPLE — either a starter-kit template from the ONE embedded gallery catalog, or any live project on the platform (an example a seeded creator published, or another org's app serving at \u003cslug\u003e.hanzo.app).","description":"Creates a project seeded from a PUBLISHED EXAMPLE — either a\nstarter-kit template from the ONE embedded gallery catalog, or any live\nproject on the platform (an example a seeded creator published, or another\norg's app serving at \u003cslug\u003e.hanzo.app). Answers 201 with the new project.\n\n`slug` names the PARENT to fork and is required. Templates resolve first, and\nthe caller org's own private templates ahead of the public gallery, so a\ncurated template slug keeps meaning the same thing even if someone later\npublishes a live project under it; `variant` picks that template's\nformat/page/theme. If no template matches, the slug resolves to the UNIQUE\nlive project that owns it across all orgs — the same resolution the site edge\nuses to serve \u003cslug\u003e.hanzo.app, so what you can browse is what you can fork.\n\n`name` and `target` override the derived project name and slug; everything\nelse is inherited from the parent. A live parent contributes its REPO, so the\nchild builds from the same source — the parent's deployed bytes are never\ncopied, because releases are per-tenant by design and the fork publishes its\nown. The parent it actually resolved is stamped on the child as `forkedFrom`,\nso attribution is a fact recorded at fork time rather than a claim\nreconstructed later.\n\nA gallery template is COPIED instead: its source becomes a new private\nrepository in the org's own code workspace on the forge — made on this first\nneed if the org has none — and the project's `repo` is that copy, so what the\norg changes is its own and never the template everybody forks. A copy that\ncannot be made fails the fork with the forge's reason, and nothing is left\nbehind. The copy is then published: built from its repository in a sandbox\nand served at the project's own address, answering `status: building` until\nit is `live`. Unless `target` names the project, its slug is numbered past\nany the org holds and any address another project serves at, so the copy has\nan address of its own to publish to.\n\nIt funnels through the SAME create path POST /v1/project uses, so slug\nvalidation, org scoping, ID minting and the 409 on a slug the caller's own org\nalready uses are identical.\n\nScope: a validated principal is required (401 without one) and the child is\ncreated in THAT principal's org.","tags":["project"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsFork"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsProject"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true}},"/v1/project/sites":{"get":{"operationId":"get_project_sites","summary":"Returns the org's deployed sites at the pretty URLs they serve at.","description":"Returns the org's deployed sites at the pretty URLs they serve at.\n\nIt reads the SAME org-scoped store as /v1/project and keeps only the projects\nthat are actually `live`, so a draft or a failed build is not advertised as a\nsite.\n\nScope: a validated principal is required (401 without one) and the list is\nkeyed by that principal's org.","tags":["project"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/project.projectsSite"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true},"post":{"operationId":"post_project_sites","summary":"Generates a self-contained, mobile-responsive static site from a natural-language brief and deploys it live in one call.","description":"Generates a self-contained, mobile-responsive static site from a\nnatural-language brief and deploys it live in one call.\n\nOne inference call turns `brief` (capped at 8 KiB) into a file manifest, which\nthen runs through the SAME validation, guards and viewport guarantee as a\nhand-supplied manifest: index.html required at the root, absolute and\ntraversal paths rejected, per-file and total size capped, and a mobile\nviewport meta tag injected into every HTML document that lacks one. The\ngenerated site is fully inline — no CDNs, no remote fonts or images — so it is\nCSP-safe. `slug` and `name` are optional: the model's own title is preferred,\nand a slug is derived or minted when none is given.\n\nIt writes into the SAME org-scoped store as /v1/project — it ensures a\nproject (framework `static`) for the resolved slug and records a deployment —\nso this is a second entry point to one publish pipeline, not a second copy of\nproject state. Publishing is free; what is billed is the model's tokens, to the\ncaller's own ledger, and the storage the org holds past the free tier. The\nstorage gate runs BEFORE any inference or upload, so an org past the tier that\ncannot pay a month of what it holds (402, or 503 when commerce is unreachable)\ngenerates and uploads NOTHING.\n\nAnswers 503 when object storage or inference is unconfigured, and 400 when the\nmodel's manifest cannot be parsed or fails the guards.\n\nScope: a validated principal is required (401 without one) and the site is\npublished into THAT principal's org.","tags":["project"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsBuildSite"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsSiteDeploy"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true}},"/v1/project/sites/deploy":{"post":{"operationId":"post_project_sites_deploy","summary":"Deploys a caller-supplied file manifest — the deploy_site capability an agent calls — and answers with where it went live.","description":"Deploys a caller-supplied file manifest — the deploy_site\ncapability an agent calls — and answers with where it went live.\n\n`files` is a list of {path, content} pairs, the same shape the brief build\nemits, and it runs through the SAME guards: index.html required at the root,\nabsolute and traversal paths rejected, per-file and total size capped, and a\nmobile viewport meta tag injected into every HTML document that lacks one — so\na hand-built site is exactly as safe and as responsive as a generated one.\n`slug` and `name` are optional; a slug is derived from the name or minted.\n\nIt writes into the SAME org-scoped store as /v1/project, ensuring a project\n(framework `static`) for the resolved slug and recording a deployment. It is\nfree: the site is billed for the storage its org holds past the free tier, and\nthe storage gate runs before the upload, refusing (402) an org past the tier\nthat cannot pay a month of what it holds. Answers 503 when object storage is\nunconfigured.\n\nScope: a validated principal is required (401 without one) and the site is\npublished into THAT principal's org.","tags":["project"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsDeploySite"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsSiteDeploy"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true}},"/v1/project/sites/{slug}":{"get":{"operationId":"get_project_sites_by_slug","summary":"Returns one site — the same row ListSites carries, for one slug.","description":"Returns one site — the same row ListSites carries, for one slug.\n\nEvery sub-resource under a site already answered: deployments, releases,\npublish. The site itself did not, and a route that is never registered\nanswers 404 for a LIVE site exactly as it does for one that was never\ncreated. So the one call a client makes to ask \"is it there yet?\" could only\never say no, and a CI lane watching for its own publish would wait forever on\na success it had already achieved.\n\nThe org is the caller's, never a path segment. A slug is unique within an org\nand two orgs may both own `tel`; taking the org from the validated principal\ninstead of the URL means a caller cannot read another org's site by editing a\npath, and it is the same scope ListProjects and ListSites already use.\n\nA site that exists but is not live is NOT found here, matching ListSites,\nwhich keeps only `live` rows so a draft or a failed build is never advertised\nas a site. One definition of \"is a site\", used by both.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the project to act on, from the path. It is unique within the\ncaller's org and nowhere else, so another tenant's slug is a 404.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsSite"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true}},"/v1/project/tags":{"get":{"operationId":"get_project_tags","summary":"The site's browser tag set for the hosted tag — which pixels to inject, by publishable key","description":"Returns the client-side pixels the SITE has connected (GA4, Google Ads, LinkedIn, Meta, Pinterest, Reddit, TikTok, X) with their NON-SECRET ids, so the hosted tag injects them first-party and stamps each browser event with the same event_id the server-side Conversions API uses — deduping the two. Resolved per site: by the publishable key on ?key= when it names a project, else by the request host, so hanzo.ai and hanzo.chat carry different tags under one org. WITHOUT a resolvable site it answers an empty set at 200 — a page never breaks on its tag config. `audience` says who is asking — `bot` (automation, a crawler, or a cloud provider's published address), `internal` (a member of the site's org, by the IAM bearer the page sends, or an address in the project's internal networks) or `person` — and the set answers for it: nothing for a bot, Google Analytics alone for the team. A site that reports to several Meta pixels names each (comma separated on the project's `meta`), and each is a tag of its own. `consent` is the visitor's rule for the third-party tags, decided per request from the country and US state Cloudflare attests: `eu` (the EU, the EEA, the UK and Switzerland, and any visitor no edge placed: before a choice Google Analytics runs cookieless under Consent Mode denied, Meta is held revoked, nothing else loads), `us_privacy` (a US state with a privacy law, or a US visitor with no attested state: everything runs, the visitor opts out of sale or sharing) or `global` (everywhere else: everything runs, with a notice); `defaults` is the categories granted before a choice, `refused` says the request carried Global Privacy Control or Do Not Track (no third party loads, in any region), and a choice's grants count when stored under a version from `floor` to `version`. The tag set is the same under every rule; the page gates it. The answer is per visitor and never cached by a shared cache. The site's own first-party stream is not governed by it.","tags":["project"],"responses":{"2XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tagConfig"}}},"description":"Success"}},"x-app":"project","x-public":true}},"/v1/project/{slug}":{"delete":{"operationId":"delete_project_by_slug","summary":"Deletes a project and takes its site off the internet.","description":"Deletes a project and takes its site off the internet.\n\nThe metadata delete is authoritative and everything after it is best-effort,\nin this order: the public `\u003cslug\u003e` subdomain binding is released so the slug is\nfree to reclaim, the release rows are dropped so a reclaimed slug never\ninherits the previous owner's rollback menu, the git source is retired on\nevery copy it has so a reclaimed slug never adopts a repository left behind\n(visibility.go), the S3 origin is purged under BOTH `\u003corg\u003e/\u003cslug\u003e/` and the\nsite's sibling release space, and the edge cache-tag is flushed. A failure in\nany of those is logged and the delete still answers 204 — resurrecting a\nproject because a purge missed would be worse than a leaked prefix.\n\nScope: a validated principal is required (401 without one) and the project is\nresolved within that principal's org, so another tenant's slug is a 404 and\nnothing of theirs is touched.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the project to act on, from the path. It is unique within the\ncaller's org and nowhere else, so another tenant's slug is a 404.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true},"get":{"operationId":"get_project_by_slug","summary":"Returns one project of yours by slug — its settings, its live URL and the deployment currently serving it.","description":"Returns one project of yours by slug — its settings, its live URL\nand the deployment currently serving it.\n\nScope: a validated principal is required (401 without one) and the lookup is\nkeyed by (org, slug), so another tenant's slug is a 404 exactly like a\nnonexistent one.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the project to act on, from the path. It is unique within the\ncaller's org and nowhere else, so another tenant's slug is a 404.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsProject"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true},"patch":{"operationId":"patch_project_by_slug","summary":"Changes a project's settings, and only the settings you send.","description":"Changes a project's settings, and only the settings you send.\n\nEvery field is optional and absent means \"leave it\": `name` may not be blanked,\n`framework` must stay a known build hint, and `cacheControl` is capped at 256\ncharacters with no newlines (it becomes a response header). `visibility` flips\npublic/private under the same rule as create — public is free, private needs a\nfunded org. `upstream` and `license` are free-text credit for third-party work,\nand sending \"\" clears one. Changing anything reconciles the project's canonical\ngit repo, so a visibility change reaches the source and not just the listing.\n\nSending `repo` decides the site's `namespace` again: the repository's GitHub\norg when this org holds that GitHub account, else the org. Linking a\nrepository in another account refuses (409) a move that is not safe: a site\nwith releases, a published site whose objects are not already copied to\n`\u003cnamespace\u003e/\u003cslug\u003e/`, a prefix something else already keeps objects at.\nSending the same repository moves the site only where that is safe, and\notherwise leaves it where it is. Nothing is copied here.\n\n`hidden`/`hiddenReason` are platform MODERATION and are ignored unless the\ncaller is a platform admin; they remove a project from the public catalogue\nwithout touching the publisher's own visibility choice, so un-hiding restores\nexactly what they asked for.\n\nScope: a validated principal is required (401 without one) and the project is\nresolved within that principal's org, so another tenant's slug is a 404.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the project to update, from the path. The URL is the addressing\nauthority — a `slug` in the body cannot move the write to another project.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsUpdate"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsProject"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true}},"/v1/project/{slug}/deploy":{"post":{"operationId":"post_project_by_slug_deploy","summary":"Upload a built site as one archive and serve it","description":"Takes a built site live at `https://\u003cslug\u003e.hanzo.app` in one call. The body is the site itself — a `zip` or `tar.gz` holding `index.html` at its root (or a single wrapper directory that does), sent raw or as a multipart file part. It is unpacked to the site's own storage prefix and served immediately, answering the finished deployment.\n\nIt is bounded by the edge body limit (16 MiB by default), and that bound is the whole reason the other path exists: an oversized POST is refused by the server BEFORE any handler runs and surfaces as an opaque `400 Error when parsing request` that reads like a malformed payload rather than a size cap. A site too large for one archive opens a deployment with `POST /v1/project/{slug}/deployments` instead and writes its files straight to storage against the scoped grant that answers with — no body limit, and no bytes through this API at all.\n\nPublishing is free: no deploy is charged, and an org with no balance can publish and republish. A site is billed for the storage its org holds past the free tier, metered hourly; an org already past the tier must be able to pay a month of that storage, or the upload is refused 402 (503 when commerce is unreachable) BEFORE anything is parsed or written. A failed upload never flips the live site, and a redeploy replaces the site's files and answers the SAME URL, because slug and apex are stable.\n\nScope: a validated principal is required (401 without one) and the site is resolved within that principal's org, so another tenant's slug is a 404. Object storage must be configured (503); an archive that does not walk is a 400 and one over the size cap is a 413.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/octet-stream":{"schema":{"format":"binary","type":"string"}}}},"responses":{"2XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/projectsDeployment"}}},"description":"Success"}},"x-app":"project","x-public":true}},"/v1/project/{slug}/deployments":{"get":{"operationId":"get_project_by_slug_deployments","summary":"Returns a project's deploy history, newest version first.","description":"Returns a project's deploy history, newest version first.\n\nEvery deploy of the project is a row — uploads, generated sites, and git/CI\nbuilds alike — carrying its version, status, source, commit, live URL, file\ncount and byte count. The short-lived upload grant a queued git deployment was\nhanded is NOT replayed here: it exists only on the 202 that minted it, so a\ngrant cannot outlive its build by being fetched again.\n\nScope: a validated principal is required (401 without one) and the project is\nresolved within that principal's org, so another tenant's slug is a 404.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the project to act on, from the path. It is unique within the\ncaller's org and nowhere else, so another tenant's slug is a 404.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/project.projectsDeployment"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true},"post":{"operationId":"post_project_by_slug_deployments","summary":"Opens a deployment and hands back a short-lived, prefix-scoped grant to write its bytes straight to object storage.","description":"Opens a deployment and hands back a short-lived, prefix-scoped\ngrant to write its bytes straight to object storage. Answers 202.\n\nThis is the path for a site too large to send as one archive: a real export is\nhundreds of megabytes against a 16 MiB body limit, so the bytes deliberately do\nNOT pass through the API. The answer carries `bucket`, `prefix` and `upload` —\na presigned POST policy that S3 itself confines to this site's prefix\n(starts-with `\u003corg\u003e/\u003cslug\u003e/`), expires in 30 minutes and bounds each object.\nSo a build writes its own files and holds no standing bucket credential; there\nis nothing to rotate and nothing that leaks between tenants. Never guess the\nprefix — it is server-derived, and a guessed one lands where nothing is served.\n\nThe deployment is `queued` until POST .../deployments/{id}/complete flips it\nlive (or error). That completion is also where DELETION happens: the grant\nauthorizes writes only, so a build cannot remove a file, and cloud reconciles\nthe prefix against the `keys` manifest the completion carries. A build that\ndies before completing leaves the deployment queued rather than a half-live\nsite.\n\nThe grant is on the 202 and NOWHERE else — it is never stored and never\nreplayed on a later read, so it cannot outlive the build it was minted for. A\ndeployment whose grant could not be minted is still created and still\ncompletable; it simply carries no `upload`, and a caller with no other way to\nwrite should treat that as the failure it is.\n\nBilling: the deployment is free. The one gate is storage, and it runs BEFORE\nanything is created: an org past the free storage tier that cannot pay a month of\nwhat it holds is 402, and 503 when commerce is unreachable. What the build uploads\nis billed as storage from the hourly sweep that finds it, never as a deploy.\n\nScope: a validated principal is required (401 without one) and the site is\nresolved within that principal's org, so another tenant's slug is a 404.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the site to deploy, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsDeployStart"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsDeployment"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true}},"/v1/project/{slug}/deployments/{id}":{"get":{"operationId":"get_project_by_slug_deployments_by_id","summary":"Returns one deployment of a project by id.","description":"Returns one deployment of a project by id.\n\nIt is how a console follows a build: the status (`queued`, `uploading`,\n`live`, `error`), the message a failure left, and the URL and prefix it went\nlive at. Like the history, it never replays the upload grant.\n\nScope: a validated principal is required (401 without one). Both the project\nand the deployment are resolved within that principal's org, so a deployment\nof another project — or of another tenant — is a 404.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the project the deployment belongs to, from the path.","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"description":"ID is the deployment id, from the path. A deployment of another project —\nor of another tenant's project — is not found.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsDeployment"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true}},"/v1/project/{slug}/deployments/{id}/complete":{"post":{"operationId":"post_project_by_slug_deployments_by_id_complete","summary":"CompleteDeployment is the CI completion hook that flips a queued git deployment to live (or error) once CI has synced the built site to S3.","description":"CompleteDeployment is the CI completion hook that flips a queued git\ndeployment to live (or error) once CI has synced the built site to S3.\n\n`status` must be `live` or `error`. On a LIVE completion the public host is\nclaimed FIRST, so the deployment reports the URL it actually OWNS — a\nCI-supplied `liveUrl` is a hint that can refine that URL but can never assert\na subdomain another tenant holds. `keys` is the manifest CI just uploaded,\nrelative to the deployment prefix: cloud reconciles the prefix against it so a\npage deleted from the build actually stops serving. Omit `keys` and nothing is\ndeleted — the prefix only grows. Reconciliation runs only on a live completion\n(pruning against a failed build's manifest would delete the site the last good\nbuild is still serving) and is best-effort, so a stale leftover never turns a\nsuccessful deploy into a 500. No completion is charged: the site is billed for\nthe storage it holds, and a live completion re-measures its org.\n\nScope: a validated principal is required (401 without one). CI authenticates\nwith an org-scoped token through the gateway, so the deployment is resolved\nwithin that principal's org and another tenant's slug or deployment id is a\n404.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the project the deployment belongs to, from the path.","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"description":"ID is the queued deployment to complete, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsComplete"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsDeployment"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true}},"/v1/project/{slug}/domains":{"get":{"operationId":"get_project_by_slug_domains","summary":"Returns every custom hostname this site holds: the live ones, plus any pending claim with the DNS records it still owes.","description":"Returns every custom hostname this site holds: the live ones, plus\nany pending claim with the DNS records it still owes.\n\n`domains` is the routing answer — the hosts that are verified right now —\nwhile `claims` is the full panel, one row per host, each saying whether it is\nlive or pending and, if pending, exactly what to publish.\n\nScope: a validated principal is required (401 without one) and the site is\nresolved within that principal's org, so another tenant's slug is a 404.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the project to act on, from the path. It is unique within the\ncaller's org and nowhere else, so another tenant's slug is a 404.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsDomains"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true},"post":{"operationId":"post_project_by_slug_domains","summary":"Attaches one or more CUSTOM public hostnames to this org's site.","description":"Attaches one or more CUSTOM public hostnames to this org's site.\n\nBinding a host you do not own would let you shadow it at the edge, so which\noutcome you get depends on whether ownership is already established: a SuperAdmin\nvouches (the operator manages the customer's DNS, so its bind IS the proof) and\nbinds VERIFIED immediately; every other caller, INCLUDING an admin of the\ndeployment's own brand org, has the host CLAIMED as pending and gets the DNS\nchallenge back in `bound[].records`. A pending claim HOLDS the name so nobody\nelse can take it, but it does not route until POST .../domains/{host}/verify\nproves control.\n\nA hostname we operate is refused to a non-vouched caller (those are assigned\nby the platform, never claimed), a host another site already holds is a 409,\nand a name the platform holds is a 400 for EVERY caller — a vouch skips the\nownership proof, never the host table's own invariant. Claims and binds are\nidempotent for the same\n(org, slug), and re-claiming returns the SAME token rather than invalidating a\nrecord the customer has already published. The edge cache-tag is flushed\nafterwards so a newly-verified host serves the current build immediately.\n\nScope: a validated principal is required (401 without one) and the site is\nresolved within that principal's org, so another tenant's slug is a 404.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the site the hosts attach to, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsDomainsBind"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsBoundDomains"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true}},"/v1/project/{slug}/domains/{host}":{"delete":{"operationId":"delete_project_by_slug_domains_by_host","summary":"Gives a custom hostname back, so the name is free to reuse.","description":"Gives a custom hostname back, so the name is free to reuse.\n\nA claim is FIRST-COME and global, so ownership includes giving a name back: a\ncustomer who mistyped a domain, or moved one elsewhere, releases it here and\nthe name is free for them or anyone else. The release is scoped to (host, org,\nslug), so it can only ever drop THIS tenant's own claim, and it is IDEMPOTENT:\nreleasing a host we do not hold is a clean 204, never a 404 that would let a\ncaller probe which hosts other tenants hold. The edge cache-tag is flushed,\nsince the host stops routing here.\n\nScope: a validated principal is required (401 without one) and the site is\nresolved within that principal's org, so another tenant's slug is a 404.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the project the host is attached to, from the path.","schema":{"type":"string"}},{"name":"host","in":"path","required":true,"description":"Host is the custom hostname, from the path. It is cleaned to its canonical\nform (lowercased, trailing dot dropped) before anything is looked up.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true}},"/v1/project/{slug}/domains/{host}/verify":{"post":{"operationId":"post_project_by_slug_domains_by_host_verify","summary":"Checks the DNS challenge for a pending custom hostname and, when it passes, promotes the host so it begins routing at the edge.","description":"Checks the DNS challenge for a pending custom hostname and, when\nit passes, promotes the host so it begins routing at the edge.\n\nIt answers 200 either way, with the host's honest current state: verified once\nthe TXT record is found, still pending — with the records to publish and the\nresolver's own explanation in `detail` — when it is not. A not-yet is not an\nerror: the check ran, DNS simply has not propagated, and the customer retries.\nAn already-verified host is returned unchanged without re-resolving. On a\nsuccessful promotion the edge cache-tag is flushed, since the host routes as\nof that moment.\n\nScope: a validated principal is required (401 without one). Both the site and\nthe claim are resolved within that principal's org, so a host claimed by\nanother tenant is \"not claimed by this site\".","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the project the host is attached to, from the path.","schema":{"type":"string"}},{"name":"host","in":"path","required":true,"description":"Host is the custom hostname, from the path. It is cleaned to its canonical\nform (lowercased, trailing dot dropped) before anything is looked up.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsDomain"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true}},"/v1/project/{slug}/publish":{"post":{"operationId":"post_project_by_slug_publish","summary":"Promotes a build output into a new release AND goes live with it — create+activate in one call, which is the 99% path.","description":"Promotes a build output into a new release AND goes live with it —\ncreate+activate in one call, which is the 99% path.\n\nIt is exactly the two halves in sequence with no extra semantics, so the\nstaged flow and the one-shot flow can never drift apart: `source` is promoted\nunder the same org-relative rule and the same guards CreateRelease applies,\nthen the site's pointer is flipped to it, the public host is claimed and the\nedge is purged. Idempotent on unchanged bytes — same manifest, same release id,\nno copy, and so nothing more stored. Free, behind the same storage gate.\n\nScope: a validated principal is required (401 without one) and the site is\nresolved within that principal's org, so another tenant's slug is a 404.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the site to publish, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsPublish"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsRelease"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true}},"/v1/project/{slug}/purge":{"post":{"operationId":"post_project_by_slug_purge","summary":"Flushes the site's edge cache without redeploying anything.","description":"Flushes the site's edge cache without redeploying anything.\n\nIt invalidates the edge cache-tag `site-\u003cnamespace\u003e-\u003cslug\u003e` and stamps `lastPurgeAt`\n(unix seconds), and it NEVER writes or deletes the S3 origin — the live build\nkeeps serving; only stale copies held at the edge drop, so the next request\nre-fetches the current artifact from origin. Idempotent, and an edge that is\nunconfigured or failing is not fatal: `lastPurgeAt` is still stamped and the\nanswer is still the updated project.\n\nScope: a validated principal is required (401 without one) and the project is\nresolved within that principal's org, so another tenant's slug is a 404.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the project to act on, from the path. It is unique within the\ncaller's org and nowhere else, so another tenant's slug is a 404.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsProject"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true}},"/v1/project/{slug}/releases":{"get":{"operationId":"get_project_by_slug_releases","summary":"Returns a site's releases newest-first, marking the active one — the rollback menu.","description":"Returns a site's releases newest-first, marking the active one —\nthe rollback menu.\n\nEach row carries the release id to activate, the source it was promoted from,\nits object and byte counts, and the URL if it is the one serving. Retention\nbounds the list, so it is the set that can actually still be rolled back to,\nnot a full history.\n\nScope: a validated principal is required (401 without one) and the site is\nresolved within that principal's org, so another tenant's slug is a 404.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the project to act on, from the path. It is unique within the\ncaller's org and nowhere else, so another tenant's slug is a 404.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/project.projectsRelease"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true},"post":{"operationId":"post_project_by_slug_releases","summary":"Promotes a build output into a new immutable release WITHOUT serving it — the staged half of publishing, for when you want to check a release before it goes live.","description":"Promotes a build output into a new immutable release WITHOUT\nserving it — the staged half of publishing, for when you want to check a\nrelease before it goes live. Answers 201.\n\n`source` is a path RELATIVE to your org's own storage space: the org segment\nis prepended server-side from the validated principal and the bucket is never\nin the request at all, so a server-side copy can only ever reach bytes your\norg already owns. The prefix is listed, content-addressed (SHA-256 over the\nsorted manifest of key/size/etag), and copied into an immutable\n`\u003corg\u003e/.releases/\u003cslug\u003e/\u003cid\u003e/` prefix; the row is written LAST, so a partial\ncopy is unreachable rather than merely unlikely. Re-publishing an unchanged\nsource is idempotent BY CONSTRUCTION — same bytes, same id, no copy at all.\n\nThe source must contain index.html at its root and stay under the same file\nand byte caps an artifact deploy does (413 past them); a source that changes\nmid-copy is a 409 and the release is abandoned. Each publish also reclaims\nreleases past the retention depth, so a site's release space stays bounded.\nCreating a release is free. A retained release is stored bytes, so it counts\ntoward the org's storage until retention reclaims it; the storage gate runs\nbefore any copy, refusing (402) an org past the free tier that cannot pay a\nmonth of what it holds.\n\nScope: a validated principal is required (401 without one) and the site is\nresolved within that principal's org, so another tenant's slug is a 404.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the site to publish, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsPublish"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsRelease"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true}},"/v1/project/{slug}/releases/{release}/activate":{"post":{"operationId":"post_project_by_slug_releases_by_release_activate","summary":"Points the site at an existing release — the go-live, and equally the ROLLBACK.","description":"Points the site at an existing release — the go-live, and\nequally the ROLLBACK.\n\nAim it at an older release and the site serves that one again: releases are\nimmutable and retained to the retention depth, so nothing is rebuilt or\nre-copied and the flip is one atomic statement. Before the flip, two\nconditions run in the order that gives each its own honest answer — the ROW\nsays whether this release exists for this tenant at all (404, with no signal\nabout a foreign id), and only then do the BYTES say whether it can still serve\n(410 GONE when retention has reclaimed them; that rollback target is not\ncoming back, so publish again). Going live also claims the public host and\npurges the edge, so the release is reachable and no cached predecessor is\nserved. NOT billed: no new content is produced, only a pointer moved.\n\nScope: a validated principal is required (401 without one) and the site is\nresolved within that principal's org, so another tenant's slug is a 404.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the site the release belongs to, from the path.","schema":{"type":"string"}},{"name":"release","in":"path","required":true,"description":"Release is the content-addressed release id (\"rel_\" + 32 hex chars), from\nthe path. Anything that is not that shape is not found, rather than being\ninterpolated into a storage prefix.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsRelease"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true}},"/v1/project/{slug}/shot":{"get":{"operationId":"get_project_by_slug_shot","summary":"Get a PNG of the project's live site","description":"Returns a screenshot of what this project currently serves, as image/png. The capture is keyed by the deployment, so a redeploy invalidates it by construction rather than by anyone remembering to clear a cache. A project with nothing deployed answers 404 — that is a 404 about the PICTURE and not about the project, which is still right there in the list. Scoped to the caller's org: a validated principal is required, and a slug belonging to another org is not found rather than forbidden.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"project","x-public":true}},"/v1/project/{slug}/star":{"delete":{"operationId":"delete_project_by_slug_star","summary":"Removes the caller's own bookmark from a project, and answers whether it is starred afterwards.","description":"Removes the caller's own bookmark from a project, and answers whether\nit is starred afterwards.\n\nIt removes only YOUR star — the same one star wrote — so a project other\npeople have starred stays on their lists. Unstarring one you had not starred\nis not an error; it leaves it unstarred.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the project to act on, from the path. It is unique within the\ncaller's org and nowhere else, so another tenant's slug is a 404.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsStar"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true},"put":{"operationId":"put_project_by_slug_star","summary":"Bookmarks a project for the person calling, and answers whether it is starred afterwards.","description":"Bookmarks a project for the person calling, and answers whether it is\nstarred afterwards.\n\nThe star is YOURS: it is keyed by you as well as by the project, so two people\nsee two answers for the same one and starring it says nothing about anybody\nelse's list. Starring a project you have already starred leaves it starred.","tags":["project"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the project to act on, from the path. It is unique within the\ncaller's org and nowhere else, so another tenant's slug is a 404.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/project.projectsStar"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"project","x-public":true,"x-tool":true}},"/v1/prompt":{"get":{"operationId":"get_prompt","summary":"Returns the caller org's prompt library as one row per prompt: its name, type, every version number it has, its taxonomy and when it last changed.","description":"Returns the caller org's prompt library as one row per prompt: its name,\ntype, every version number it has, its taxonomy and when it last changed. The\ntemplate bodies are deliberately absent — fetch one prompt to read its text.","tags":["prompt"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/prompt.promptList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"prompt","x-public":true,"x-tool":true},"post":{"operationId":"post_prompt","summary":"Records a prompt for the caller's org and answers 201 with it.","description":"Records a prompt for the caller's org and answers 201 with it. A name the\norg already uses is NOT an error and NOT an overwrite: it appends a new version,\nso the library keeps real, inspectable history and the response carries the whole\nversion list. The name is also the URL segment the prompt is fetched by, which is\nwhy its shape is constrained and a handful of names are reserved.","tags":["prompt"],"requestBody":{"content":{"application/json":{"example":{"name":"greeting","prompt":"You are a helpful assistant.","tags":["support"]},"schema":{"$ref":"#/components/schemas/prompt.promptReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/prompt.promptDetail"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"prompt","x-public":true,"x-tool":true}},"/v1/prompt/catalog":{"get":{"operationId":"get_prompt_catalog","summary":"Returns the read-only starter prompt library shipped with the binary — reference content every tenant sees the same, NOT the caller's own prompts and never mixed into them.","description":"Returns the read-only starter prompt library shipped with the binary —\nreference content every tenant sees the same, NOT the caller's own prompts and\nnever mixed into them. An org's library stays honestly empty until someone\nexplicitly imports a starter, which is an ordinary POST /v1/prompt. Entries that\nwould fail the create guards are dropped, so everything offered here can actually\nbe imported.","tags":["prompt"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/prompt.catalogList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"prompt","x-public":true,"x-tool":true}},"/v1/prompt/metrics":{"get":{"operationId":"get_prompt_metrics","summary":"Returns real per-prompt statistics for the caller's org: how many versions each prompt has, which one is current, and when it was created and last changed.","description":"Returns real per-prompt statistics for the caller's org: how many versions\neach prompt has, which one is current, and when it was created and last changed.\nEvery number is counted from the store — nothing here is estimated or fabricated.","tags":["prompt"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/prompt.metricList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"prompt","x-public":true,"x-tool":true}},"/v1/prompt/{name}":{"delete":{"operationId":"delete_prompt_by_name","summary":"Delete removes one of the caller org's prompts and every version of it, answering 204.","description":"Delete removes one of the caller org's prompts and every version of it, answering\n204. It is scoped to the caller's org, so a name another tenant owns is the same\n404 an unknown name gives. There is no undo: the version history goes with it.","tags":["prompt"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the prompt to act on, from the path.","schema":{"type":"string"},"example":"greeting"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"prompt","x-public":true,"x-tool":true},"get":{"operationId":"get_prompt_by_name","summary":"Returns one of the caller org's prompts: its CURRENT template text plus the metadata of every version it has had.","description":"Returns one of the caller org's prompts: its CURRENT template text plus the\nmetadata of every version it has had. The history carries version numbers, types\nand timestamps only — not each version's body — so a long history cannot inflate\nthis response. A name the caller's org does not own is 404, whoever owns it.","tags":["prompt"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the prompt to act on, from the path.","schema":{"type":"string"},"example":"greeting"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/prompt.promptDetail"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"prompt","x-public":true,"x-tool":true}},"/v1/provider":{"get":{"operationId":"get_provider","summary":"Returns every registered integration provider together with THIS org's connection status for it — the catalog the console's Integrations page renders.","description":"Returns every registered integration provider together with THIS org's\nconnection status for it — the catalog the console's Integrations page renders.\nOrg-authed: a caller with no validated principal is 403, because the status is\nper-org and there is no org-less answer. User-plane providers (the /v1/connection\nsurface) are omitted; the two planes are disjoint.","tags":["provider"],"responses":{"200":{"content":{"application/json":{"example":{"providers":[{"available":true,"category":"Communication","connected":true,"connection":{"account":"Acme","connectedAt":"2026-07-01T10:00:00Z","externalId":"T0231","scopes":["chat:write"]},"description":"Connect your workspace.","id":"slack","name":"Slack"}]},"schema":{"$ref":"#/components/schemas/provider.listOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/discord/interactions":{"post":{"operationId":"post_provider_discord_interactions","summary":"Discord interactions endpoint","description":"The Interactions Endpoint URL for the Discord app. It answers Discord's PING with a PONG, and handles the `/hanzo` slash command by acknowledging with a deferred ephemeral reply and editing that reply with the answer once the agent has run. Any other interaction is acknowledged and ignored.\n\nRequests are verified by ED25519 SIGNATURE over the timestamp and body against the app's public key — not by HMAC, unlike the Slack webhooks. Interactions work over plain HTTP, so no gateway connection and no message-content intent is involved.\n\nDiscord does not retry, so this is the one channel where being at capacity is shown to the user as an ephemeral ask-to-run-it-again rather than answered as a retriable failure — nothing is recorded either way, so the next attempt is clean.\n\nThe caller here is the PLATFORM, not a Hanzo tenant, so there is no bearer and no principal. The signature check IS the authentication, and it fails closed. The tenant is never read from the payload either: it is resolved from the verified platform identifier through the connection map, so an event from a workspace nobody connected does nothing. Refusals are written with their own status rather than being flattened to a 500, so a rejected signature reads as 401 and a malformed body as 400.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/discord/link":{"get":{"operationId":"get_provider_discord_link","summary":"Begin linking a Hanzo account from Discord","description":"The entry point behind the connect prompt Hanzo shows in a Discord server. It starts a link session and redirects to Discord's OAuth `identify` consent — the narrowest scope that establishes which Discord user is asking, and nothing more.\n\nThis is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/discord/link/callback":{"get":{"operationId":"get_provider_discord_link_callback","summary":"Complete the Discord account link","description":"The final leg: it binds the verified Discord user to the Hanzo account that just signed in, and answers a short confirmation page telling them to return to Discord. The Hanzo credential is sealed into the connected org's KMS namespace rather than stored beside the link.\n\nThis is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/discord/link/discord":{"get":{"operationId":"get_provider_discord_link_discord","summary":"Discord sign-in return leg","description":"Where Discord returns the user after the identify consent. It resolves the verified Discord user, confirms the server is connected to an org, and hands the browser to the Hanzo sign-in that completes the link.\n\nThis is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/forge/webhook":{"post":{"operationId":"post_provider_forge_webhook","summary":"Forge workflow_job webhook","description":"Receives the forge's workflow_job delivery. The signature over the raw body is checked against the secret at KMS forge.WebhookRef before anything is decoded; a queued job becomes one ephemeral runner Job on the cluster, minted a registration token for exactly that job. Every other action is answered 200 and ignored.","tags":["provider"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/forgeJob"}}}},"responses":{"2XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/forgeLaunched"}}},"description":"Success"}},"x-app":"provider","x-public":true}},"/v1/provider/github/fork":{"post":{"operationId":"post_provider_github_fork","summary":"Forks a granted repository.","description":"Forks a granted repository.\n\nGitHub's fork is ASYNCHRONOUS: it answers 202 with the target repo and\npopulates it in the background, and it answers the same 202 when the fork\nalready exists. So this reports what GitHub said rather than waiting — a call\nthat blocked until the clone finished would time out on a large repository and\ntell the caller nothing it does not already know.","tags":["provider"],"requestBody":{"content":{"application/json":{"example":{"repo":"widgets"},"schema":{"$ref":"#/components/schemas/provider.githubForkReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"clone_url":"https://github.com/acme/widgets.git","default_branch":"main","existing":false,"full_name":"acme/widgets","html_url":"https://github.com/acme/widgets"},"schema":{"$ref":"#/components/schemas/provider.githubForkOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/github/installations":{"get":{"operationId":"get_provider_github_installations","summary":"Lists the GitHub accounts the caller may see the App installed on, each confirmed against the App's own list, plus where to add another.","description":"Lists the GitHub accounts the caller may see the App\ninstalled on, each confirmed against the App's own list, plus where to add\nanother.\n\nThe confirmation is the point. A connection row holds an installation id, and\nan id whose installation was since removed on GitHub is a row that mints\nnothing — every list and import against it fails with a token error, which\nreads as \"our git integration is broken\" rather than \"that install is gone\".\nChecking the App's view turns that into a fact the caller can act on.\n\nORG-SCOPED for a tenant, deliberately. The App is installed across every\ncustomer, so the raw list is the customer list; a tenant sees only accounts its\nown org has bound. It discovers a NEW account by installing it (InstallURL),\nwhich is GitHub's own consent screen — not by reading ours.\n\nA SUPER ADMIN sees the App's whole install list, because that list is the\nplatform's own inventory rather than any one tenant's data, and platform sudo\nis the single cross-tenant scope this house has. Without it an App installed\nout-of-band — granted straight from GitHub, so no connect flow ever ran and no\nconnection row exists — is invisible to everyone: the console card reads \"not\nconnected\" and an operator asked \"which GitHub orgs do you see\" can only\nanswer for accounts already bound, which is precisely the accounts that were\nnever the question.","tags":["provider"],"responses":{"200":{"content":{"application/json":{"example":{"installUrl":"https://github.com/apps/hanzo/installations/new","installations":[{"connected":true,"grant":"all","htmlUrl":"https://github.com/hanzoai","login":"hanzoai","type":"Organization"}]},"schema":{"$ref":"#/components/schemas/provider.githubInstallationsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/github/issues/backfill":{"post":{"operationId":"post_provider_github_issues_backfill","summary":"Seeds the native todo with the EXISTING issues across the org's granted repos (default state=open); the webhook keeps them live thereafter.","description":"Seeds the native todo with the EXISTING issues across the\norg's granted repos (default state=open); the webhook keeps them live thereafter.\nOrg-scoped by the validated principal — a caller only ever backfills its OWN org.\nSynchronous + bounded (a total time budget and an issue cap) so it returns the\ncounts directly; idempotent by ExtRef, so a re-run continues where a truncated\npass left off and never duplicates.","tags":["provider"],"requestBody":{"content":{"application/json":{"example":{"repo":"acme/api","state":"all"},"schema":{"$ref":"#/components/schemas/provider.githubBackfillIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"created":410,"failed":0,"issues":430,"repos":12,"updated":20},"schema":{"$ref":"#/components/schemas/provider.githubBackfillResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/github/repos":{"get":{"operationId":"get_provider_github_repos","summary":"Lists the GitHub repositories the caller may work on, most recently pushed first, searched and paged on the server.","description":"Lists the GitHub repositories the caller may work on, most\nrecently pushed first, searched and paged on the server.\n\nA person who connected their own GitHub sees what their token reaches in this\nApp's installations. An org admin who has not sees every repository in the\ninstallations their org holds. Anyone else gets an empty page with\nconnected:false, which is the console's cue to ask them to connect.","tags":["provider"],"parameters":[{"name":"q","in":"query","required":false,"description":"Q keeps repositories whose owner/name contains it, case-insensitively.","schema":{"type":"string"},"example":"cloud"},{"name":"owner","in":"query","required":false,"description":"Owner keeps one GitHub account's repositories — an org or a user login.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit is the page size: 1 to 100, and 50 when absent or unreadable.","schema":{"format":"int64","type":"integer"},"example":50},{"name":"after","in":"query","required":false,"description":"After is the `next` of the previous page. Absent starts at the most\nrecently pushed.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"connected":true,"next":"","repos":[{"default_branch":"main","full_name":"hanzoai/cloud","installation_id":62000701,"name":"cloud","owner":"hanzoai","private":false,"pushed_at":"2026-09-24T18:00:00Z"}],"total":1},"schema":{"$ref":"#/components/schemas/provider.githubReposOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/github/repos/import":{"post":{"operationId":"post_provider_github_repos_import","summary":"Imports the selected (or all) granted repos into git.hanzo.ai.","description":"Imports the selected (or all) granted repos into git.hanzo.ai. The\nselection is intersected with the installation's GRANTED set, so a client can\nnever import a repo the App was not granted (org isolation + a grant check). The\nimport runs in a bounded background worker (don't block the request), so the\nanswer is 202 Accepted; poll GET /v1/git/repos for each repository to appear\non git.hanzo.ai.","tags":["provider"],"requestBody":{"content":{"application/json":{"example":{"repos":["widgets"]},"schema":{"$ref":"#/components/schemas/provider.githubImportIn"}}},"required":true},"responses":{"202":{"content":{"application/json":{"example":{"queued":1,"repos":["widgets"]},"schema":{"$ref":"#/components/schemas/provider.githubImportOut"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/github/repos/{owner}/{repo}/branches":{"get":{"operationId":"get_provider_github_repos_by_owner_by_repo_branches","summary":"Lists a repository's branches, the default first, with prefix search.","description":"Lists a repository's branches, the default first, with prefix\nsearch. The repository must be one the caller may see — the same set\nGET /v1/provider/github/repos lists — or it is 404.","tags":["provider"],"parameters":[{"name":"owner","in":"path","required":true,"description":"Owner is the GitHub account that holds the repository.","schema":{"type":"string"},"example":"hanzoai"},{"name":"repo","in":"path","required":true,"description":"Repo is the repository's name within that account.","schema":{"type":"string"},"example":"cloud"},{"name":"q","in":"query","required":false,"description":"Q keeps branches whose name starts with it, matched by GitHub.","schema":{"type":"string"},"example":"feat/"},{"name":"limit","in":"query","required":false,"description":"Limit is the page size: 1 to 100, and 50 when absent or unreadable.","schema":{"format":"int64","type":"integer"}},{"name":"after","in":"query","required":false,"description":"After is the `next` of the previous page.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"branches":[{"commit":"9f2c1e7a","default":true,"name":"main"},{"commit":"4b8d0e3f","default":false,"name":"feat/login"}],"next":"","total":2},"schema":{"$ref":"#/components/schemas/provider.githubBranchesOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/github/repos/{repo}/pages":{"delete":{"operationId":"delete_provider_github_repos_by_repo_pages","summary":"Deletes the repo's Pages site.","description":"Deletes the repo's Pages site. 404 when there is none, so a\ncaller can tell \"turned it off\" from \"there was nothing on\".","tags":["provider"],"parameters":[{"name":"repo","in":"path","required":true,"description":"Repo is the repository's short name within the org's installation, with no\nowner prefix (the owner is server-derived from the grant). A trailing \".git\"\nis stripped.","schema":{"type":"string"},"example":"widgets"}],"responses":{"200":{"content":{"application/json":{"example":{"disabled":true,"repo":"widgets"},"schema":{"$ref":"#/components/schemas/provider.githubPagesDisabledOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true},"get":{"operationId":"get_provider_github_repos_by_repo_pages","summary":"Returns the repo's Pages status, live URL, custom domain and build source.","description":"Returns the repo's Pages status, live URL, custom domain and build\nsource. The repo is resolved against the org installation's GRANTED set, so a\ncaller can never address a repo the App was not granted; 404 when the repo has no\nPages site.","tags":["provider"],"parameters":[{"name":"repo","in":"path","required":true,"description":"Repo is the repository's short name within the org's installation, with no\nowner prefix (the owner is server-derived from the grant). A trailing \".git\"\nis stripped.","schema":{"type":"string"},"example":"widgets"}],"responses":{"200":{"content":{"application/json":{"example":{"buildType":"legacy","cname":"docs.acme.com","custom404":false,"httpsEnforced":true,"repo":"widgets","source":{"branch":"main","path":"/docs"},"status":"built","url":"https://acme.github.io/widgets/"},"schema":{"$ref":"#/components/schemas/provider.githubPagesView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true},"post":{"operationId":"post_provider_github_repos_by_repo_pages","summary":"Creates the repo's Pages site and answers 201 Created with it.","description":"Creates the repo's Pages site and answers 201 Created with it.\nWith buildType \"workflow\" the site builds via GitHub Actions; otherwise it builds\nfrom a branch source, defaulting to the repo's own default branch when none is\ngiven. Only \"/\" and \"/docs\" are legal source paths (GitHub's rule).","tags":["provider"],"parameters":[{"name":"repo","in":"path","required":true,"description":"Repo is the repository, from the :repo path segment.","schema":{"type":"string"},"example":"widgets"}],"requestBody":{"content":{"application/json":{"example":{"branch":"main","path":"/docs","repo":"widgets"},"schema":{"$ref":"#/components/schemas/provider.githubPagesEnableReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"buildType":"legacy","custom404":false,"httpsEnforced":true,"repo":"widgets","source":{"branch":"main","path":"/docs"},"status":"building","url":"https://acme.github.io/widgets/"},"schema":{"$ref":"#/components/schemas/provider.githubPagesView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true},"put":{"operationId":"put_provider_github_repos_by_repo_pages","summary":"Sets or clears the custom domain (cname) and updates HTTPS enforcement, build type, or source.","description":"Sets or clears the custom domain (cname) and updates HTTPS\nenforcement, build type, or source. ONLY the provided fields are sent to GitHub,\nso an update never resets a setting the caller did not mention.","tags":["provider"],"parameters":[{"name":"repo","in":"path","required":true,"description":"Repo is the repository, from the :repo path segment.","schema":{"type":"string"},"example":"widgets"}],"requestBody":{"content":{"application/json":{"example":{"cname":"docs.acme.com","httpsEnforced":true,"repo":"widgets"},"schema":{"$ref":"#/components/schemas/provider.githubPagesUpdateReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"repo":"widgets","updated":true},"schema":{"$ref":"#/components/schemas/provider.githubPagesUpdatedOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/github/repos/{repo}/pages/builds":{"post":{"operationId":"post_provider_github_repos_by_repo_pages_builds","summary":"Requests a Pages rebuild and returns the queued build's status.","description":"Requests a Pages rebuild and returns the queued build's status.\nThe build is queued AT GITHUB, not completed here, so the answer is 202 Accepted\nand its status is the one GitHub reported at queue time. 404 when the repository\nhas no Pages site, or when the org's installation was not granted it.","tags":["provider"],"parameters":[{"name":"repo","in":"path","required":true,"description":"Repo is the repository's short name within the org's installation, with no\nowner prefix (the owner is server-derived from the grant). A trailing \".git\"\nis stripped.","schema":{"type":"string"},"example":"widgets"}],"responses":{"202":{"content":{"application/json":{"example":{"repo":"widgets","status":"queued","url":"https://api.github.com/repos/acme/widgets/pages/builds/1"},"schema":{"$ref":"#/components/schemas/provider.githubPagesBuildOut"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/github/search":{"post":{"operationId":"post_provider_github_search","summary":"Finds repositories on GitHub.","description":"Finds repositories on GitHub.\n\nThis reads the PUBLIC index and returns nothing an installation unlocks: it is\nhow you find a repository to fork, not a way to see inside one. The org's own\ntoken is used only so the query is rate-limited against the installation\nrather than anonymously — the results are the same ones anyone would get.","tags":["provider"],"requestBody":{"content":{"application/json":{"example":{"limit":5,"q":"language:go raft"},"schema":{"$ref":"#/components/schemas/provider.githubSearchReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"count":1,"repos":[{"full_name":"hashicorp/raft","language":"Go","stars":8000}]},"schema":{"$ref":"#/components/schemas/provider.githubSearchOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/github/user":{"get":{"operationId":"get_provider_github_user","summary":"Reports whether the caller has connected their own GitHub account in the org they act in, and as whom.","description":"Reports whether the caller has connected their own GitHub\naccount in the org they act in, and as whom.","tags":["provider"],"responses":{"200":{"content":{"application/json":{"example":{"configured":true,"connected":true,"connectedAt":"2026-09-24T12:00:00Z","expiresAt":"2026-09-24T20:00:00Z","login":"octocat"},"schema":{"$ref":"#/components/schemas/provider.githubUserOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/github/user/callback":{"get":{"operationId":"get_provider_github_user_callback","summary":"Is where GitHub returns the person.","description":"Is where GitHub returns the person. It verifies the state,\nburns its nonce, and parks the code for the return page to complete; it\nexchanges nothing. PUBLIC and state-authed, like every OAuth return, and raw because it\nanswers a browser with a redirect.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/github/user/complete":{"post":{"operationId":"post_provider_github_user_complete","summary":"Finishes connecting the caller's GitHub account: it takes the authorization the callback parked, trades it for the person's token, and seals it.","description":"Finishes connecting the caller's GitHub account: it takes\nthe authorization the callback parked, trades it for the person's token, and\nseals it. Only the person who started the flow can complete it — another\nperson's grant id is simply not found — and a grant completes once.","tags":["provider"],"requestBody":{"content":{"application/json":{"example":{"grant":"9f2c1e7a4b8d0e3f6a5b2c1d0e9f8a7b"},"schema":{"$ref":"#/components/schemas/provider.githubUserCompleteIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"configured":true,"connected":true,"connectedAt":"2026-09-24T12:00:00Z","expiresAt":"2026-09-24T20:00:00Z","login":"octocat"},"schema":{"$ref":"#/components/schemas/provider.githubUserOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/github/user/connect":{"post":{"operationId":"post_provider_github_user_connect","summary":"Begins connecting the caller's own GitHub account: it answers the App's authorization page, carrying a state signed for this org and this person.","description":"Begins connecting the caller's own GitHub account: it answers\nthe App's authorization page, carrying a state signed for this org and this\nperson. Every member may connect their own; it grants nothing the person does\nnot already hold on GitHub.","tags":["provider"],"requestBody":{"content":{"application/json":{"example":{"return":"https://hanzo.ai/?at=-/settings/integrations"},"schema":{"$ref":"#/components/schemas/provider.githubUserConnectIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"authorizeUrl":"https://github.com/login/oauth/authorize?client_id=Iv23li3SYLoq40ExR6EN\u0026redirect_uri=...\u0026state=..."},"schema":{"$ref":"#/components/schemas/provider.githubUserConnectOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/github/user/disconnect":{"post":{"operationId":"post_provider_github_user_disconnect","summary":"Forgets the caller's GitHub connection in this org: the token is revoked at GitHub, and the sealed secrets and the row go.","description":"Forgets the caller's GitHub connection in this org: the\ntoken is revoked at GitHub, and the sealed secrets and the row go. It says\nwhether GitHub confirmed the revocation rather than reporting a success it did\nnot see. Disconnecting what is not connected succeeds.","tags":["provider"],"responses":{"200":{"content":{"application/json":{"example":{"disconnected":true,"revoked":true},"schema":{"$ref":"#/components/schemas/provider.githubUserDisconnectOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/github/webhook":{"post":{"operationId":"post_provider_github_webhook","summary":"GitHub App webhook","description":"The address the GitHub App delivers events to. A push is handed to the repository sync engine, and an issue or issue-comment event is mirrored into the native todo — idempotently, so the same issue re-syncs to one row however many times it is edited, closed or reopened. A repository event that puts a repo INTO the granted set (created, transferred, unarchived) raises one todo offering to import it; accepting means POSTing that repo to /v1/provider/github/import. It never imports on its own.\n\nIt answers a benign 200 for everything it does not act on — the ping, other event types, an unknown installation — deliberately, so GitHub does not enter a retry storm over events that were never going to do anything. Only a bad signature and a genuine sync failure are non-200, and an oversized payload is refused outright.\n\nTwo sync rules are worth stating because neither is guessable. EVERY ref syncs, tags as well as branches, because releases are cut by tag and filtering them would stop publishing with nothing reporting a failure. And a delete is NEVER propagated: the native side is canonical, so an inbound delete never removes a native ref.\n\nThe payload is verified by HMAC against the webhook secret before it is parsed.\n\nThe caller here is the PLATFORM, not a Hanzo tenant, so there is no bearer and no principal. The signature check IS the authentication, and it fails closed. The tenant is never read from the payload either: it is resolved from the verified platform identifier through the connection map, so an event from a workspace nobody connected does nothing. Refusals are written with their own status rather than being flattened to a 500, so a rejected signature reads as 401 and a malformed body as 400.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/gitlab/projects":{"get":{"operationId":"get_provider_gitlab_projects","summary":"Lists the projects the org's GitLab connection can reach — membership projects, most recently active first.","description":"Lists the projects the org's GitLab connection can reach —\nmembership projects, most recently active first.","tags":["provider"],"responses":{"200":{"content":{"application/json":{"example":{"account":"acme","projects":[{"cloneUrl":"https://gitlab.com/acme/widgets.git","defaultBranch":"main","fullName":"acme/widgets","htmlUrl":"https://gitlab.com/acme/widgets","name":"widgets","private":true,"pushedAt":"2026-07-01T10:00:00Z"}]},"schema":{"$ref":"#/components/schemas/provider.gitlabProjectsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/google/user":{"get":{"operationId":"get_provider_google_user","summary":"Reports whether the caller has connected their own Google account in the org they act in, and as whom.","description":"Reports whether the caller has connected their own Google\naccount in the org they act in, and as whom.","tags":["provider"],"responses":{"200":{"content":{"application/json":{"example":{"configured":true,"connected":true,"connectedAt":"2026-10-26T12:00:00Z","email":"ada@example.com","expiresAt":"2026-10-26T13:00:00Z","send":true},"schema":{"$ref":"#/components/schemas/provider.googleUserOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/google/user/callback":{"get":{"operationId":"get_provider_google_user_callback","summary":"Is where Google returns the person.","description":"Is where Google returns the person. It verifies the state,\nburns its nonce, and parks the code for the return page to complete; it\nexchanges nothing. PUBLIC and state-authed, like every OAuth return, and raw\nbecause it answers a browser with a redirect.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/google/user/complete":{"post":{"operationId":"post_provider_google_user_complete","summary":"Finishes connecting the caller's Google account: it takes the authorization the callback parked, trades it for the person's tokens, and seals them.","description":"Finishes connecting the caller's Google account: it takes\nthe authorization the callback parked, trades it for the person's tokens, and\nseals them. Only the person who started the flow can complete it — another\nperson's grant id is simply not found — and a grant completes once. A grant\nthat leaves out sending mail, or offline access, is refused and nothing is\nkept: a connection that cannot send is not one this surface offers.","tags":["provider"],"requestBody":{"content":{"application/json":{"example":{"grant":"9f2c1e7a4b8d0e3f6a5b2c1d0e9f8a7b"},"schema":{"$ref":"#/components/schemas/provider.googleUserCompleteIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"configured":true,"connected":true,"connectedAt":"2026-10-26T12:00:00Z","email":"ada@example.com","expiresAt":"2026-10-26T13:00:00Z","send":true},"schema":{"$ref":"#/components/schemas/provider.googleUserOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/google/user/connect":{"post":{"operationId":"post_provider_google_user_connect","summary":"Begins connecting the caller's own Google account: it answers Google's consent page, asking offline access to send mail as them, carrying a state signed for this org and this person.","description":"Begins connecting the caller's own Google account: it answers\nGoogle's consent page, asking offline access to send mail as them, carrying a\nstate signed for this org and this person. Every member may connect their own;\nit grants nothing the person does not already hold at Google.","tags":["provider"],"requestBody":{"content":{"application/json":{"example":{"return":"https://hanzo.ai/?at=-/settings/integrations"},"schema":{"$ref":"#/components/schemas/provider.googleUserConnectIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"authorizeUrl":"https://accounts.google.com/o/oauth2/v2/auth?client_id=...\u0026scope=openid+email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.send\u0026state=..."},"schema":{"$ref":"#/components/schemas/provider.googleUserConnectOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/google/user/disconnect":{"post":{"operationId":"post_provider_google_user_disconnect","summary":"Forgets the caller's Google connection in this org: the grant is revoked at Google, and the sealed secrets and the row go.","description":"Forgets the caller's Google connection in this org: the\ngrant is revoked at Google, and the sealed secrets and the row go. It says\nwhether Google confirmed the revocation rather than reporting a success it did\nnot see. Disconnecting what is not connected succeeds.","tags":["provider"],"responses":{"200":{"content":{"application/json":{"example":{"disconnected":true,"revoked":true},"schema":{"$ref":"#/components/schemas/provider.googleUserDisconnectOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/linear/claim":{"post":{"operationId":"post_provider_linear_claim","summary":"Binds the caller's Linear organization to the org and seals the webhook secret.","description":"Binds the caller's Linear organization to the org and seals the\nwebhook secret. The organization is READ from the caller's own key, never taken\nfrom the body: a person can only bind an organization they are a member of. An\norganization another org already holds is refused.","tags":["provider"],"requestBody":{"content":{"application/json":{"example":{"secret":"whsec_…"},"schema":{"$ref":"#/components/schemas/provider.linearClaimIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"name":"acme","organization":"6f0b…","path":"/v1/provider/linear/webhook"},"schema":{"$ref":"#/components/schemas/provider.linearClaimOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/linear/comments":{"post":{"operationId":"post_provider_linear_comments","summary":"Posts a comment on a Linear issue with the caller's own key, so it carries their name.","description":"Posts a comment on a Linear issue with the caller's own key, so it\ncarries their name. This is the op an agent is offered when it should answer in\nLinear rather than in chat.","tags":["provider"],"requestBody":{"content":{"application/json":{"example":{"body":"Reproduced on main; fix in #482.","issue":"ENG-123"},"schema":{"$ref":"#/components/schemas/provider.linearCommentIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"id":"c0f1…","url":"https://linear.app/acme/issue/ENG-123#comment-c0f1"},"schema":{"$ref":"#/components/schemas/provider.linearCommentOut"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/linear/issues/backfill":{"post":{"operationId":"post_provider_linear_issues_backfill","summary":"Seeds the native todo with the EXISTING Linear issues the caller's key can see (default state=open); the webhook keeps them live thereafter.","description":"Seeds the native todo with the EXISTING Linear issues the\ncaller's key can see (default state=open); the webhook keeps them live\nthereafter. Synchronous and bounded, idempotent by ExtRef.","tags":["provider"],"requestBody":{"content":{"application/json":{"example":{"state":"all"},"schema":{"$ref":"#/components/schemas/provider.linearBackfillIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"created":410,"failed":0,"issues":430,"updated":20},"schema":{"$ref":"#/components/schemas/provider.linearBackfillResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/linear/webhook":{"post":{"operationId":"post_provider_linear_webhook","summary":"Linear webhook","description":"The address Linear delivers Issue and Comment events to. An issue event is mirrored into the native todo — idempotently by identifier, so ENG-123 is one row however many times it is edited, moved or closed — and every issue and comment event is handed to the automations engine as a verified trigger, which is how an org runs an agent when an issue is assigned to it or a comment mentions it. A remove is never propagated: the native side is canonical.\n\nIt answers a benign 200 for what it does not act on — an unknown organization, other event types — so Linear does not retry-storm. A bad signature and a delivery older than a minute are 401; only a sink failure is 502.\n\nThe delivery names its Linear organization; that organization's own webhook secret — sealed at /v1/provider/linear/claim — verifies the HMAC over the raw body, so the tenant is the organization the signature proves, never a header.\n\nThe caller here is the PLATFORM, not a Hanzo tenant, so there is no bearer and no principal. The signature check IS the authentication, and it fails closed. The tenant is never read from the payload either: it is resolved from the verified platform identifier through the connection map, so an event from a workspace nobody connected does nothing. Refusals are written with their own status rather than being flattened to a 500, so a rejected signature reads as 401 and a malformed body as 400.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/openrouter/webhook":{"post":{"operationId":"post_provider_openrouter_webhook","summary":"Receive OpenRouter Broadcast traces as usage rows","description":"OpenRouter's spend is invisible to every Hanzo money lens because those lenses read hanzo.cloud_usage and OpenRouter meters keys of its own. Point a Broadcast destination (Settings ▸ Observability ▸ Webhook) at this endpoint and each generation span becomes ONE row in that same ledger with provider `openrouter`, so one query answers what we spend everywhere. Enable the Cost and Identity field categories: cost is the money and identity carries `openrouter.api_key_name`, which is what says WHICH key spent it — it lands in `account` as openrouter/\u003ckey name\u003e.\n\nAUTHENTICATION IS A HANZO KEY. Broadcast signs nothing; its only authentication is the destination's Headers map, so send a key as `Authorization: Bearer pk-…` and it is admitted exactly as /v1/event admits a beacon's: a project key resolves through the project that minted it, an IAM-issued key through IAM. That key names the org every row is filed under; it can write and cannot read. No key, or a key that names no org, is 401 and nothing is stored.\n\nThe body is OTLP/JSON — `{resourceSpans:[{scopeSpans:[{spans:[…]}]}]}` — exactly as OpenTelemetry defines it; the model, tokens and cost are read from each span's `gen_ai.*` attributes and the key name from `openrouter.api_key_name`. The answer is `{stored, dropped}`: how many generations became rows, and how many spans named no model. Those are OpenRouter's trace and span parents — they carry no cost to meter. An empty payload stores nothing and answers 200, which is what makes Test Connection pass. A warehouse that cannot take the rows answers 503 so the delivery shows red and can be replayed: a row is keyed by its span id, so a redelivery collapses rather than double-counting.","tags":["provider"],"requestBody":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}}},"responses":{"2XX":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"Success"}},"x-app":"provider","x-public":true}},"/v1/provider/slack/channels":{"get":{"operationId":"get_provider_slack_channels","summary":"Lists Slack conversations for the caller's connected workspace.","description":"Lists Slack conversations for the caller's connected workspace.\nRead next_cursor until empty to discover channels, including private channels\nor group DMs when types requests them and the bot has their read scopes.","tags":["provider"],"parameters":[{"name":"types","in":"query","required":false,"description":"Types selects public_channel, private_channel, im or mpim, comma-separated.\nDefaults to public_channel; each selected type requires its own read scope.","schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"description":"Cursor continues the previous page's next_cursor.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provider.slackChannelsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/slack/commands":{"post":{"operationId":"post_provider_slack_commands","summary":"Slack slash command webhook","description":"The address Slack posts a slash command to, form-encoded. It acknowledges inside Slack's three-second budget and posts the answer afterwards to the command's own response URL, which is why the immediate reply is empty.\n\nThe body is verified against the same app signing secret as the events webhook, and a repeat of the same command invocation is absorbed rather than answered twice.\n\nThe caller here is the PLATFORM, not a Hanzo tenant, so there is no bearer and no principal. The signature check IS the authentication, and it fails closed. The tenant is never read from the payload either: it is resolved from the verified platform identifier through the connection map, so an event from a workspace nobody connected does nothing. Refusals are written with their own status rather than being flattened to a 500, so a rejected signature reads as 401 and a malformed body as 400.\n\nThe answer is acknowledged immediately and the work happens afterwards, because every one of these platforms times out a slow webhook. Duplicate deliveries are absorbed durably, so a platform retry of an event that already ran never runs it a second time or bills for it twice. When the agent pool is full nothing at all is recorded and the delivery is refused as retriable, so the message is re-delivered later rather than being lost or half-processed.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/slack/events":{"post":{"operationId":"post_provider_slack_events","summary":"Slack Events API webhook","description":"The address a Slack app posts workspace events to. It answers Slack's url_verification handshake with the challenge, and routes an @mention or a direct message to an agent turn that replies in the same thread. The turn holds the product's own tools, so a request to change code starts a sandbox run because the model chose to — there is no prefix and no second path.\n\nThe raw body and its timestamp are verified against the app's signing secret before anything is read from them. Hanzo's own bot messages are dropped, so a reply cannot trigger another reply.\n\nThe caller here is the PLATFORM, not a Hanzo tenant, so there is no bearer and no principal. The signature check IS the authentication, and it fails closed. The tenant is never read from the payload either: it is resolved from the verified platform identifier through the connection map, so an event from a workspace nobody connected does nothing. Refusals are written with their own status rather than being flattened to a 500, so a rejected signature reads as 401 and a malformed body as 400.\n\nThe answer is acknowledged immediately and the work happens afterwards, because every one of these platforms times out a slow webhook. Duplicate deliveries are absorbed durably, so a platform retry of an event that already ran never runs it a second time or bills for it twice. When the agent pool is full nothing at all is recorded and the delivery is refused as retriable, so the message is re-delivered later rather than being lost or half-processed.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/slack/file":{"get":{"operationId":"get_provider_slack_file","summary":"Read one Slack file's bytes.","description":"Streams the bytes of a file attached to a message in the workspace this organization connected. `id` is the Slack file id a message's `files` carries; the response is the file itself, under the Content-Type Slack recorded for it, never JSON.\n\nTHE WORKSPACE IS THE CALLER'S. The org comes from the validated identity and never from the request, and it selects the token the read spends, so a caller cannot name a workspace they have not connected. A file that workspace cannot see answers 404 from Slack's own answer rather than from a guess made here, and a file past the size bound is refused by name instead of arriving truncated.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/slack/install":{"get":{"operationId":"get_provider_slack_install","summary":"Install the Hanzo app into a Slack workspace","description":"The address behind Slack's \"Add to Slack\" and Marketplace Install buttons. It answers a 302 to Slack's own consent screen and does nothing else — it is a redirector by design.\n\nIt exists because Slack refuses a slack.com URL in that field and requires one of ours that redirects there, which makes the field an ATTRIBUTION hook: routing the click through our own address is what lets an install be counted, and always answering the redirect is what keeps the counter from becoming a detour that never reaches consent. The destination is the same consent URL every time, built from the same scopes the console's Connect button asks for, so a workspace is asked to grant one thing however the install began.\n\nIt is PUBLIC and carries no principal, because whoever clicks Install in Slack's directory has no Hanzo session yet. It binds no org either, and that is deliberate rather than missing: the org is resolved at the shared provider callback, from the signed state a console connect minted or from the workspace's existing connection. Minting an org for an anonymous click is the one thing that would break tenant isolation, so an install begun here finishes under exactly the rules every other install obeys.\n\nWhere the app is not configured it answers 503, rather than a consent URL carrying an empty client_id that Slack would render as its own dead-end error page.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/slack/join":{"post":{"operationId":"post_provider_slack_join","summary":"Joins every public channel in the caller org's workspace.","description":"Joins every public channel in the caller org's workspace.\n\nOrg admin, because it changes what the whole workspace sees: after it the agent\nis a member of every public room and answers in all of them.","tags":["provider"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provider.slackJoinOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/slack/link":{"get":{"operationId":"get_provider_slack_link","summary":"Begin linking a Hanzo account from Slack","description":"The entry point behind the connect prompt Hanzo posts in Slack. It starts a link session in the browser and redirects to Slack's own sign-in, which is what proves which Slack user is asking.\n\nThis is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/slack/link/callback":{"get":{"operationId":"get_provider_slack_link_callback","summary":"Complete the Slack account link","description":"The final leg: the user has proved both who they are in Slack and who they are in Hanzo, and this binds the two. It answers a short confirmation page telling them to return to Slack.\n\nThe Hanzo credential obtained here is sealed into the connected workspace's own KMS namespace; it is never written to a database column and never logged. A deployment whose secret store is unavailable refuses the link rather than completing it without custody of the credential.\n\nThis is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/slack/link/slack":{"get":{"operationId":"get_provider_slack_link_slack","summary":"Slack sign-in return leg","description":"Where Slack returns the user after they sign in. It establishes the verified Slack workspace and user, confirms that workspace is connected to an org, and hands the browser on to the Hanzo sign-in that completes the link.\n\nThe verified pair is carried onward in a host-bound cookie rather than in the URL, so the identity being linked cannot be edited in transit.\n\nThis is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/slack/messages":{"delete":{"operationId":"delete_provider_slack_messages","summary":"Takes back one of this app's messages: DELETE /v1/provider/slack/messages.","description":"Takes back one of this app's messages:\nDELETE /v1/provider/slack/messages.","tags":["provider"],"parameters":[{"name":"channel","in":"query","required":false,"schema":{"type":"string"}},{"name":"ts","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provider.slackDeleteMessageOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true},"get":{"operationId":"get_provider_slack_messages","summary":"Reads recent messages from a named Slack channel such as #hanzo-gtm.","description":"Reads recent messages from a named Slack channel such as\n#hanzo-gtm. The bot must be a member and have the relevant history scope.\nSet thread_ts to fetch a parent's replies, and cursor to continue a page.\nChannel history is newest first; thread replies are oldest first.","tags":["provider"],"parameters":[{"name":"channel","in":"query","required":false,"description":"Channel is a Slack channel ID, name (#hanzo-gtm), or Slack channel mention.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit bounds the page to 1-100 messages; zero defaults to 15.","schema":{"format":"int64","type":"integer"}},{"name":"cursor","in":"query","required":false,"description":"Cursor continues the previous page's next_cursor.","schema":{"type":"string"}},{"name":"thread_ts","in":"query","required":false,"description":"ThreadTS reads a thread via conversations.replies. Empty reads recent\nchannel messages via conversations.history, which excludes thread replies.","schema":{"type":"string"}},{"name":"oldest","in":"query","required":false,"description":"Oldest filters to messages after this Slack timestamp (exclusive).","schema":{"type":"string"}},{"name":"latest","in":"query","required":false,"description":"Latest filters to messages before this Slack timestamp (exclusive).","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provider.slackMessagesOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true},"post":{"operationId":"post_provider_slack_messages","summary":"Posts as Hanzo to the caller's connected Slack workspace.","description":"Posts as Hanzo to the caller's connected Slack workspace.\nUse channel from a message read and thread_ts to reply to a specific message.\nRequires chat:write; this operation does not join channels automatically.","tags":["provider"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provider.slackSendMessageIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provider.slackSendMessageOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true},"put":{"operationId":"put_provider_slack_messages","summary":"Rewrites one of this app's messages: PUT /v1/provider/slack/messages.","description":"Rewrites one of this app's messages:\nPUT /v1/provider/slack/messages. Slack refuses a message the token did not\npost, and that refusal is reported as it arrives.","tags":["provider"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provider.slackUpdateMessageIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provider.slackUpdateMessageOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/slack/reactions":{"post":{"operationId":"post_provider_slack_reactions","summary":"Adds an emoji reaction: POST /v1/provider/slack/reactions.","description":"Adds an emoji reaction: POST /v1/provider/slack/reactions.","tags":["provider"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provider.slackReactIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provider.slackReactOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/slack/search":{"post":{"operationId":"post_provider_slack_search","summary":"Answers a workspace question: POST /v1/provider/slack/search.","description":"Answers a workspace question: POST /v1/provider/slack/search.\n\nSlack's search.messages wants a USER token for a person's own view of a\nworkspace; a bot token searches what the app can see. Whichever the install\ngranted, the token custodied for this org is the one sent.","tags":["provider"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provider.slackSearchIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provider.slackSearchOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/teams/events":{"post":{"operationId":"post_provider_teams_events","summary":"Microsoft Teams Bot Framework webhook","description":"The messaging endpoint for the Teams bot. A message activity is routed to an agent turn and answered proactively through the Bot Connection; anything that is not a message with text is acknowledged and ignored.\n\nAuthentication is the Bot Framework's RS256 JWT, verified against its published keys and bound BOTH to this deployment's app id and to the activity's own service URL. The service-URL binding is the part that matters: without it a token valid for one activity could point the outbound reply somewhere else.\n\nThe caller here is the PLATFORM, not a Hanzo tenant, so there is no bearer and no principal. The signature check IS the authentication, and it fails closed. The tenant is never read from the payload either: it is resolved from the verified platform identifier through the connection map, so an event from a workspace nobody connected does nothing. Refusals are written with their own status rather than being flattened to a 500, so a rejected signature reads as 401 and a malformed body as 400.\n\nThe answer is acknowledged immediately and the work happens afterwards, because every one of these platforms times out a slow webhook. Duplicate deliveries are absorbed durably, so a platform retry of an event that already ran never runs it a second time or bills for it twice. When the agent pool is full nothing at all is recorded and the delivery is refused as retriable, so the message is re-delivered later rather than being lost or half-processed.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/teams/link":{"get":{"operationId":"get_provider_teams_link","summary":"Begin linking a Hanzo account from Teams","description":"The entry point behind the connect prompt Hanzo shows in Teams. It starts a link session and redirects to Microsoft sign-in addressed to the CHAT'S OWN tenant, not the common endpoint, so only a member of that tenant can complete it.\n\nThis is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/teams/link/aad":{"get":{"operationId":"get_provider_teams_link_aad","summary":"Microsoft sign-in return leg","description":"Where Microsoft returns the user after sign-in. It resolves the verified directory identity and then re-checks the tenant: the signed-in user's tenant must equal the tenant of the chat the link started from, so a valid Microsoft sign-in from a different organization is refused here rather than accepted.\n\nThis is the leg Teams has and the other platforms do not, which is why the Teams flow has an extra address.\n\nThis is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/teams/link/callback":{"get":{"operationId":"get_provider_teams_link_callback","summary":"Complete the Teams account link","description":"The final leg: it binds the verified directory identity to the Hanzo account that just signed in, and answers a short confirmation page telling them to return to Teams. The Hanzo credential is sealed into the connected org's KMS namespace.\n\nThis is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/telegram/connect":{"post":{"operationId":"post_provider_telegram_connect","summary":"Mints a short, single-use deep-link code bound to the caller's org and returns the t.me link the console navigates to.","description":"Mints a short, single-use deep-link code bound to the caller's\norg and returns the t.me link the console navigates to. Org-authed: a caller with\nno validated principal is 403 (same gate as the framework connect). The code is\nstored as an oauth_nonce (org,telegram); the webhook's /start handler claims it to\nbind chat→org. It is short (128-bit hex) so it fits Telegram's 64-char `start`\npayload limit.","tags":["provider"],"responses":{"200":{"content":{"application/json":{"example":{"authorizeUrl":"https://t.me/hanzo_bot?start=9f3c1d2e4b5a6c7d8e9f0a1b2c3d4e5f"},"schema":{"$ref":"#/components/schemas/provider.authorizeOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/telegram/link":{"get":{"operationId":"get_provider_telegram_link","summary":"Begin linking a Hanzo account from Telegram","description":"The entry point behind the connect prompt Hanzo sends in Telegram. Unlike the other platforms it answers an HTML PAGE rather than a redirect: Telegram has no OAuth flow, so the page hosts Telegram's Login Widget, and the browser is sent onward only after the user signs in through it.\n\nThe widget only appears on the domain registered for the bot, so a deployment whose bot domain is unset renders a page with nothing on it.\n\nThis is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/telegram/link/auth":{"get":{"operationId":"get_provider_telegram_link_auth","summary":"Telegram Login Widget return leg","description":"Where Telegram's Login Widget sends the user with its signed authentication data. That data is verified against the bot token — this is the identity source, and it is the widget's signature rather than a code exchange — and the chat is confirmed to be bound to an org before the browser is handed to the Hanzo sign-in.\n\nWidget data is only accepted while it is fresh, so a captured sign-in blob cannot be replayed later even though its signature stays valid.\n\nThis is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/telegram/link/callback":{"get":{"operationId":"get_provider_telegram_link_callback","summary":"Complete the Telegram account link","description":"The final leg: it binds the verified Telegram user to the Hanzo account that just signed in, and answers a short confirmation page telling them to return to Telegram. The Hanzo credential is sealed into the connected org's KMS namespace.\n\nThis is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/telegram/webhook":{"post":{"operationId":"post_provider_telegram_webhook","summary":"Telegram Bot API webhook","description":"The update webhook for the Telegram bot. It does two jobs: `/start \u003ccode\u003e` or `/connect \u003ccode\u003e` binds the chat it was sent from to an org, idempotently; anything else is treated as a possible agent trigger.\n\nWhat counts as a trigger differs by chat type, and it is easy to get wrong: in a private chat every message is a trigger, while in a group the message must mention the bot or use the `/hanzo` command. Non-triggers and non-message updates are acknowledged and dropped.\n\nAuthentication is the secret token Telegram echoes on every update, compared in constant time. A message in a chat that has never been bound is dropped, which is why the bind command exists.\n\nThe caller here is the PLATFORM, not a Hanzo tenant, so there is no bearer and no principal. The signature check IS the authentication, and it fails closed. The tenant is never read from the payload either: it is resolved from the verified platform identifier through the connection map, so an event from a workspace nobody connected does nothing. Refusals are written with their own status rather than being flattened to a 500, so a rejected signature reads as 401 and a malformed body as 400.\n\nThe answer is acknowledged immediately and the work happens afterwards, because every one of these platforms times out a slow webhook. Duplicate deliveries are absorbed durably, so a platform retry of an event that already ran never runs it a second time or bills for it twice. When the agent pool is full nothing at all is recorded and the delivery is refused as retriable, so the message is re-delivered later rather than being lost or half-processed.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/twitter/callback":{"get":{"operationId":"get_provider_twitter_callback","summary":"Completes an X consent that arrived on the twitter spelling of the callback.","description":"Completes an X consent that arrived on the twitter spelling of the callback.\nThe consent URL this process sends is /v1/provider/x/callback. The X app is\nalso registered at this address, so a browser sent there still finishes the\nsame flow. State is signed for provider x, and the answer is a redirect.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/whatsapp/webhook":{"get":{"operationId":"get_provider_whatsapp_webhook","summary":"WhatsApp Cloud API subscription challenge","description":"Meta calls this once when the webhook is subscribed, carrying the verify token this deployment was configured with and a challenge to echo. The token is compared in constant time before the echo — answering the challenge without checking it would let anyone point their own app at this address and have it confirm the subscription.","tags":["provider"],"x-app":"provider","x-public":true},"post":{"operationId":"post_provider_whatsapp_webhook","summary":"WhatsApp Cloud API webhook","description":"One delivery from Meta. Authenticity is the X-Hub-Signature-256 HMAC over the raw body, and it is the whole of it: a message accepted here creates the reply route that authorises this org to answer, so an unsigned delivery would let anyone hand an org a conversation to answer under its own number.\n\nMeta batches (entry × changes × messages) and sends status callbacks — sent/delivered/read — through this same address with no message at all. Those are acknowledged and dropped rather than refused, because a non-2xx is retried with backoff and eventually disables the subscription: the only refusals here are an unconfigured endpoint and a bad signature, which are ours to fix and not Meta's to retry.\n\nThe answer is acknowledged immediately and the work happens afterwards, because every one of these platforms times out a slow webhook. Duplicate deliveries are absorbed durably, so a platform retry of an event that already ran never runs it a second time or bills for it twice. When the agent pool is full nothing at all is recorded and the delivery is refused as retriable, so the message is re-delivered later rather than being lost or half-processed.","tags":["provider"],"x-app":"provider","x-public":true}},"/v1/provider/{provider}":{"get":{"operationId":"get_provider_by_provider","summary":"Returns ONE provider with this org's connection status — the same view list carries, for a single id.","description":"Returns ONE provider with this org's connection status — the same view list\ncarries, for a single id. An unknown id is 404, and so is a user-plane provider:\nthe org surface never resolves one.","tags":["provider"],"parameters":[{"name":"provider","in":"path","required":true,"description":"Provider is the registry id of the connector — \"slack\", \"github\",\n\"cloudflare\". Unknown ids are 404, as are the user-plane (/v1/connection)\nproviders, which this surface never resolves.","schema":{"type":"string"},"example":"slack"}],"responses":{"200":{"content":{"application/json":{"example":{"available":true,"category":"Communication","connected":false,"description":"Connect your workspace.","id":"slack","name":"Slack"},"schema":{"$ref":"#/components/schemas/provider.providerView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/{provider}/callback":{"get":{"operationId":"get_provider_by_provider_callback","summary":"OAuth return for any connector","description":"The single address every connector's OAuth flow returns to. It exchanges the authorization the provider granted, records the connection, and ALWAYS redirects the browser back to the console — on success and on every labeled failure alike, so a user never lands on a raw JSON dead end.\n\nIt is public and carries no principal, so the org is taken ONLY from the signed state minted when the flow began; no header is trusted here. That state is single-use and is burned BEFORE the exchange, so one authorization is one attempt and a replayed return fails instead of exchanging twice.\n\nTokens are sealed into the org's KMS namespace BEFORE the connection row is written, so a failure of the secret store leaves no half-connected integration advertising a credential that was never stored. Token values never appear in the redirect, in a log line or in an error.\n\nOne generalization is worth knowing: a GitHub App installation returns an installation identifier instead of an OAuth code, and it is accepted in the code's place so the App model needs no second address.","tags":["provider"],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"provider","x-public":true}},"/v1/provider/{provider}/connect":{"post":{"operationId":"post_provider_by_provider_connect","summary":"Acquires the org's credential for one provider.","description":"Acquires the org's credential for one provider. It has TWO paths and the\nREQUEST picks which: a \"token\" key in the body seals that credential directly\n(verify-before-store), and its absence begins the 3-legged OAuth flow — minting a\nsingle-use nonce plus an HMAC-signed state that binds this org to this provider,\nand answering with the provider's authorize URL for the caller to redirect to.\n\nFail-closed order, unchanged: no principal → 403; unknown provider → 404; an\nAdminOnly connector without the caller's own-org admin bit → 403; not configured\n→ 503; KMS not ready → 503 (the flow WILL need to seal a token, so refuse now\nrather than dead-end at the callback).","tags":["provider"],"parameters":[{"name":"provider","in":"path","required":true,"description":"Provider is the connector's registry id, from the :provider path segment.","schema":{"type":"string"},"example":"cloudflare"}],"requestBody":{"content":{"application/json":{"example":{"accountId":"a1b2c3","provider":"cloudflare","token":"cf-scoped-api-token"},"schema":{"$ref":"#/components/schemas/provider.connectIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"account":"Acme","connected":true,"externalId":"a1b2c3","provider":"cloudflare","scopes":[]},"schema":{"$ref":"#/components/schemas/provider.connectOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/{provider}/disconnect":{"post":{"operationId":"post_provider_by_provider_disconnect","summary":"Revokes (best-effort) and forgets an org's connection: it deletes every custodied KMS secret and the connection row.","description":"Revokes (best-effort) and forgets an org's connection: it deletes\nevery custodied KMS secret and the connection row. Idempotent — disconnecting a\nprovider that was never connected still returns {disconnected:true}. Symmetric\nwith connect: an AdminOnly connector needs the caller's own-org admin bit.\n\nAn `account` disconnects that one account and leaves the org's others; without\nit every account goes. A provider with an App installation (GitHub) also removes\nthe installation at the provider for each account no other org still holds, so\nconnecting that account again is a fresh install rather than GitHub's Configure\npage, which returns nothing the connect can bind.","tags":["provider"],"parameters":[{"name":"provider","in":"path","required":true,"description":"Provider is the connector's registry id, from the :provider path segment.","schema":{"type":"string"},"example":"github"}],"requestBody":{"content":{"application/json":{"example":{"account":"acme","provider":"github"},"schema":{"$ref":"#/components/schemas/provider.disconnectIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"accounts":["acme"],"disconnected":true,"uninstalled":["acme"]},"schema":{"$ref":"#/components/schemas/provider.disconnectOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/{provider}/logo":{"get":{"operationId":"get_provider_by_provider_logo","summary":"Serves a connector's logo from the catalog.","description":"Serves a connector's logo from the catalog. PUBLIC: an \u003cimg\u003e carries no\nbearer, and a logo is not the org's. It is served from the embedded catalog\nonly, never fetched, with a policy that runs nothing — an SVG opened directly\nis a picture, not a page.","tags":["provider"],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"provider","x-public":true}},"/v1/provider/{provider}/run":{"post":{"operationId":"post_provider_by_provider_run","summary":"Runs one action of a connector as the caller's org, with the credential the org connected, and answers what the action returned.","description":"Runs one action of a connector as the caller's org, with the credential\nthe org connected, and answers what the action returned. The credential is\nread from the org's KMS namespace here and never leaves this service. An\naction that ran and failed is ok:false with the reason; an unknown connector\nis 404, an action that does not run on this deployment 422, and a connector\nthe org has not connected 424.","tags":["provider"],"parameters":[{"name":"provider","in":"path","required":true,"description":"Provider is the connector, from the path.","schema":{"type":"string"},"example":"bitly"}],"requestBody":{"content":{"application/json":{"example":{"action":"create_bitlink","input":{"long_url":"https://hanzo.ai"},"provider":"bitly"},"schema":{"$ref":"#/components/schemas/provider.runIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"example":{"ok":true,"output":{"link":"https://bit.ly/3xyz"}},"schema":{"$ref":"#/components/schemas/provider.runOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provider/{provider}/verify":{"post":{"operationId":"post_provider_by_provider_verify","summary":"Re-checks a CONNECTED apikey connector's stored credential against the provider, live (`hanzo connector verify`).","description":"Re-checks a CONNECTED apikey connector's stored credential against the\nprovider, live (`hanzo connector verify`). Org-scoped (any member may check\nstatus); the credential is read from KMS, verified, and NEVER returned or logged.\nA verification failure is reported as {active:false}, not an error — the console/\nCLI renders it. Only apikey providers support verify (OAuth tokens are checked at\nuse, not re-verified here).","tags":["provider"],"parameters":[{"name":"provider","in":"path","required":true,"description":"Provider is the registry id of the connector — \"slack\", \"github\",\n\"cloudflare\". Unknown ids are 404, as are the user-plane (/v1/connection)\nproviders, which this surface never resolves.","schema":{"type":"string"},"example":"cloudflare"}],"responses":{"200":{"content":{"application/json":{"example":{"account":"Acme","active":true,"externalId":"a1b2c3","provider":"cloudflare","scopes":["zone:read"]},"schema":{"$ref":"#/components/schemas/provider.verifyOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provider","x-public":true,"x-tool":true}},"/v1/provisioning/datastore":{"get":{"operationId":"get_provisioning_datastore","summary":"Lists the caller org's Hanzo Datastore warehouses.","description":"Lists the caller org's Hanzo Datastore warehouses. Each one is\na DEDICATED analytical instance the org alone runs, so the host is that\ninstance's own in-cluster Service and the port is its HTTP port, 8123.","tags":["provisioning"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/provisioning.provisionedSummary"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true},"post":{"operationId":"post_provisioning_datastore","summary":"Launches your org's OWN Hanzo Datastore instance and answers with its `datastore://` connection string.","description":"Launches your org's OWN Hanzo Datastore instance and answers\nwith its `datastore://` connection string.\n\nThe instance is yours alone — a deployment in your own tenant namespace, so its\nadmin credential is naturally scoped to you and no other tenant shares the\nprocess. Off-cluster this fails closed with 503 rather than handing back a\nshared one.","tags":["provisioning"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionResult"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true}},"/v1/provisioning/datastore/{name}":{"delete":{"operationId":"delete_provisioning_datastore_by_name","summary":"Deprovisions one Hanzo Datastore warehouse.","description":"Deprovisions one Hanzo Datastore warehouse. It reverts any app\ninstance bound to it back to Base BEFORE tearing down the org's dedicated\ninstance, then deletes the sealed credential and removes the metadata row.\nAnswers 204 with no body; a second call is a 404.","tags":["provisioning"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create.","schema":{"type":"string"},"example":"warehouse"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true},"get":{"operationId":"get_provisioning_datastore_by_name","summary":"Returns one Hanzo Datastore warehouse's metadata.","description":"Returns one Hanzo Datastore warehouse's metadata. It carries the\nwarehouse's status, its instance address and the admin user the instance\nbooted with — never the password. A still-booting instance reads\n\"provisioning\", reconciled from the operator's live view rather than the row.","tags":["provisioning"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create.","schema":{"type":"string"},"example":"warehouse"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionedResource"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true}},"/v1/provisioning/docdb":{"get":{"operationId":"get_provisioning_docdb","summary":"Lists the caller org's Hanzo DocDB document databases.","description":"Lists the caller org's Hanzo DocDB document databases. Each one is\na DEDICATED FerretDB instance the org alone runs, speaking the MongoDB wire\nprotocol, so the host is that instance's own in-cluster Service and the port\nis 27017.","tags":["provisioning"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/provisioning.provisionedSummary"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true},"post":{"operationId":"post_provisioning_docdb","summary":"Launches your org's OWN document-database instance and answers with its `mongodb://` connection string.","description":"Launches your org's OWN document-database instance and answers with\nits `mongodb://` connection string. It speaks the MongoDB wire protocol, so\nexisting MongoDB drivers connect unchanged.\n\nThe instance is yours alone — a deployment in your own tenant namespace, so its\nadmin credential is naturally scoped to you and no other tenant shares the\nprocess. Off-cluster this fails closed with 503 rather than handing back a\nshared one.","tags":["provisioning"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionResult"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true}},"/v1/provisioning/docdb/{name}":{"delete":{"operationId":"delete_provisioning_docdb_by_name","summary":"Deprovisions one Hanzo DocDB database.","description":"Deprovisions one Hanzo DocDB database. It reverts any app instance\nbound to it back to Base BEFORE tearing down the org's dedicated FerretDB\ninstance, then deletes the sealed credential and removes the metadata row.\nAnswers 204 with no body; a second call is a 404.","tags":["provisioning"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create.","schema":{"type":"string"},"example":"sessions"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true},"get":{"operationId":"get_provisioning_docdb_by_name","summary":"Returns one Hanzo DocDB database's metadata.","description":"Returns one Hanzo DocDB database's metadata. It carries the\ndatabase's status, its instance address and the SCRAM user the instance was\nset up with — never the password. A still-booting instance reads\n\"provisioning\", reconciled from the operator's live view.","tags":["provisioning"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create.","schema":{"type":"string"},"example":"sessions"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionedResource"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true}},"/v1/provisioning/kv":{"get":{"operationId":"get_provisioning_kv","summary":"Lists the caller org's Hanzo KV stores.","description":"Lists the caller org's Hanzo KV stores. Each one is a DEDICATED Valkey\ninstance the org alone runs, so the host is that instance's own in-cluster\nService and the port is 6379.","tags":["provisioning"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/provisioning.provisionedSummary"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true},"post":{"operationId":"post_provisioning_kv","summary":"Launches your org's OWN key-value instance and answers with its `kv://` connection string.","description":"Launches your org's OWN key-value instance and answers with its `kv://`\nconnection string.\n\nThe instance is yours alone — a deployment in your own tenant namespace, so its\nadmin credential is naturally scoped to you and no other tenant shares the\nprocess. Off-cluster this fails closed with 503 rather than handing back a\nshared one.","tags":["provisioning"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionResult"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true}},"/v1/provisioning/kv/{name}":{"delete":{"operationId":"delete_provisioning_kv_by_name","summary":"Deprovisions one Hanzo KV store.","description":"Deprovisions one Hanzo KV store. It reverts any app instance bound to\nit back to Base BEFORE tearing down the org's dedicated Valkey instance, then\ndeletes the sealed credential and removes the metadata row. Answers 204 with\nno body; a second call is a 404.","tags":["provisioning"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create.","schema":{"type":"string"},"example":"sessions"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true},"get":{"operationId":"get_provisioning_kv_by_name","summary":"Returns one Hanzo KV store's metadata.","description":"Returns one Hanzo KV store's metadata. It carries the store's status,\nits instance address and the Valkey user it authenticates as (\"default\", the\nonly user a requirepass instance has) — never the password. A still-booting\ninstance reads \"provisioning\", reconciled from the operator's live view.","tags":["provisioning"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create.","schema":{"type":"string"},"example":"sessions"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionedResource"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true}},"/v1/provisioning/s3":{"get":{"operationId":"get_provisioning_s3","summary":"Lists the caller org's object-storage buckets.","description":"Lists the caller org's object-storage buckets. A bucket lives in an\nalready-live shared object store and is reached through the public gateway.\nThe names here are the friendly ones the org provisioned; the physical bucket\nis org-namespaced underneath, which is what keeps two tenants' buckets\ndistinct.","tags":["provisioning"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/provisioning.provisionedSummary"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true},"post":{"operationId":"post_provisioning_s3","summary":"Creates an S3-compatible bucket inside the already-running shared object store and answers with the endpoint that reaches it.","description":"Creates an S3-compatible bucket inside the already-running shared\nobject store and answers with the endpoint that reaches it.","tags":["provisioning"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionResult"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true}},"/v1/provisioning/s3/{name}":{"delete":{"operationId":"delete_provisioning_s3_by_name","summary":"Deletes one bucket from the shared object store and removes its metadata row.","description":"Deletes one bucket from the shared object store and removes its\nmetadata row. Answers 204 with no body; a second call is a 404.","tags":["provisioning"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create.","schema":{"type":"string"},"example":"uploads"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true},"get":{"operationId":"get_provisioning_s3_by_name","summary":"Returns one bucket's metadata.","description":"Returns one bucket's metadata. It carries the bucket's status and the\ngateway address it is reached at, and no username: the object store\nauthenticates with a shared, out-of-band key rather than a per-bucket\ncredential.","tags":["provisioning"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create.","schema":{"type":"string"},"example":"uploads"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionedResource"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true}},"/v1/provisioning/search":{"get":{"operationId":"get_provisioning_search","summary":"Lists the caller org's search indexes.","description":"Lists the caller org's search indexes. An index is a logical\nresource inside an already-live shared backend, so every one of them is\nreached through the public gateway rather than at an instance of its own.","tags":["provisioning"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/provisioning.provisionedSummary"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true},"post":{"operationId":"post_provisioning_search","summary":"Creates a search index inside the already-running shared search backend and answers with the endpoint that reaches it.","description":"Creates a search index inside the already-running shared search\nbackend and answers with the endpoint that reaches it.","tags":["provisioning"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionResult"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true}},"/v1/provisioning/search/{name}":{"delete":{"operationId":"delete_provisioning_search_by_name","summary":"Deletes one search index from the shared backend and removes its metadata row.","description":"Deletes one search index from the shared backend and removes its\nmetadata row. Answers 204 with no body; a second call is a 404.","tags":["provisioning"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create.","schema":{"type":"string"},"example":"products"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true},"get":{"operationId":"get_provisioning_search_by_name","summary":"Returns one search index's metadata.","description":"Returns one search index's metadata. It carries the index's status\nand the gateway address it is reached at, and no username: the backend\nauthenticates with a shared, out-of-band key rather than a per-index\ncredential.","tags":["provisioning"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create.","schema":{"type":"string"},"example":"products"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionedResource"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true}},"/v1/provisioning/sql":{"get":{"operationId":"get_provisioning_sql","summary":"Lists the caller org's Hanzo SQL databases.","description":"Lists the caller org's Hanzo SQL databases. Each one is a DEDICATED\nPostgreSQL instance the org alone runs, so the host is that instance's own\nin-cluster Service and the port is 5432.","tags":["provisioning"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/provisioning.provisionedSummary"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true},"post":{"operationId":"post_provisioning_sql","summary":"Launches your org's OWN PostgreSQL instance and answers with its `postgres://` connection string.","description":"Launches your org's OWN PostgreSQL instance and answers with its\n`postgres://` connection string.\n\nThe instance is yours alone — a deployment in your own tenant namespace, so its\nadmin credential is naturally scoped to you and no other tenant shares the\nprocess. Off-cluster, where there is no orchestrator to launch one, this fails\nclosed with 503 rather than handing back a shared one.","tags":["provisioning"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionResult"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true}},"/v1/provisioning/sql/{name}":{"delete":{"operationId":"delete_provisioning_sql_by_name","summary":"Deprovisions one Hanzo SQL database.","description":"Deprovisions one Hanzo SQL database. It reverts any app instance\nbound to it back to Base BEFORE tearing down the org's dedicated Postgres\ninstance — never a live app pointed at a deleted backend — then deletes the\nsealed credential and removes the metadata row. Answers 204 with no body; a\nsecond call is a 404, not a second delete.","tags":["provisioning"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create.","schema":{"type":"string"},"example":"orders"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true},"get":{"operationId":"get_provisioning_sql_by_name","summary":"Returns one Hanzo SQL database's metadata.","description":"Returns one Hanzo SQL database's metadata. It carries the database's\nstatus, its instance address and the admin user Postgres booted with — never\nthe password, which is returned once at create and otherwise lives only in\nHanzo KMS. A still-booting instance reads \"provisioning\", reconciled from the\noperator's live view rather than from the row.","tags":["provisioning"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create.","schema":{"type":"string"},"example":"orders"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionedResource"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true}},"/v1/provisioning/vector":{"get":{"operationId":"get_provisioning_vector","summary":"Lists the caller org's vector collections.","description":"Lists the caller org's vector collections. A collection is a\nlogical resource inside an already-live shared backend, so every one of them\nis reached through the public gateway rather than at an instance of its own.","tags":["provisioning"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/provisioning.provisionedSummary"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true},"post":{"operationId":"post_provisioning_vector","summary":"Creates a vector collection inside the already-running shared vector backend and answers with the endpoint that reaches it.","description":"Creates a vector collection inside the already-running shared\nvector backend and answers with the endpoint that reaches it.","tags":["provisioning"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionResult"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true}},"/v1/provisioning/vector/{name}":{"delete":{"operationId":"delete_provisioning_vector_by_name","summary":"Deletes one vector collection from the shared backend and removes its metadata row.","description":"Deletes one vector collection from the shared backend and removes\nits metadata row. Answers 204 with no body; a second call is a 404.","tags":["provisioning"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create.","schema":{"type":"string"},"example":"embeddings"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true},"get":{"operationId":"get_provisioning_vector_by_name","summary":"Returns one vector collection's metadata.","description":"Returns one vector collection's metadata. It carries the\ncollection's status and the gateway address it is reached at, and no username:\nthe backend authenticates with a shared, out-of-band key rather than a\nper-collection credential, so there is no per-resource user to report.","tags":["provisioning"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create.","schema":{"type":"string"},"example":"embeddings"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/provisioning.provisionedResource"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"provisioning","x-public":true,"x-tool":true}},"/v1/pubsub/publish":{"post":{"operationId":"post_pubsub_publish","summary":"Puts one message on the org's bus.","description":"Puts one message on the org's bus. When a stream captures the subject\nthe write is DURABLE — the receipt names the stream and sequence only after\nJetStream has it on storage, and a repeated Nats-Msg-Id header within the\ndedup window answers duplicate instead of storing twice. When nothing\ncaptures it, the message goes out core NATS: delivered to current\nsubscribers, receipt {ok}, nothing retained.","tags":["pubsub"],"requestBody":{"content":{"application/json":{"example":{"data":"{\"id\":\"o_1\"}","headers":{"Nats-Msg-Id":"o_1"},"subject":"orders.created"},"schema":{"$ref":"#/components/schemas/pubsub.busPublish"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pubsub.busAck"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pubsub","x-public":true,"x-tool":true}},"/v1/pubsub/request":{"post":{"operationId":"post_pubsub_request","summary":"Sends one request on the org's bus and waits for one reply — the synchronous half of pub/sub, for callers speaking to a responder subscribed on the NATS port.","description":"Sends one request on the org's bus and waits for one reply — the\nsynchronous half of pub/sub, for callers speaking to a responder subscribed\non the NATS port. 404 when nobody is listening on the subject; 408 when a\nresponder exists but no reply arrived within the timeout.","tags":["pubsub"],"requestBody":{"content":{"application/json":{"example":{"data":"{\"sku\":\"gpu_1\"}","subject":"billing.quote","timeoutMs":2000},"schema":{"$ref":"#/components/schemas/pubsub.busRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pubsub.busMessage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"pubsub","x-public":true,"x-tool":true}},"/v1/reference":{"get":{"operationId":"riskReferenceSets","summary":"Lists every set this plane publishes, with its version and how fresh it is.","description":"Lists every set this plane publishes, with its version and how\nfresh it is.\n\nRead the Stale and Refused lists first: they are the two ways this plane can\nbe quietly wrong, and they are reported rather than inferred. A set in\nRefused answers nothing — it has never loaded, it is held by another\ncomponent, or it names a source we hold no licence for.","tags":["reference"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/reference.ReferenceSetsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"reference","x-public":true,"x-tool":true}},"/v1/reference/resolve":{"post":{"operationId":"riskResolveReference","summary":"Looks keys up against the reference plane.","description":"Looks keys up against the reference plane.\n\nYour organisation's own overrides are consulted FIRST and win outright; the\nshared baseline answers everything they do not cover. Every answer names the\nversion that produced it, when that version was current and whether it is\nstale, so a decision can record exactly what it consulted.\n\nRead Refusal before reading Hit. A set that has never loaded, one held by the\ncomponent that screens against it, and one whose source needs a licence we do\nnot hold all answer with a refusal — and a miss on a refusing set means\nnothing is known, not that the key is clean.","tags":["reference"],"requestBody":{"content":{"application/json":{"example":{"keys":["user@tempbox.example","3.5.140.1"],"sets":["domain","net"]},"schema":{"$ref":"#/components/schemas/reference.ResolveReferenceIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/reference.ResolveReferenceOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"reference","x-public":true,"x-tool":true}},"/v1/reference/{set}":{"delete":{"operationId":"riskClearReference","summary":"Removes one of your organisation's overrides.","description":"Removes one of your organisation's overrides.\n\nIt removes an entry your organisation wrote, never a baseline member: the\npublished set is not writable from here, so a removal can only ever restore\nthe baseline's own answer.","tags":["reference"],"parameters":[{"name":"set","in":"path","required":true,"schema":{"type":"string"},"example":"domain"},{"name":"key","in":"query","required":false,"schema":{"type":"string"},"example":"partner.example"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/reference.ClearReferenceOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"reference","x-public":true,"x-tool":true},"get":{"operationId":"riskReference","summary":"Reference describes one set and lists your org's overrides in it.","description":"Reference describes one set and lists your org's overrides in it.\n\nThe set half is public data about a published list — its version, its\npublishers, their licences and how current each one is. The overrides half is\nyours alone: it is read from your organisation's own store, and no other\norganisation's entries can appear in it.","tags":["reference"],"parameters":[{"name":"set","in":"path","required":true,"schema":{"type":"string"},"example":"domain"},{"name":"after","in":"query","required":false,"description":"After pages the override listing: the last key of the previous page.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps the override listing: default 200, maximum 1000.","schema":{"format":"int64","type":"integer"},"example":50}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/reference.ReferenceOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"reference","x-public":true,"x-tool":true},"put":{"operationId":"riskSetReference","summary":"Writes your organisation's own allow and deny entries over a set.","description":"Writes your organisation's own allow and deny entries over a set.\n\nIdempotent on the key: writing the same entry twice is one entry, and writing\nit again replaces the verdict and the note. The whole batch is one\ntransaction, so a batch that would cross the per-set bound writes nothing\nrather than half of itself — a half-applied deny list is worse than a refused\none, because nobody can tell which half applied.\n\nYour entries are held in your organisation's own store and are never visible\nto another organisation, and they never change what any other organisation\nsees. The shared baseline is not writable from here at all.","tags":["reference"],"parameters":[{"name":"set","in":"path","required":true,"schema":{"type":"string"},"example":"domain"}],"requestBody":{"content":{"application/json":{"example":{"entries":[{"key":"partner.example","note":"our reseller","verdict":"allow"}],"set":"domain"},"schema":{"$ref":"#/components/schemas/reference.SetReferenceIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/reference.SetReferenceOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"reference","x-public":true,"x-tool":true}},"/v1/referral":{"get":{"operationId":"get_referral","summary":"Returns the caller's referral code, share link and the referrals they have made.","description":"Returns the caller's referral code, share link and the referrals they have made.\n\nThe code is a stable, deterministic function of the org, so the link in this\nresponse is the same one every time. Each row carries the referee and the status\nof that attribution.\n\nIT IS A PURE READ. It advances no referral, grants nothing and deposits nothing\n— a GET reports state, it never changes it. Qualification is the admin sweep's\njob (POST /v1/admin/referral/sweep). The one row this handler can write is the\ncaller's OWN code-directory entry (EnsureCode), which materialises a value\nderiveCode already computes deterministically from the org id so the code has an\nO(1) reverse lookup; it carries no money, no referral state and no other tenant.","tags":["referral"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/referral.myReferrals"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"referral","x-public":true,"x-tool":true},"put":{"operationId":"put_referral","summary":"Updates the caller's referral code and returns the updated referral summary.","description":"Updates the caller's referral code and returns the updated referral summary.","tags":["referral"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/referral.setCodeRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/referral.myReferrals"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"referral","x-public":true,"x-tool":true}},"/v1/referral/claim":{"post":{"operationId":"post_referral_claim","summary":"Records that the caller's org signed up through a referral code.","description":"Records that the caller's org signed up through a referral code.\n\nThe REFEREE is the validated caller, never a client field, and the referrer is\nresolved from the code — so a caller can only ever attach THEMSELVES to someone\nelse's code. Referring yourself is 400 and an unknown code is 404.\n\nIt is idempotent and first-touch: an org can be referred once, ever. A repeat\ncall returns the referral already on file with created=false and 200, where the\nfirst call answers 201.\n\nRecording a referral grants nothing, and neither does anything downstream of it:\nthe edge later advances to qualified when the referee makes metered spend\n(POST /v1/admin/referral/sweep), and that is the end of it. No credit is ever\nissued from this package.","tags":["referral"],"requestBody":{"content":{"application/json":{"example":{"code":"H4NZ0ABC"},"schema":{"$ref":"#/components/schemas/referral.claimRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/referral.claimView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"referral","x-public":true,"x-tool":true}},"/v1/registry/images":{"get":{"operationId":"get_registry_images","summary":"Lists the org's container repositories, read live from the OCI catalog and filtered server-side to the org's namespace — the page can only ever hold the caller's own images.","description":"Lists the org's container repositories, read live from the OCI\ncatalog and filtered server-side to the org's namespace — the page can only\never hold the caller's own images.","tags":["registry"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/registry.registryImageList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"registry","x-public":true,"x-tool":true}},"/v1/registry/packages":{"get":{"operationId":"get_registry_packages","summary":"Lists the org's npm packages — `\u003corg\u003e` and `@\u003corg\u003e/…` — from the npm registry's search index, optionally narrowed by a query within that scope.","description":"Lists the org's npm packages — `\u003corg\u003e` and `@\u003corg\u003e/…` — from the\nnpm registry's search index, optionally narrowed by a query within that\nscope. The org boundary is applied server-side after the search, so a query\ncan never widen it.","tags":["registry"],"parameters":[{"name":"query","in":"query","required":false,"description":"Query narrows the listing within the org's scope when present; the org\nboundary itself is never widened by it. It rides the query string.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/registry.registryPackageList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"registry","x-public":true,"x-tool":true}},"/v1/registry/projects":{"get":{"operationId":"get_registry_projects","summary":"Lists the namespaces the caller can see with what each holds: the org's slug, its repository count on the OCI catalog, and its package count on the npm registry.","description":"Lists the namespaces the caller can see with what each holds: the\norg's slug, its repository count on the OCI catalog, and its package count\non the npm registry. Today that is exactly one row — the caller's org.","tags":["registry"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/registry.registryProjectList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"registry","x-public":true,"x-tool":true}},"/v1/registry/status":{"get":{"operationId":"get_registry_status","summary":"Reports whether the OCI and npm registries are reachable and, when the OCI half is auth-gated, which token realm its challenge advertises — an honest lens for \"is the registry plane up\", never a fabricated ok.","description":"Reports whether the OCI and npm registries are reachable and, when\nthe OCI half is auth-gated, which token realm its challenge advertises — an\nhonest lens for \"is the registry plane up\", never a fabricated ok.","tags":["registry"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/registry.registryStatus"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"registry","x-public":true,"x-tool":true}},"/v1/registry/tags":{"get":{"operationId":"get_registry_tags","summary":"Lists one org-owned repository's tags, read live from the OCI registry.","description":"Lists one org-owned repository's tags, read live from the OCI registry.\nThe repository is addressed inside the org's namespace — a name outside it\ncannot be expressed, and an unknown one answers 404.","tags":["registry"],"parameters":[{"name":"image","in":"query","required":false,"description":"Image is the repository name inside the org's namespace, as returned by\nthe images op. It rides the query string.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/registry.registryTagList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"registry","x-public":true,"x-tool":true}},"/v1/registry/token":{"post":{"operationId":"post_registry_token","summary":"Mints a short-lived, pull-only registry token for exactly one of the org's images, through the same IAM realm the docker CLI authenticates against.","description":"Mints a short-lived, pull-only registry token for exactly one of the\norg's images, through the same IAM realm the docker CLI authenticates\nagainst. The scope is pinned server-side to `\u003corg\u003e/\u003cimage\u003e` with the `pull`\naction — no field exists to name another org's image or ask for push. Use it\nas `Authorization: Bearer …` on the OCI wire; it expires in minutes.","tags":["registry"],"requestBody":{"content":{"application/json":{"example":{"image":"cloud"},"schema":{"$ref":"#/components/schemas/registry.registryMint"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/registry.registryToken"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"registry","x-public":true,"x-tool":true}},"/v1/rerank":{"post":{"operationId":"post_rerank","summary":"Implements POST /v1/rerank (Cohere/Jina-compatible).","description":"Implements POST /v1/rerank (Cohere/Jina-compatible).\n\nBody: {\"model\": \"...\", \"query\": \"...\", \"documents\": [\"...\", ...]|[{\"text\":\"...\"}],\n\n\t\"top_n\"?: int, \"return_documents\"?: bool}\n\nResponse: {\"object\":\"list\",\"model\":...,\"results\":[{\"index\",\"relevance_score\",\"document\"?}],\"usage\":{...}}\n\nBackend selection is provider-driven (one endpoint, one contract):\n  - If the model routes to a native rerank provider (Jina/Cohere/Voyage) the\n    request is proxied to that provider's /rerank endpoint.\n  - Otherwise scores are computed as a real bi-encoder ranking: embed the\n    query and documents through the resolved embedding model and rank by\n    cosine similarity. No rerank-specific key required.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.Ranking"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/responses":{"post":{"operationId":"post_responses","summary":"Implements POST /v1/responses.","description":"Implements POST /v1/responses. The converted request is completed by\nthe chat path, which is handed a sink saying where the answer goes: a stream is\ntranslated as it is produced, a whole body is translated entire.","tags":["ai"],"parameters":[{"name":"X-Max-Cost","in":"header","required":false,"description":"The most this request may cost, in USD per 1,000 tokens. Routing picks only models under it; an org's own ceiling fills it when it is absent, and the lower of the two holds.","schema":{"minimum":0,"type":"number"}},{"name":"X-Max-Latency-Ms","in":"header","required":false,"description":"The slowest model this request accepts, in milliseconds.","schema":{"minimum":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ai.ResponsesResource"},{"properties":{"routing":{"description":"What the router decided for this request and why, present when one routed it (a model Enso routes by reasoning depth). Every field is one the router read or wrote; it reports no score, expected cost or latency because it weighs none.","properties":{"candidates":{"description":"Each model the router's table names, with the reasoning depths that read it, shallow to deep.","items":{"properties":{"depths":{"items":{"type":"string"},"type":"array"},"model":{"type":"string"}},"required":["model","depths"],"type":"object"},"type":"array"},"chosen":{"description":"The model the request is served at.","type":"string"},"inputs":{"properties":{"depth":{"description":"The reasoning depth the request states; default when it states none.","type":"string"},"key":{"description":"The table row that depth was read at.","type":"string"},"policy":{"description":"Whether the caller's plan or credit pays for the paid model at that depth.","enum":["funded","unfunded","n/a"],"type":"string"}},"required":["depth","key","policy"],"type":"object"},"reason":{"description":"How the inputs led to chosen, in a sentence.","type":"string"},"router":{"description":"The router that decided: enso.","type":"string"}},"required":["router","chosen","candidates","inputs","reason"],"type":"object"}},"type":"object"}]}}},"description":"Success.","headers":{"X-Routed-Model":{"description":"The model that served a routed request, one that named auto or an id the router resolves. The body's model field names the same id.","schema":{"type":"string"}}}},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/risk/features":{"get":{"operationId":"riskFeatures","summary":"The feature catalogue: what the model reads, and what your surface carries","description":"Features is the feature catalogue in its two honest lenses.\n\nThe MODEL lens is the governed inventory: one entry per dimension of the model\nspace, each carrying the typology it serves, the supervisor's own words for the\nindicator, and the published standard those words come from — so a coverage\nclaim is checkable rather than asserted. It is the same for every organisation.\n\nThe SURFACE lens is what THIS organisation's own event surface actually carries,\nmeasured over the window: how many of its buckets carry each dimension at all,\nand what the dimension reads where it is present. A dimension present in no\nbucket is BLIND, and saying so is the difference between no risk and no data.","tags":["risk"],"parameters":[{"name":"days","in":"query","required":false,"description":"Days is how far back to measure the organisation's own coverage, 1 to 400.\nZero takes thirty.","schema":{"format":"int64","type":"integer"},"example":30}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/risk.riskCatalog"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"risk","x-public":true,"x-tool":true}},"/v1/risk/health":{"get":{"operationId":"get_risk_health","summary":"Whether the risk model plane can actually work right now","description":"Reports whether the per-organisation model plane is genuinely usable: that the plane was built, that the per-organisation stores can be written, and whether the event surface the feature plane is rolled up from is reachable. It is a REAL probe, not status theatre.\n\n200 only when the plane can work. Otherwise 503 CARRYING THE REPORT — which part failed and the real error — and that body is why this is not a typed op: a typed op reaches a non-2xx by returning an error, and the envelope that produces would drop exactly the detail the probe exists to deliver.\n\nAn unreachable event surface is REPORTED and is not a failure. Scoring reads in-memory aggregates and never the warehouse, so a warm that cannot run degrades how much history a model has seen and does not stop it deciding.\n\nIt also reports how many organisations' models are resident, how many have been evicted to hold that bound, and how many of the resident ones are at their own aggregate bound. Eviction is lossless — learned state is written to that organisation's own store first and its aggregates rebuild from its own record — so a climbing count is a capacity signal, not a loss. A STRAINED model is different: it has started forgetting its own least-recently-active subjects, and each forgotten subject reads as inactive until it is active again. That is a control degrading, and it is reported here because it is otherwise silent.\n\nIt answers about the process, not about a tenant: it takes no organisation and names none.","tags":["risk"],"x-app":"risk","x-public":true}},"/v1/risk/learn":{"post":{"operationId":"riskLearn","summary":"Teach your organisation's own model from its own events","description":"Records a batch of events into the caller organisation's own aggregates\nand lets its model learn from them. It answers how many it learned from.\n\nIT DOES NOT SCORE, AND THAT IS THE POINT. An observation is a value you record;\nlearning is a transformation over observations; a verdict is a query against the\nresult. This op is the first two. [ops.score] is the third, it is pure, and it\nis the ONE entry point to a verdict. They were one call, which meant you could\nnot record without training and could not train without being answered — and the\nmodel ran twice over every event to produce a verdict the response carried and\nno caller read.\n\nTO OBSERVE AND JUDGE, COMPOSE THE TWO, and mind the order. Score FIRST, then\nlearn: the score is then the model's opinion of an event it has not yet learned\nfrom, which is the question worth asking. The other order answers for a model\nthat has already absorbed the event it is judging.\n\nThis is the training path, and there is no job behind it: the model IS a set of\nmass counters over half-space trees, so learning is an increment and the model\nis current the instant the last event lands. Nothing from any other\norganisation is in it, and nothing from this organisation leaves it.\n\nA RETRY IS INERT. The record deduplicates on the event id you send, and an event\nalready in it moves nothing, costs nothing and is not counted — so a client that\ntimed out can send the same batch again and its model holds what it holds.\nWithout an id of your own there is nothing to converge on: two identical bodies\nare two events.","tags":["risk"],"requestBody":{"content":{"application/json":{"example":{"events":[{"id":"tx_9","kind":"account","nano":420000000,"subject":"u_412"}]},"schema":{"$ref":"#/components/schemas/risk.riskLearnIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/risk.riskLearnOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"risk","x-public":true,"x-tool":true}},"/v1/risk/policy":{"get":{"operationId":"riskPolicy","summary":"Your organisation's decision-regime history, and which version is in force","description":"Reports the caller organisation's own decision-regime history: every\ndistinct regime it has adopted, which version is in force, and what retention\nhas taken.\n\nWHY IT EXISTS. Every score cites the version it was decided under\n([riskScoreOut.Policy]), and the threshold that score was measured against is\nderived from the appetite that version states. Restate the appetite and, without\nthis record, every earlier decision becomes unreconstructible — the cut it was\njudged by no longer exists anywhere. An adverse decision that cannot be\nexplained against the policy in force when it was taken cannot be defended.\n\nIt covers ONE organisation. The history is on that organisation's own shelf, so\nanother's versions are not filtered out of the answer — they are not in the file\nthe answer is read from.","tags":["risk"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/risk.riskPolicyOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"risk","x-public":true,"x-tool":true},"put":{"operationId":"riskSetPolicy","summary":"State the decision regime: the appetite, the sample, and whether the model is live","description":"States the decision regime the caller organisation's model decides\nunder: how much of its own stream may be sent for examination, how much of the\nrest is sampled to measure what was missed, and whether the model may change an\noutcome at all.\n\nThe appetite is the decision a model is not permitted to make for itself: its\noutput is a probability, so how likely it is to MISS something is a matter of\npolicy that has to be stated, measured and reviewed rather than absorbed into a\nconstant. The alert threshold is derived from it as a quantile of the scores\nactually observed, which is what keeps its meaning as the distribution drifts.\n\nIt is DURABLE BEFORE IT IS IN FORCE. The regime is recorded as a new version on\nthe organisation's own shelf before anything in memory moves, so a policy that\ncannot be written down is refused rather than answered from state the next\nrollout would silently undo.\n\nARMING IS AN ADMIN ACT AND TUNING IS NOT. Setting `live` requires an admin of\nthis organisation; stating the appetite and the sample is self-service for any\nmember. Taking the model live decides whether it may change an OUTCOME at all —\na payment frozen, a grant refused — for every customer this organisation has,\nand that is a decision an organisation takes rather than one of its members.\n\nA RESTATEMENT OF THE REGIME IN FORCE MINTS NOTHING and answers the version\nalready in force. Compare the version you receive with the version you had:\nunchanged means the numbers were the same, which is why there is no flag for it.\n\nLearned state survives the change. The model's identity covers its SHAPE — the\ninventory and the geometry — and not its appetite, so restating policy unlearns\nnothing. It also does not REPORT the learned state: what the model is is read\nfrom the model.","tags":["risk"],"requestBody":{"content":{"application/json":{"example":{"live":false,"review":0.01,"sample":0.001},"schema":{"$ref":"#/components/schemas/risk.riskAppetiteIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/risk.riskPolicyOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"risk","x-public":true,"x-tool":true}},"/v1/risk/score":{"post":{"operationId":"riskScore","summary":"Score one event against your organisation's own model","description":"Judges one event against the caller organisation's OWN model and learns\nnothing from it. It is how a candidate is tried against real behaviour before\nanything depends on the answer, and it is the model's analogue of testing a\nrule.\n\nBecause it records nothing, the aggregates it reads do not include the event:\nthe numbers are the organisation's history as it stands. A model still warming\ndeclines with a reason rather than answering zero, because silence must never\nread as a clean result.","tags":["risk"],"requestBody":{"content":{"application/json":{"example":{"event":{"id":"tx_9","kind":"account","nano":420000000,"subject":"u_412"}},"schema":{"$ref":"#/components/schemas/risk.riskScoreIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/risk.riskScoreOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"risk","x-public":true,"x-tool":true}},"/v1/risk/search":{"post":{"operationId":"riskSearch","summary":"Search exhaustively for the model shape that fits your own history","description":"Runs an exhaustive search for the model shape that best fits the caller\norganisation's own history, and answers 202 with the run to read back.\n\nEvery candidate is replayed over that organisation's OWN feature surface in its\nown sandbox — its own aggregates, its own model, neither of them the live one —\nso a run cannot move a live threshold and cannot see another organisation's\ndata. The result is the learning curve for each shape and the one that fit\nbest, ranked on how closely it honoured the stated appetite, whether it warmed\nat all, whether it saturated, and how much of the coordinate space it left\nblind.\n\nAn empty history is REFUSED rather than reported as zero alerts, because \"no\nalerts\" is exactly what a quiet model looks like.","tags":["risk"],"requestBody":{"content":{"application/json":{"example":{"days":30},"schema":{"$ref":"#/components/schemas/risk.riskSearchIn"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/risk.riskSearchRun"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"risk","x-public":true,"x-tool":true}},"/v1/risk/search/{id}":{"get":{"operationId":"riskSearchResult","summary":"Read back one exhaustive search","description":"Reads back one search run: every shape tried over this\norganisation's own history, best first, and the one that fit.\n\nA run another organisation started is simply not there — the same 404 an\nunknown id gives, so the read is not a probe oracle.","tags":["risk"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the run, taken from the path. A run another organisation started is\nsimply not there — the same answer an unknown id gives.","schema":{"type":"string"},"example":"srch_2f6a1c"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/risk.riskSearchReport"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"risk","x-public":true,"x-tool":true}},"/v1/risk/state":{"get":{"operationId":"riskState","summary":"Report your organisation's model: what it learned, and what it realised","description":"Reports the caller organisation's own model: what it has learned, whether\nit is live or still in shadow, the threshold in force, the appetite it stated\nbeside the share it actually realised, every refusal by reason, every feature\nthat read blind, and how much of the organisation's own event surface has been\nfolded in.\n\nIt covers ONE organisation. A caller cannot learn another's volumes, alert rate\nor behaviour from it, because the state is read out of a model that holds only\nits own.","tags":["risk"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/risk.riskModelState"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"risk","x-public":true,"x-tool":true}},"/v1/risk/state/model":{"post":{"operationId":"riskPublishModel","summary":"Publish your organisation's model as a named, immutable value","description":"Publishes your organisation's model as a NAMED VALUE, so a decision\ntaken today can be reconstructed tomorrow and a change made today can be undone.\n\nIt answers with a NAME and not with the state. The masses stay on your\norganisation's own encrypted store and are referred to by an address computed\nfrom their own content: the shape, the geometry seed, the position in the window,\nthe threshold, the masses themselves as IEEE-754 bits, and the fold watermark\nbehind them. That is what makes the value nameable without making the caller its\ncustodian.\n\nIT IS IDEMPOTENT ON THE VALUE. A model that has not changed publishes to the name\nit already has and mints nothing, reporting minted=false — so publishing at every\nboundary that matters is free. Ten values are retained per organisation, bounded\nin BYTES rather than in rows, and the oldest is disposed of past that.\n\nA model that has learned nothing is refused: planted is not learned, and a value\nthat reproduces nothing is not a value.\n\nIt is POST and PUT on one address because they are one plane's two verbs over one\nkind of thing: POST mints a value from the model in force, PUT puts a value in\nforce. They were /v1/risk/state/snapshot and /v1/risk/state/restore — two addresses\nnamed after the operation rather than after the thing, which is how a reader ends\nup asking what the difference between a snapshot and a value is.","tags":["risk"],"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/risk.riskPublishOut"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"risk","x-public":true,"x-tool":true},"put":{"operationId":"riskAdoptModel","summary":"Put one of your organisation's own published model values in force","description":"Puts one of your organisation's OWN PUBLISHED VALUES in force, by name —\nwhich is what an instant rollback is, what promoting a challenger is, and what\ninstalling the shape a search found is.\n\nIT TAKES AN ADDRESS AND NEVER STATE. The masses are read from your own store, so\nnothing about your model has to be held by whatever is making this call. That\ncloses the sharpest edge the previous shape had: a body of counters is something\na caller can COMPOSE, and a region filled until activity inside it reads as\nordinary is a model that has been shaped rather than learned. The engine's mass\ninvariant was the only thing standing between a composed body and the model; with\nan address there is no body to compose.\n\nIT ADOPTS THE SHAPE, NOT ONLY THE MASSES. A value records the model space its\nmasses were taken in, and a value whose space differs from the one in force\nREPLANTS your model into that space before restoring them. That is what makes\nPOST /v1/risk/search actionable: a search answers with the shape that fits your own\nhistory best and publishes it fitted, and its address is what you name here. Before\nthis, a winning shape was advice nobody could take — the adoption path refused every\nshape change, and a winner is a different shape by definition.\n\nWHAT ADOPTING A SEARCHED SHAPE COSTS, SAID PLAINLY: the value a search fits has\nlearned the window the search replayed and nothing older, so installing it trades\nhistory for fit. Your appetite is untouched — that is your policy record's, with its\nown versions — and so is the geometry, which stays your own.\n\nAn address your organisation has not published is NOT FOUND. That includes one\nanother organisation published, and it is not a lookup that failed: the store is\nper organisation and the address is a name, never an authority.","tags":["risk"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/risk.riskAdoptIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/risk.riskModelState"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"risk","x-public":true,"x-tool":true}},"/v1/runner/declare":{"post":{"operationId":"post_runner_declare","summary":"Republishes what a registered runner can do, and answers with what this side understands, so the two learn about each other from one exchange.","description":"Republishes what a registered runner can do, and answers with what\nthis side understands, so the two learn about each other from one exchange.","tags":["git"],"parameters":[{"name":"x-runner-uuid","in":"header","required":false,"schema":{"type":"string"}},{"name":"x-runner-token","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/runner.DeclareIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/runner.DeclareOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/runner/log":{"post":{"operationId":"post_runner_log","summary":"Adds console output to a task's log and answers with how far that log is durable, so the runner knows where to resend from.","description":"Adds console output to a task's log and answers with how far that log is\ndurable, so the runner knows where to resend from.","tags":["git"],"parameters":[{"name":"x-runner-uuid","in":"header","required":false,"schema":{"type":"string"}},{"name":"x-runner-token","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/runner.LogIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/runner.LogOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/runner/register":{"post":{"operationId":"post_runner_register","summary":"Trades a pool's join secret for a runner identity and the token that authenticates every later call.","description":"Trades a pool's join secret for a runner identity and the token that\nauthenticates every later call. It is the one operation with no credential to\ncheck, because a runner has none until this answers.\n\nThe secret names the pool it opens, and a pool exists only because somebody\ndeclared it. A daemon that starts against capacity nobody declared is refused\nhere, which is where the rule that pools are declared state actually holds.","tags":["git"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/runner.RegisterIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/runner.RegisterOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/runner/state":{"post":{"operationId":"post_runner_state","summary":"Records a task's progress and that of its steps, and answers with the result this side now holds — which is how a runner learns its task was stopped from somewhere else.","description":"Records a task's progress and that of its steps, and answers with the\nresult this side now holds — which is how a runner learns its task was stopped\nfrom somewhere else.","tags":["git"],"parameters":[{"name":"x-runner-uuid","in":"header","required":false,"schema":{"type":"string"}},{"name":"x-runner-token","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/runner.StateIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/runner.StateOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/runner/task":{"post":{"operationId":"post_runner_task","summary":"Hands the runner a job to execute, if its pool has one, and answers immediately either way.","description":"Hands the runner a job to execute, if its pool has one, and answers\nimmediately either way. A runner sends the queue version it last saw; when it\nmatches, nothing has been queued since and no lease transaction is opened.","tags":["git"],"parameters":[{"name":"x-runner-uuid","in":"header","required":false,"schema":{"type":"string"}},{"name":"x-runner-token","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/runner.TaskIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/runner.TaskOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"git","x-public":true,"x-tool":true}},"/v1/s3/buckets":{"get":{"operationId":"get_s3_buckets","summary":"Lists the caller org's own buckets.","description":"Lists the caller org's own buckets.\n\nOnly the caller's: every bucket is physically named under a per-org prefix and\nthe listing strips that prefix, so a tenant sees friendly names and another\ntenant's buckets are not in the answer at all. Another org's bucket is not\nrefused but INVISIBLE, so this cannot be used to learn that a name is taken\nelsewhere.\n\nBilled per call: the balance is checked BEFORE anything is touched, so an\nunfunded org is refused with nothing done, and the debit lands only once the\nwork has succeeded.","tags":["s3"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/s3.bucketList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"s3","x-public":true,"x-tool":true},"post":{"operationId":"post_s3_buckets","summary":"Makes a new bucket for the caller's org and answers 201 with it.","description":"Makes a new bucket for the caller's org and answers 201 with it.\n\nIt requires an admin of the org, a SuperAdmin, or the org's own application\n(CI makes its cache bucket on first use): every member of the org uses\nits buckets, and only an admin makes or removes one. Anyone else is refused 403\nwith nothing created.\n\nThe physical name is derived from the caller's validated org, so a tenant can\nonly ever create inside its own namespace and no request field can redirect\nthat. A name already taken in the org is 409.\n\nBilled per call: the balance is checked BEFORE anything is touched, so an\nunfunded org is refused with nothing created, and the debit lands only once the\nbucket exists.","tags":["s3"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/s3.bucketIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/s3.bucketItem"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"s3","x-public":true,"x-tool":true}},"/v1/s3/buckets/{bucket}":{"delete":{"operationId":"delete_s3_buckets_by_bucket","summary":"Removes an EMPTY bucket and answers 204.","description":"Removes an EMPTY bucket and answers 204.\n\nIt requires an admin of the org, or a SuperAdmin, as creating one does; anyone\nelse is refused 403 with nothing deleted.\n\nA non-empty bucket is 409 rather than a cascade: deleting a tenant's objects\nbehind a single bucket call is not a thing this surface will do silently. A\nbucket the caller's org does not own is the same 404 an unknown name gives.\n\nBilled per call: the balance is checked BEFORE anything is touched, so an\nunfunded org is refused with nothing deleted, and the debit lands only once the\nbucket is gone.","tags":["s3"],"parameters":[{"name":"bucket","in":"path","required":true,"description":"Bucket is the bucket's friendly name, from the path.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"s3","x-public":true,"x-tool":true}},"/v1/s3/buckets/{bucket}/objects":{"get":{"operationId":"get_s3_buckets_by_bucket_objects","summary":"Lists one folder level of a bucket.","description":"Lists one folder level of a bucket.\n\nFolder-style by default: sub-prefixes come back as directory entries, which is\nthe file-manager view. `?recursive=true` lists every key flat under the prefix\ninstead. Keys are RELATIVE to `?prefix=`, and the listing is bounded so a huge\nbucket cannot exhaust memory — Total is what came back, not what the bucket\nholds.\n\nBilled per call: the balance is checked BEFORE anything is touched, so an\nunfunded org is refused with nothing read, and the debit lands only once the\nlisting has succeeded.","tags":["s3"],"parameters":[{"name":"bucket","in":"path","required":true,"description":"Bucket is the bucket to list, from the path.","schema":{"type":"string"}},{"name":"prefix","in":"query","required":false,"schema":{"type":"string"}},{"name":"recursive","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/s3.objectList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"s3","x-public":true,"x-tool":true},"post":{"operationId":"post_s3_buckets_by_bucket_objects","summary":"Mints a presigned PUT URL the caller uploads to DIRECTLY.","description":"Mints a presigned PUT URL the caller uploads to DIRECTLY.\n\nThe bytes never pass through this binary and the admin credential never leaves\nthe server: the URL is signed against the PUBLIC host, scoped to exactly this\nbucket and key, and expires. A deployment with no public endpoint configured\ncannot mint one and answers 503 rather than a URL that will not work.\n\nBilled per call — for MINTING the URL, which is the work this operation does;\nthe upload that follows it goes straight to the store and is not seen here. The\nbalance is checked BEFORE anything is touched, so an unfunded org is refused\nwith no URL issued.","tags":["s3"],"parameters":[{"name":"bucket","in":"path","required":true,"description":"Bucket is the bucket to upload into, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/s3.uploadIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/s3.presignResponse"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"s3","x-public":true,"x-tool":true}},"/v1/s3/buckets/{bucket}/uploads":{"post":{"operationId":"post_s3_buckets_by_bucket_uploads","summary":"Begins a multipart upload of a large file into one of the caller's org buckets.","description":"Begins a multipart upload of a large file into one of the caller's\norg buckets. Then mint presigned URLs for its parts with POST\n.../uploads/{upload}/parts, PUT each part's bytes to its URL — every part but\nthe last exactly partSize bytes — and assemble the object with POST\n.../uploads/{upload}/complete. A dropped connection loses nothing:\nGET .../uploads/{upload} lists the parts already stored, so only the rest are\nsent again. Use this for anything over a few megabytes; a small file takes the\nsingle presigned PUT of POST /v1/s3/buckets/{bucket}/objects.","tags":["s3"],"parameters":[{"name":"bucket","in":"path","required":true,"description":"Bucket is the bucket to upload into, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"key":"chat/backup.tar","type":"application/x-tar"},"schema":{"$ref":"#/components/schemas/s3.uploadStart"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/s3.uploadStarted"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"s3","x-public":true,"x-tool":true}},"/v1/s3/buckets/{bucket}/uploads/{upload}":{"delete":{"operationId":"delete_s3_buckets_by_bucket_uploads_by_upload","summary":"Aborts a multipart upload and deletes the parts it stored.","description":"Aborts a multipart upload and deletes the parts it stored. The\nobject it would have become is never created.","tags":["s3"],"parameters":[{"name":"bucket","in":"path","required":true,"description":"Bucket is the bucket, from the path.","schema":{"type":"string"}},{"name":"upload","in":"path","required":true,"description":"Upload is the upload's id, from the path.","schema":{"type":"string"}},{"name":"key","in":"query","required":false,"description":"Key is the object key the upload was started on. In the query for a read\nor an abandon, in the body to complete.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/s3.uploadGone"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"s3","x-public":true,"x-tool":true},"get":{"operationId":"get_s3_buckets_by_bucket_uploads_by_upload","summary":"Answers the parts a multipart upload already holds, in order: what a client resuming after a dropped connection reads to send only the rest.","description":"Answers the parts a multipart upload already holds, in order: what\na client resuming after a dropped connection reads to send only the rest.","tags":["s3"],"parameters":[{"name":"bucket","in":"path","required":true,"description":"Bucket is the bucket, from the path.","schema":{"type":"string"}},{"name":"upload","in":"path","required":true,"description":"Upload is the upload's id, from the path.","schema":{"type":"string"}},{"name":"key","in":"query","required":false,"description":"Key is the object key the upload was started on. In the query for a read\nor an abandon, in the body to complete.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/s3.storedParts"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"s3","x-public":true,"x-tool":true}},"/v1/s3/buckets/{bucket}/uploads/{upload}/complete":{"post":{"operationId":"post_s3_buckets_by_bucket_uploads_by_upload_complete","summary":"Assembles a multipart upload into its object from every part the store holds, in order.","description":"Assembles a multipart upload into its object from every part the\nstore holds, in order. The parts must run 1, 2, 3 … with no gap; a gap is 409,\nnaming the first part missing, and the upload stays open to send it.","tags":["s3"],"parameters":[{"name":"bucket","in":"path","required":true,"description":"Bucket is the bucket, from the path.","schema":{"type":"string"}},{"name":"upload","in":"path","required":true,"description":"Upload is the upload's id, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/s3.uploadRef"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/s3.uploadDone"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"s3","x-public":true,"x-tool":true}},"/v1/s3/buckets/{bucket}/uploads/{upload}/parts":{"post":{"operationId":"post_s3_buckets_by_bucket_uploads_by_upload_parts","summary":"Answers presigned PUT URLs for some parts of a multipart upload, at most 64 a call, each valid for minutes: mint them as the upload reaches them.","description":"Answers presigned PUT URLs for some parts of a multipart upload, at\nmost 64 a call, each valid for minutes: mint them as the upload reaches them.\nPUT a part's bytes to its URL as they are — no headers are signed — and the\nstore answers the part's ETag, which completing does not need.","tags":["s3"],"parameters":[{"name":"bucket","in":"path","required":true,"description":"Bucket is the bucket, from the path.","schema":{"type":"string"}},{"name":"upload","in":"path","required":true,"description":"Upload is the upload's id, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/s3.uploadParts"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/s3.partURLs"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"s3","x-public":true,"x-tool":true}},"/v1/s3/health":{"get":{"operationId":"get_s3_health","summary":"Reports whether this deployment can serve object storage.","description":"Reports whether this deployment can serve object storage.\n\nIt is a REAL probe rather than a constant: 200 when admin credentials are\npresent, so the store is reachable in principle, and 503 with the reason when\nthey are not. It is deliberately NOT gated — liveness has to be probe-able\nwithout a token — so it is the one operation here that names no bucket and\nbills nothing.","tags":["s3"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/s3.s3Health"}}},"description":"ok"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/s3.s3Health"}}},"description":"service unavailable"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"s3","x-public":true,"x-tool":true}},"/v1/sandbox":{"get":{"operationId":"get_sandbox","summary":"Lists the sandboxes the caller holds, newest first.","description":"Lists the sandboxes the caller holds, newest first.\n\nA member holds the sandboxes they leased; an admin of the org, or a SuperAdmin,\nholds every one in it. `?project=` and `?status=` narrow it. Only the caller's\norg's: the store is keyed on the validated org, so another tenant's sandbox is\nnot something this operation can return.","tags":["sandbox"],"parameters":[{"name":"project","in":"query","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.sandboxList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sandbox","x-public":true,"x-tool":true},"post":{"operationId":"post_sandbox","summary":"Leases a sandbox — a real computer — for the caller's org.","description":"Leases a sandbox — a real computer — for the caller's org.\n\nThe class decides what it is for and therefore its image, working directory\nand isolation. A dev or desktop sandbox is SINGLE-ATTACH per project, so\nasking twice for one project resumes the one that exists rather than paying\nfor a second; an exec sandbox carries no project and is bounded per org\ninstead, refused 429 past the ceiling because the caller's correct response is\nto wait.\n\nAnswers 201 with the sandbox as leased, which names the runtime it GOT — not\nthe one that was asked for.","tags":["sandbox"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.sandboxIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.Sandbox"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sandbox","x-public":true,"x-tool":true}},"/v1/sandbox/end":{"post":{"operationId":"end_sandbox","summary":"End a sandbox and release it","description":"Ends the caller's sandbox lease: the pod goes, and the volume goes only\nwhen the caller asked for that too.","tags":["sandbox"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.EndIn"}}},"required":true},"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sandbox","x-public":true,"x-tool":true}},"/v1/sandbox/lease":{"post":{"operationId":"lease_sandbox","summary":"Lease a sandbox — a real computer — or resume one you hold","description":"Leases the caller's sandbox, or returns the one it named if that\nlease is still running, or gives it a pod again if it is parked — with its\ndisk as it was left.\n\nWhat comes back is a real computer: a pod under a runtime boundary with a\ntoolchain already in it, its own filesystem, and a lease that ends it. Every\nother op here acts on the one this returns.","tags":["sandbox"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.LeaseIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.Leased"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sandbox","x-public":true,"x-tool":true}},"/v1/sandbox/read":{"post":{"operationId":"read_sandbox_file","summary":"Read a file from a sandbox you hold","description":"Reads one path in the caller's sandbox: a file's bytes, or a\ndirectory's entries when the path names one.","tags":["sandbox"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.PathIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.Blob"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sandbox","x-public":true,"x-tool":true}},"/v1/sandbox/run":{"post":{"operationId":"run_in_sandbox","summary":"Run a command in a sandbox you hold and read its output","description":"Runs one command inside the caller's sandbox and answers its exit code,\nstdout and stderr. A non-zero exit is a successful call carrying a failed\nprogram, so it comes back as data and not as an error.\n\nName a `session` and the command NARRATES INTO IT: its output is appended to\nthat session's live log as the program produces it, so anything watching the\nsession — GET /v1/agent/sessions/stream, scoped to one run with ?root= —\nwatches the work happen rather than waiting for the verdict. Without it the\ncall is what it always was: silent until it returns, which for an agentic run\nis twenty-five minutes of blank screen.\n\nThe session is named; the TENANT is not. It is the org the caller already\nproved, so a session belonging to somebody else is absent from the org this\ncall acts for and the append is refused there.","tags":["sandbox"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.RunIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.Ran"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sandbox","x-public":true,"x-tool":true}},"/v1/sandbox/stop":{"post":{"operationId":"stop_run","summary":"Stop what a sandbox is running, and keep the sandbox","description":"Interrupts whatever the caller's sandbox is running and answers how\nmany commands it ended. The sandbox stays leased — stop ends the WORK, end ends\nthe RESOURCE — so whoever stopped a run can still read what it left behind.","tags":["sandbox"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.StopIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.Stopped"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sandbox","x-public":true,"x-tool":true}},"/v1/sandbox/write":{"post":{"operationId":"write_sandbox_file","summary":"Write a file into a sandbox you hold","description":"Writes bytes to one path in the caller's sandbox, creating parents,\nand answers the resolved path.","tags":["sandbox"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.WriteIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.Wrote"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sandbox","x-public":true,"x-tool":true}},"/v1/sandbox/{id}":{"delete":{"operationId":"delete_sandbox_by_id","summary":"Ends a sandbox and releases the compute behind it.","description":"Ends a sandbox and releases the compute behind it. Answers 204.\n\nENDING IS NOT STOPPING. This releases the resource: the pod goes and anything\nonly inside it goes with it. To end what a sandbox is RUNNING while keeping\nthe sandbox — the checkout, the logs, the half-written file — the verb is\nPOST /v1/sandbox/stop.\n\n`?purge=1` additionally removes the record, so the sandbox stops being listed\nat all rather than being listed as ended.","tags":["sandbox"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the sandbox to end, from the path.","schema":{"type":"string"}},{"name":"purge","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sandbox","x-public":true,"x-tool":true},"get":{"operationId":"get_sandbox_by_id","summary":"Returns one sandbox: its class, project, image, the runtime it was given, its status and when its lease ends.","description":"Returns one sandbox: its class, project, image, the runtime it was\ngiven, its status and when its lease ends.\n\nA sandbox is its lessee's and its org admins'. An id the caller does not hold —\nanother org's, or another member's — is the same 404 an unknown id gives.","tags":["sandbox"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the sandbox to address, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.Sandbox"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sandbox","x-public":true,"x-tool":true}},"/v1/sandbox/{id}/exec":{"post":{"operationId":"post_sandbox_by_id_exec","summary":"Runs one command in a sandbox the caller holds and answers with its exit code, stdout and stderr.","description":"Runs one command in a sandbox the caller holds and answers with\nits exit code, stdout and stderr.\n\nSend `argv` — an argument vector cannot be word-split by accident — or\n`command` for a shell line, which is the only input here that ever reaches a\nshell. A non-zero exit is a SUCCESSFUL call carrying a failed command: the\nstatus is 200 and the exit code is in the answer, because \"the command failed\"\nand \"the call failed\" are different facts.","tags":["sandbox"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the sandbox to run in, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.execRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.ExecResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sandbox","x-public":true,"x-tool":true}},"/v1/sandbox/{id}/fs":{"get":{"operationId":"get_sandbox_by_id_fs","summary":"Read a file, or list a directory","description":"Reads one file from the sandbox's project directory as text, or lists the entries when the path names a directory. Paths resolve under the project root and a path that climbs out is refused rather than rewritten.","tags":["sandbox"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"sandbox","x-public":true},"post":{"operationId":"post_sandbox_by_id_fs","summary":"Write a file","description":"Writes the request body to one file in the sandbox's project directory, creating parent directories. Same confinement as the read above.","tags":["sandbox"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"sandbox","x-public":true}},"/v1/sandbox/{id}/pause":{"post":{"operationId":"post_sandbox_by_id_pause","summary":"Stops the pod, keeps the row and the volume, and settles the tail: POST /v1/sandbox/:id/pause.","description":"Stops the pod, keeps the row and the volume, and settles the tail: POST\n/v1/sandbox/:id/pause.\n\nThe claim, the stop and the ship are ONE settlement for the same reason a\nretirement is — the snapshot that carries the advanced watermark has to carry\nthe new state, or a successor hydrates a running row for a pod that is gone\nand bills for it until the reaper notices.","tags":["sandbox"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the sandbox to address, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.Sandbox"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sandbox","x-public":true,"x-tool":true}},"/v1/sandbox/{id}/ports":{"get":{"operationId":"get_sandbox_by_id_ports","summary":"Lists the TCP ports something listens on in a sandbox the caller holds, each with the preview host that serves it — what the sandbox's Browser can open.","description":"Lists the TCP ports something listens on in a sandbox the caller\nholds, each with the preview host that serves it — what the sandbox's Browser\ncan open. A dev server started in the sandbox appears here once it listens.","tags":["sandbox"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the sandbox, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.Ports"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sandbox","x-public":true,"x-tool":true}},"/v1/sandbox/{id}/preview":{"post":{"operationId":"post_sandbox_by_id_preview","summary":"Opens a port of a sandbox the caller holds in a browser.","description":"Opens a port of a sandbox the caller holds in a browser.\n\nIt answers a URL at an origin of the preview's own —\nhttps://sandbox-\u003cid\u003e-preview-\u003cport\u003e.\u003capex\u003e/ — carrying a single-use ticket.\nOpening it sets a cookie on that origin and lands on its root, and from then on\nevery request there is carried to the port inside the sandbox: pages, assets,\nAPIs and WebSockets, as the app serves them on localhost. The preview stays open\nfor twelve hours or until the sandbox stops running; a preview answering 401 is\nopened again by asking for another URL. A sandbox that is not running is 409.","tags":["sandbox"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the sandbox, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.previewIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.previewGrant"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sandbox","x-public":true,"x-tool":true}},"/v1/sandbox/{id}/resume":{"post":{"operationId":"post_sandbox_by_id_resume","summary":"Gives a parked sandbox a pod again: POST /v1/sandbox/:id/resume.","description":"Gives a parked sandbox a pod again: POST /v1/sandbox/:id/resume.\n\nThe pod is NEW and so is its lease: a fresh pod name, because a pod name is\nnever reused (store.go), the volume the row already names, a lease of the\nclass's own length from now, and the RESUMING caller's credential rather than\nthe one that took the lease — a session is short-lived and the one that parked\nit is gone.","tags":["sandbox"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the sandbox to address, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.Sandbox"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sandbox","x-public":true,"x-tool":true}},"/v1/sandbox/{id}/screen":{"get":{"operationId":"get_sandbox_by_id_screen","summary":"The screen, as a page","description":"A complete, self-contained desktop — noVNC inline, no other origin — that opens its own socket and draws this sandbox's display. Embed it in an iframe and there is nothing else to build.\n\n`ticket` is the credential from the POST above, carried through to the socket. The page is NOT gated: it is inert markup and does not redeem the ticket, because a ticket is spent once and a page that spent it would hold a credential that no longer opens anything. `frame-ancestors` admits our own brands' hosts and nothing further.\n\nIt is served for every class, not only for `desktop`. The class is a fact about the image, and a sandbox with no VNC server already fails exactly — the connection is refused and the page says so — where a check here would be a second opinion about what is running inside a pod, formed from a label rather than from the pod.","tags":["sandbox"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"sandbox","x-public":true}},"/v1/sandbox/{id}/screen/ticket":{"post":{"operationId":"post_sandbox_by_id_screen_ticket","summary":"Mints a short-lived grant to open the screen of a desktop sandbox.","description":"Mints a short-lived grant to open the screen of a desktop\nsandbox. Same properties as the terminal ticket, for the other endpoint.","tags":["sandbox"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the sandbox to address, from the path.","schema":{"type":"string"}}],"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.ticketGrant"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sandbox","x-public":true,"x-tool":true}},"/v1/sandbox/{id}/screen/ws":{"get":{"operationId":"get_sandbox_by_id_screen_ws","summary":"The screen, as a socket","description":"Upgrades to a WebSocket carrying RFB — the VNC wire protocol — from the sandbox's display, for a host that brings its own client. Requires `ticket`; a missing, expired or already-spent one answers 401 without upgrading.\n\nTHE WIRE IS RFB, in BINARY frames both ways, and it is not interpreted here: this is a pipe between the caller's client and the server inside the pod.\n\nTHE PIXELS COME OUT THROUGH THE EXEC CHANNEL. The display binds 127.0.0.1 only and deliberately nothing else, so there is no address to dial — `socat` joins the stream to that loopback port over the same Kubernetes exec subresource every other call into a sandbox uses. One way in, one thing to authorize, nothing further exposed.\n\nThe window size is ignored. A browser pane is not the X server's geometry, and the client scales what it is given rather than asking a server with no RandR to resize itself.","tags":["sandbox"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"sandbox","x-public":true}},"/v1/sandbox/{id}/terminal":{"get":{"operationId":"get_sandbox_by_id_terminal","summary":"The terminal, as a page","description":"A complete, self-contained terminal — xterm inline, no other origin — that opens its own socket and runs a shell in this sandbox. Embed it in an iframe and there is nothing else to build.\n\n`ticket` is the credential from the POST above and `arg` names the session (see the socket below); both are simply carried through to the socket. The page is NOT gated — it is inert markup and does not redeem the ticket, because a ticket is spent once and a page that spent it would hold a credential that no longer opens anything.\n\nWhen the terminal is up it posts `{source:\"hanzo-term\", ready:true}` to its parent frame, so a host can tell a live terminal from a page that failed into something else. `frame-ancestors` admits our own brands' hosts and nothing further.","tags":["sandbox"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"sandbox","x-public":true}},"/v1/sandbox/{id}/terminal/ticket":{"post":{"operationId":"post_sandbox_by_id_terminal_ticket","summary":"Mints a short-lived grant to open a terminal on a sandbox.","description":"Mints a short-lived grant to open a terminal on a sandbox.\n\nThe ticket travels in the query string of the URL it answers with, because a\nbrowser cannot set an Authorization header on a WebSocket handshake. It is\nsingle-purpose and short-lived for exactly that reason. A sandbox that is not\nrunning is 409 rather than a ticket that cannot be used.","tags":["sandbox"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the sandbox to address, from the path.","schema":{"type":"string"}}],"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sandbox.ticketGrant"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sandbox","x-public":true,"x-tool":true}},"/v1/sandbox/{id}/terminal/ws":{"get":{"operationId":"get_sandbox_by_id_terminal_ws","summary":"The terminal, as a socket","description":"Upgrades to a WebSocket carrying a login shell on a pseudo-terminal inside the sandbox — for a host that brings its own emulator. Requires `ticket`; a missing, expired or already-spent one answers 401 without upgrading.\n\nTHE WIRE. A text frame is stdin, unless it is the one control object `{\"resize\":{\"cols\":N,\"rows\":M}}`; a binary frame is always stdin. Output comes back as BINARY frames, because a pty emits arbitrary bytes cut at arbitrary offsets and a text frame carrying half a rune is one the browser closes the connection over.\n\n`arg` names a SESSION: the shell runs under `tmux new -A -s \u003carg\u003e`, which attaches to that session if it exists and creates it if it does not — so one sandbox holds as many terminals as a caller has names for. It is 1-64 characters of letters, digits, `-` or `_` and may not begin with `-`; anything else is 400. Without `arg` the shell is unnamed and unmultiplexed.\n\nThe shell is `zsh -l`, falling back to `bash -l` and then to `sh -l`, and to the plain shell again when the image has no tmux. Every step is a preference and none is a requirement: whatever else the image carries — the hanzo CLI included — is a command to type, never a condition for getting a prompt.","tags":["sandbox"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"sandbox","x-public":true}},"/v1/sbom/health":{"get":{"operationId":"get_sbom_health","summary":"Health is a pure liveness probe: the service is up; datastore reflects whether the datastore store is connected.","description":"Health is a pure liveness probe: the service is up; datastore reflects whether\nthe datastore store is connected. Not JWT-gated, always 200 (a disconnected\ndatastore is degraded-but-alive; the data endpoints report that as 503).","tags":["sbom"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sbom.SbomHealth"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sbom","x-public":true,"x-tool":true}},"/v1/search":{"post":{"operationId":"search","summary":"Hybrid search over the org's own corpora","description":"Is the typed op behind POST /v1/search. It does exactly two things the\nin-process entry point must not do: resolve the tenant from the validated\nprincipal, and refuse when there is none. Everything else is ForOrg.","tags":["search"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/search.Request"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/search.Fusion"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"search","x-public":true,"x-tool":true}},"/v1/security/findings":{"get":{"operationId":"get_security_findings","summary":"Is the org's findings — rule, severity, path, line, masked preview and fingerprint — newest first, across scans or within one.","description":"Is the org's findings — rule, severity, path, line, masked preview\nand fingerprint — newest first, across scans or within one.\n\nA minSeverity outside critical|high|medium|low is refused rather than quietly\nignored, so a filter typo cannot read as \"no findings\". Strictly org-scoped, and\na caller with no validated org is refused.","tags":["security"],"parameters":[{"name":"scanId","in":"query","required":false,"description":"ScanID narrows to a single scan.","schema":{"type":"string"}},{"name":"minSeverity","in":"query","required":false,"description":"MinSeverity drops everything below that rank: critical, high, medium or low.\nA value outside that set is refused rather than quietly ignored, so a filter\ntypo cannot read as \"no findings\".","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps the page.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/security.findingList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"security","x-public":true,"x-tool":true}},"/v1/security/findings/{id}":{"get":{"operationId":"get_security_findings_by_id","summary":"Returns a single finding: which rule fired, where (path and line), the masked preview and the SHA-256 fingerprint of the secret — the raw secret is not stored and cannot be read back.","description":"Returns a single finding: which rule fired, where (path and line),\nthe masked preview and the SHA-256 fingerprint of the secret — the raw secret is\nnot stored and cannot be read back.\n\nScoped to the caller's org, and a finding belonging to another org is the same\n404 as one that never existed.","tags":["security"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the finding the URL names.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/security.findingView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"security","x-public":true,"x-tool":true}},"/v1/security/health":{"get":{"operationId":"get_security_health","summary":"Reports that the scanning subsystem is serving and how many secret-detection rules the engine holds.","description":"Reports that the scanning subsystem is serving and how many\nsecret-detection rules the engine holds.\n\nIt has no external dependency — the answer is ok whenever the findings store\nopened — so it measures this process rather than anything downstream. It reads\nno tenant: a prober that sends no principal is answered, not refused.","tags":["security"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/security.ruleset"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"security","x-public":true,"x-tool":true}},"/v1/security/rules":{"get":{"operationId":"get_security_rules","summary":"Is the secret-detection catalog the engine scans with.","description":"Is the secret-detection catalog the engine scans with.\n\nIt returns every rule a scan can fire — the id, name and severity a finding\ncites — so a caller can render or triage results without hard-coding the\ncatalog. It is the same for everyone and discloses nothing tenant-specific, so\nit carries no org scope.","tags":["security"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/security.ruleList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"security","x-public":true,"x-tool":true}},"/v1/security/scans":{"get":{"operationId":"get_security_scans","summary":"Is the org's scan history, newest first, each as the same summary the submission answered — files read, findings fired, tally by severity.","description":"Is the org's scan history, newest first, each as the same summary the\nsubmission answered — files read, findings fired, tally by severity.\n\nStrictly org-scoped: a caller only ever sees its own scans, and one with no\nvalidated org is refused.","tags":["security"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit caps the page.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/security.scanList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"security","x-public":true,"x-tool":true},"post":{"operationId":"post_security_scans","summary":"Runs the detection engine over a batch of files and answers 201 with the scan summary: how many files were read, how many findings fired, and the tally by severity.","description":"Runs the detection engine over a batch of files and answers 201 with\nthe scan summary: how many files were read, how many findings fired, and the\ntally by severity.\n\nTHE SUBMITTED CONTENT IS NEVER STORED. It is scanned in memory; what persists is\nthe finding — its rule, its path and line, a MASKED preview (first and last\ncharacters kept, the middle starred) and the SHA-256 fingerprint of the raw\nsecret. The fingerprint is what makes the same secret recognisable across scans\nand after rotation without the secret ever being written down.\n\nIt requires a validated org, which scopes the stored scan and every finding on\nit; a caller with no org is refused. Bounded at 500 files and 8 MiB of total\ncontent per submission — split a larger tree across scans. One scan is one\nmetered unit, and the scan is recorded in the audit log with its tally, never\nwith its findings.","tags":["security"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/security.submitReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/security.scanView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"security","x-public":true,"x-tool":true}},"/v1/security/scans/{id}":{"get":{"operationId":"get_security_scans_by_id","summary":"Returns one scan together with every finding on it, so the detail view is one round-trip rather than a list call per scan.","description":"Returns one scan together with every finding on it, so the detail view\nis one round-trip rather than a list call per scan. The findings carry masked\npreviews and fingerprints, never secrets.\n\nScoped to the caller's org: a scan id belonging to another org is the same 404\nas an id that never existed, so a ruleset learns nothing about what exists\nelsewhere. No validated org is refused.","tags":["security"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the scan the URL names.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/security.scanDetail"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"security","x-public":true,"x-tool":true}},"/v1/seo/audit":{"post":{"operationId":"seoAudit","summary":"Fetch one page and report what it gets wrong","description":"Fetches one page and reports what it gets wrong.\n\nIt returns the page's on-page score, its title and description, how much readable\ntext it carries, and the full set of named checks — is it https, does it have one\nh1, is the title duplicated, is it slow, is it a redirect, is anything on it\nbroken. It is the technical half of search visibility, and it is the half a\ndeveloper can act on this afternoon.\n\nONE PAGE, LIVE, IN THIS REQUEST. It is deliberately not a site crawl: a crawl is\na job with a lifecycle, and this answers the same questions about the page\nsomebody is actually looking at, now, with no task id to poll. Point it at the\npages that matter one at a time.\n\nIt is priced per page fetched, which is one.","tags":["seo"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/seo.seoAuditIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/seo.seoAuditOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"seo","x-public":true,"x-tool":true}},"/v1/seo/backlinks":{"post":{"operationId":"seoBacklink","summary":"Who links to a target, and how much of it is broken or spam","description":"Summarises who links to a target.\n\nIt returns the authority score, how many links point at it and from how many\ndistinct sites, how many of those are broken, and how much of the profile reads\nas spam. Distinct sites is the number to read: a thousand links from one domain\nis one endorsement, and a profile that grew fast in links and not in domains is\nusually a profile somebody bought.\n\nThe target can be a whole domain, a subdomain, or one page URL — the summary is\nscoped to whatever is named. It is priced per request, so a domain with ten\nmillion links costs the same as one with ten.","tags":["seo"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/seo.seoBacklinkIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/seo.seoBacklinkOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"seo","x-public":true,"x-tool":true}},"/v1/seo/competitors":{"post":{"operationId":"seoCompetitor","summary":"The domains that place for the same phrases","description":"Names the domains that place for the same phrases.\n\nGiven a set of phrases it returns the sites that appear across them, with each\none's average position, how many of the phrases it places for, its share of the\navailable attention and the visits that earns. It answers \"who am I actually up\nagainst here\", which is a different question from \"who do I think my competitors\nare\" and frequently a different answer.\n\nPair it with seoRank: this says who is in the race, seoRank says where any one of\nthem finishes. It is priced per row, so Limit decides the cost.","tags":["seo"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/seo.seoCompetitorIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/seo.seoCompetitorOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"seo","x-public":true,"x-tool":true}},"/v1/seo/ideas":{"post":{"operationId":"seoIdea","summary":"Grow a seed phrase into the phrases nobody named yet","description":"Grows a seed phrase into the phrases nobody named yet.\n\nIt takes phrases you have and returns phrases in the same category that you do\nnot — relevant rather than merely containing the seed — each with its search\nvolume, click cost, competition and how hard its first page is to reach. This is\nwhere a keyword list comes FROM; seoKeyword is where a list you already have gets\nmeasured.\n\nIt is priced per row, so Limit is the knob that decides what the call costs.\nTotal says how many more there were.","tags":["seo"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/seo.seoIdeaIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/seo.seoIdeaOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"seo","x-public":true,"x-tool":true}},"/v1/seo/keywords":{"post":{"operationId":"seoKeyword","summary":"How often named phrases are searched, and what a click costs","description":"Measures phrases the caller already has.\n\nIt answers, for each phrase named, how many people search it in a month, what an\nadvertising click on it costs, and how contested that advertising is. This is the\nground fact of search: everything else on this surface is a question about\nphrases, and this is the one that says whether a phrase is worth having.\n\nGive it phrases you already suspect. To find phrases you have not thought of,\nuse seoIdea; to find the ones a site already places for, use seoRank.\n\nThe market defaults to the United States in English. It is priced per request\nrather than per phrase, so asking about fifty phrases costs what asking about\none does.","tags":["seo"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/seo.seoKeywordIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/seo.seoKeywordOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"seo","x-public":true,"x-tool":true}},"/v1/seo/rankings":{"post":{"operationId":"seoRank","summary":"Every phrase a domain already places for, with its position","description":"Reports every phrase a domain already places for.\n\nFor each one it gives the phrase, the position on the results page, the page of\nthe site that placed, that result's headline, the phrase's monthly searches and\nthe visits the placement is estimated to earn. It is the single most direct\nquestion about a site's search visibility — yours or a competitor's, since it\ntakes any domain.\n\nPosition is the ABSOLUTE rank, counting every element on the page — the ads, the\nanswer boxes, the map — because that is what a person scrolling actually passes.\nAn organic-only rank flatters a result that sits below half a screen of other\nthings.\n\nIt is priced per row, so Limit decides what the call costs, and Total says how\nmany more there were.","tags":["seo"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/seo.seoRankIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/seo.seoRankOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"seo","x-public":true,"x-tool":true}},"/v1/seo/rates":{"get":{"operationId":"seoRate","summary":"What each call on this surface costs, from the vendor's own list","description":"Publishes what every call on this surface costs.\n\nThe numbers are read from the upstream's own published price list, not from a\ntable kept here, so a price change on their side moves this card within the hour\nand moves what is debited with it. That is the whole of the pricing model: this\nsurface resells at cost, and the cost is theirs to state.\n\nA row has two numbers because a call has two costs: a flat charge for asking, and\na charge per row returned. An op priced per request reports zero for the second,\nand for one priced per row the total is `request + result x limit` — which is the\namount your balance is authorized against before the call, and roughly what you\nwill be debited after it.\n\nIt is a read and it is free: asking what something costs must not require the\nbalance that would pay for it. If the upstream cannot be reached the card comes\nback empty rather than stale — a price nobody can confirm is not a price.","tags":["seo"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/seo.seoRateOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"seo","x-public":true,"x-tool":true}},"/v1/settings/{product}":{"get":{"operationId":"get_settings_by_product","summary":"Reads the caller org's configuration for one product, with every secret field MASKED — only the names of the set secrets come back, never their values, which live in KMS.","description":"Reads the caller org's configuration for one product, with every\nsecret field MASKED — only the names of the set secrets come back, never their\nvalues, which live in KMS. A product the org has never configured is not a 404:\nit answers 200 with an empty config object, so the console's Settings tab always\nrenders and merges its own display defaults on top.","tags":["settings"],"parameters":[{"name":"product","in":"path","required":true,"description":"Product is the catalog slug, from the path. Must match ^[a-z0-9][a-z0-9._-]{0,62}$.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/settings.View"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"settings","x-public":true,"x-tool":true},"put":{"operationId":"put_settings_by_product","summary":"Writes the caller org's configuration for one product and answers the stored result, secrets masked.","description":"Writes the caller org's configuration for one product and answers the\nstored result, secrets masked. Secret VALUES are sealed into KMS under\norgs/{org}/settings/{product}/{key} and never touch this deployment's database;\nwith no KMS configured a write that carries any secret is refused whole (503)\nrather than dropping it or persisting it in the clear. A secret the body omits\nkeeps its stored value, so a partial write never silently clears one.","tags":["settings"],"parameters":[{"name":"product","in":"path","required":true,"description":"Product is the catalog slug, from the PATH. zip binds the path last, so the\nURL names the product being written whatever a body field claims.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/settings.settingsReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/settings.View"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"settings","x-public":true,"x-tool":true}},"/v1/share":{"get":{"operationId":"get_share","summary":"Returns the tunnel shares the caller's account currently has open — their org's, or in a held org their own — across every environment it has enabled.","description":"Returns the tunnel shares the caller's account currently has open —\ntheir org's, or in a held org their own — across every environment it has\nenabled. It is a READ and it degrades honestly: an\nunconfigured deployment, an org that has not provisioned yet, and an unreachable\ncontroller all answer an EMPTY list at 200 rather than an error, so the console\nnever error-toasts on load.","tags":["share"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/share.sharesOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"share","x-public":true,"x-tool":true}},"/v1/share/enable":{"post":{"operationId":"post_share_enable","summary":"Provisions the caller's tunnel account — their org's, or in a held org, where every self-serve signup lands, their own — and returns the credential the `hanzo share` CLI needs to run a tunnel.","description":"Provisions the caller's tunnel account — their org's, or in a held org,\nwhere every self-serve signup lands, their own — and returns the credential the\n`hanzo share` CLI needs to run a tunnel. It is idempotent: the account is keyed\ndeterministically off the VALIDATED org and, in a held org, the caller's\nattested subject, so a repeat call hands back the same account rather than\ncreating a second one, and a caller can only ever provision their OWN. 503 when\nthe deployment has no share controller configured; 502 when that controller is\nunreachable.","tags":["share"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/share.enableResp"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"share","x-public":true,"x-tool":true}},"/v1/share/rotate":{"post":{"operationId":"post_share_rotate","summary":"Replaces the credential of a tunnel account and ends every environment enabled with it, shares and all, so a credential handed out before — to a member who has left, or to anyone who read it — opens nothing from now on.","description":"Replaces the credential of a tunnel account and ends every\nenvironment enabled with it, shares and all, so a credential handed out before\n— to a member who has left, or to anyone who read it — opens nothing from now\non. The account is kept: enable hands its holder the new credential.\n\nIn a customer's org the account is the org's, which its members share, and an\nadmin of the org or a SuperAdmin rotates it. In a held org each person's\naccount is their own, and they rotate it — every account they hold, the one\nan API key of theirs was handed before included, so none stays live. An admin\nof the org or a SuperAdmin then rotates the org's own account, which no call\nthere hands out, whether or not they hold an account of their own; when that\none cannot be rotated, `pending` says so and their own are rotated still.\n\nAn account never provisioned has nothing to rotate and counts 0. 503 when the\ndeployment has no share controller configured; 502 when that controller is\nunreachable, or holds the caller's account under a credential this deployment\ndoes not derive — out of a rotation's reach, so it is refused rather than\nreported done.","tags":["share"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/share.rotated"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"share","x-public":true,"x-tool":true}},"/v1/social/accounts":{"get":{"operationId":"get_social_accounts","summary":"Returns the org's connected accounts — each one's id, network, handle, status and timestamps, most-recently-updated first.","description":"Returns the org's connected accounts — each one's id, network,\nhandle, status and timestamps, most-recently-updated first.\n\nAn account's provider access token is NEVER included in any response on this\nsurface. Only the publisher reads it.","tags":["social"],"parameters":[{"name":"provider","in":"query","required":false,"description":"Provider keeps only accounts on one network — x, facebook, instagram,\nlinkedin, tiktok, youtube or threads. Omit it for every network. It is\nlower-cased and trimmed before it is matched, and a value that names no\nnetwork simply matches nothing rather than being refused.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit bounds the page, defaulting to 200 and capped at 1000. It is a string\nrather than an integer on purpose: the route parses it with a leading trim\nand falls back to the default on anything it cannot read, so `?limit=%2050`\nis a page of fifty today. An integer field would refuse the space and read\nan unparseable value as zero, which is a different page.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/social.socialAccounts"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"social","x-public":true,"x-tool":true},"post":{"operationId":"post_social_accounts","summary":"Records a social account for the org and answers 201 with the stored row, including the generated id later calls address it by.","description":"Records a social account for the org and answers 201 with the\nstored row, including the generated id later calls address it by.","tags":["social"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/social.socialAccountBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/social.socialAccount"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"social","x-public":true,"x-tool":true}},"/v1/social/accounts/{id}":{"delete":{"operationId":"delete_social_accounts_by_id","summary":"Removes one connected account from the org and answers 204 with no body; an id that is not there is 404.","description":"Removes one connected account from the org and answers 204 with no\nbody; an id that is not there is 404.\n\nIt removes the account record only. Posts that already published through it keep\ntheir published state and their recorded external ids — this does not retract\nanything from the network.","tags":["social"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the account or post to act on, taken from the path.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"social","x-public":true,"x-tool":true},"get":{"operationId":"get_social_accounts_by_id","summary":"Returns one of the org's connected accounts by id — its network, handle, status and timestamps — or 404.","description":"Returns one of the org's connected accounts by id — its network,\nhandle, status and timestamps — or 404. The provider access token is not part of\nthe response.","tags":["social"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the account or post to act on, taken from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/social.socialAccount"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"social","x-public":true,"x-tool":true},"put":{"operationId":"put_social_accounts_by_id","summary":"Replaces the account's network, handle and status with what the body carries, and answers with the stored row.","description":"Replaces the account's network, handle and status with what the\nbody carries, and answers with the stored row.\n\nThis is a REPLACEMENT, not a merge, which is the rule most easily got wrong: a\nfield the body omits is written as its default, so leaving out the handle blanks\nit and leaving out the status resets it to connected. Send the whole record. The\nsame vocabularies as create apply, and an unknown network or status is refused\nrather than coerced.","tags":["social"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/social.socialAccountWrite"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/social.socialAccount"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"social","x-public":true,"x-tool":true}},"/v1/social/credentials":{"get":{"operationId":"get_social_credentials","summary":"Lists the apps this org has sealed.","description":"Lists the apps this org has sealed. The secret is not included.","tags":["social"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/social.orgApps"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"social","x-public":true,"x-tool":true},"put":{"operationId":"put_social_credentials","summary":"Seals the apps in the body.","description":"Seals the apps in the body. A network left out is unchanged.","tags":["social"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/social.orgAppsWrite"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/social.orgApps"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"social","x-public":true,"x-tool":true}},"/v1/social/posts":{"get":{"operationId":"get_social_posts","summary":"Returns the org's posts — content, channel, status, scheduled time, media and timestamps — most-recently-updated first.","description":"Returns the org's posts — content, channel, status, scheduled time,\nmedia and timestamps — most-recently-updated first.","tags":["social"],"parameters":[{"name":"status","in":"query","required":false,"description":"Status keeps only posts in one state — draft, scheduled, published or\nfailed. Omit it for every state. The transient publishing claim is not a\nuser-visible state and matching it is not useful.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit bounds the page, defaulting to 200 and capped at 1000. A string for\nthe same reason accountFilter.Limit is.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/social.socialPosts"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"social","x-public":true,"x-tool":true},"post":{"operationId":"post_social_posts","summary":"Stores a post for the org and answers 201 with the stored row.","description":"Stores a post for the org and answers 201 with the stored row.\n\nA post created as scheduled for a time that has already passed is published\nIMMEDIATELY, and the row returned carries that outcome — this is the one behaviour\na reader would otherwise miss. A future-scheduled post is left for the scheduler,\nand a draft is left alone. Publishing never fails the creation: the post is stored\neither way, and a publish that could not run leaves the row for the scheduler to\nretry.","tags":["social"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/social.socialPostBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/social.socialPost"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"social","x-public":true,"x-tool":true}},"/v1/social/posts/{id}":{"delete":{"operationId":"delete_social_posts_by_id","summary":"Removes one post from the org and answers 204 with no body; an id that is not there is 404.","description":"Removes one post from the org and answers 204 with no body; an id that\nis not there is 404.\n\nIt deletes the record here only. A post that has already published is not\nretracted from the network by deleting it.","tags":["social"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the account or post to act on, taken from the path.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"social","x-public":true,"x-tool":true},"get":{"operationId":"get_social_posts_by_id","summary":"Returns one of the org's posts by id, with its current status, scheduled time, media and — once it has published — the account and external id it published under.","description":"Returns one of the org's posts by id, with its current status, scheduled\ntime, media and — once it has published — the account and external id it published\nunder. 404 when there is no such post for this org.","tags":["social"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the account or post to act on, taken from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/social.socialPost"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"social","x-public":true,"x-tool":true},"put":{"operationId":"put_social_posts_by_id","summary":"Replaces the post's content, channel, status, scheduled time and media with what the body carries, and answers with the stored row.","description":"Replaces the post's content, channel, status, scheduled time and media\nwith what the body carries, and answers with the stored row.\n\nA REPLACEMENT, not a merge: an omitted field is written as its default, so\nomitting media clears it and omitting the status resets the post to draft.\n`content` is required on every update. Unlike create, this never triggers a\npublish — moving a post's scheduled time into the past here leaves it for the\nscheduler; publish now is its own operation.","tags":["social"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/social.socialPostWrite"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/social.socialPost"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"social","x-public":true,"x-tool":true}},"/v1/social/posts/{id}/publish":{"post":{"operationId":"post_social_posts_by_id_publish","summary":"Publishes the post immediately to the connected accounts on its channel and answers with the updated row, carrying the account and external id it published under.","description":"Publishes the post immediately to the connected accounts on its channel\nand answers with the updated row, carrying the account and external id it\npublished under.\n\nIt is IDEMPOTENT: a post that has already published, or that another caller is\npublishing right now, comes back unchanged rather than being posted twice. That\nclaim is taken before any network call, which is what makes a double submit safe.\n\nThe two failure shapes differ on purpose. Having no connected account for the\nchannel is the caller's to fix, so it is recorded ON the post as failed with the\nreason and answers normally. A deployment that lacks the network's own credentials\ncannot publish for anyone, so that is a 503 naming exactly what is missing.","tags":["social"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the account or post to act on, taken from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/social.socialPost"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"social","x-public":true,"x-tool":true}},"/v1/social/providers":{"get":{"operationId":"get_social_providers","summary":"Reports each supported network's publish-readiness: whether this deployment holds the OAuth application credentials for it and, when it does not, exactly which environment variables are missing.","description":"Reports each supported network's publish-readiness: whether this\ndeployment holds the OAuth application credentials for it and, when it does not,\nexactly which environment variables are missing.\n\nThis is a live read of the deployment's own configuration, not a static list of\nnetworks — it answers \"can I connect this today\", which is what a connect\naffordance and a pre-cutover checklist both need. It says nothing about whether\nthe caller has connected an account; that is the accounts listing.","tags":["social"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/social.socialProviders"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"social","x-public":true,"x-tool":true}},"/v1/social/summary":{"get":{"operationId":"get_social_summary","summary":"Returns four counts for the caller's org: total posts, how many are scheduled, how many have published, and how many accounts are connected.","description":"Returns four counts for the caller's org: total posts, how many are\nscheduled, how many have published, and how many accounts are connected. It is\nthe dashboard roll-up, computed over the org's own rows in one read.","tags":["social"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/social.socialSummary"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"social","x-public":true,"x-tool":true}},"/v1/space/health":{"get":{"operationId":"get_space_health","summary":"Reports whether this deployment can serve spaces, drives and files.","description":"Reports whether this deployment can serve spaces, drives and files.\n\nIt is a REAL probe rather than a constant: 200 when object-store credentials\nare present, so the store is reachable in principle, and 503 with the reason\nwhen they are not. It is deliberately NOT gated — liveness has to be probe-able\nwithout a token — so it is the one operation here that names no space and bills\nnothing.","tags":["space"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.spaceHealth"}}},"description":"ok"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.spaceHealth"}}},"description":"service unavailable"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"space","x-public":true,"x-tool":true}},"/v1/space/spaces":{"get":{"operationId":"get_space_spaces","summary":"Lists the caller org's own spaces.","description":"Lists the caller org's own spaces.\n\nOnly the caller's: every space is physically named under a per-org prefix and\nthe listing strips that prefix, so another org's spaces are not in the answer at\nall. Another org's space is not refused but INVISIBLE, so this cannot be used to\nlearn that a name is taken elsewhere.\n\nBilled per call: the balance is checked BEFORE anything is touched, so an\nunfunded org is refused with nothing done, and the debit lands only once the\nwork has succeeded.","tags":["space"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.spaceList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"space","x-public":true,"x-tool":true},"post":{"operationId":"post_space_spaces","summary":"Makes a new space for the caller's org and answers 201 with it.","description":"Makes a new space for the caller's org and answers 201 with it.\n\nThe one bucket a space's files live in is derived from the caller's VALIDATED\norg, so an org can only ever create inside its own namespace and no request\nfield can redirect that. A name already taken in the org is 409.\n\nBilled per call: the balance is checked BEFORE anything is touched, so an\nunfunded org is refused with nothing created, and the debit lands only once the\nspace exists.","tags":["space"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.spaceIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.spaceItem"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"space","x-public":true,"x-tool":true}},"/v1/space/{space}/drives":{"get":{"operationId":"get_space_by_space_drives","summary":"Lists a space's drives.","description":"Lists a space's drives.\n\nListing the drives IS listing the space's root folder, because a drive is the\nfirst segment of a key and nothing else — so the two can never disagree the way\na drives table and the keys under it would. A space the caller's org does not\nown is the same 404 an unknown name gives.\n\nBilled per call: the balance is checked BEFORE anything is touched, so an\nunfunded org is refused with nothing read, and the debit lands only once the\nlisting has succeeded.","tags":["space"],"parameters":[{"name":"space","in":"path","required":true,"description":"Space is the space's name, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.driveList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"space","x-public":true,"x-tool":true},"post":{"operationId":"post_space_by_space_drives","summary":"Makes a new drive in a space and answers 201 with it.","description":"Makes a new drive in a space and answers 201 with it.\n\nA drive is a PREFIX and not a bucket, so making one writes a zero-byte marker\nat \"\u003cname\u003e/\" — which is what makes an empty drive visible to a listing that has\nno other key to find. A name already taken in the space is 409.\n\nBilled per call: the balance is checked BEFORE anything is touched, so an\nunfunded org is refused with nothing created, and the debit lands only once the\ndrive exists.","tags":["space"],"parameters":[{"name":"space","in":"path","required":true,"description":"Space is the space to create the drive in, from the path. It carries NO\n`url:\"-\"`, unlike the field below it, and the difference is the whole reason\nboth tags are written out: zip's binder skips a field tagged \"-\" for EVERY\nURL source, path params included, so a path-borne value that carried it\nwould arrive empty and the create would refuse a perfectly good address.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.driveIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.driveItem"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"space","x-public":true,"x-tool":true}},"/v1/space/{space}/drives/{drive}":{"delete":{"operationId":"delete_space_by_space_drives_by_drive","summary":"Removes an EMPTY drive and answers 204.","description":"Removes an EMPTY drive and answers 204.\n\nA drive holding files is 409 rather than a cascade: deleting an org's files\nbehind a single drive call is not a thing this surface will do silently. A\ndrive or space the caller's org does not own is the same 404 an unknown name\ngives.\n\nBilled per call: the balance is checked BEFORE anything is touched, so an\nunfunded org is refused with nothing deleted, and the debit lands only once the\ndrive is gone.","tags":["space"],"parameters":[{"name":"space","in":"path","required":true,"description":"Space is the space's name, from the path.","schema":{"type":"string"}},{"name":"drive","in":"path","required":true,"description":"Drive is the drive's name, from the path.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"space","x-public":true,"x-tool":true}},"/v1/space/{space}/drives/{drive}/files":{"get":{"operationId":"get_space_by_space_drives_by_drive_files","summary":"Lists one folder level of a drive.","description":"Lists one folder level of a drive.\n\nFolder-style by default: sub-folders come back as folder entries, which is the\nfile-manager view. `?recursive=true` lists every file flat under the folder\ninstead. Names are RELATIVE to `?folder=`, and the listing is bounded so a huge\ndrive cannot exhaust memory — Total is what came back, not what the drive holds.\n\nBilled per call: the balance is checked BEFORE anything is touched, so an\nunfunded org is refused with nothing read, and the debit lands only once the\nlisting has succeeded.","tags":["space"],"parameters":[{"name":"space","in":"path","required":true,"description":"Space is the space to list in, from the path.","schema":{"type":"string"}},{"name":"drive","in":"path","required":true,"description":"Drive is the drive to list, from the path.","schema":{"type":"string"}},{"name":"folder","in":"query","required":false,"schema":{"type":"string"}},{"name":"recursive","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.fileList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"space","x-public":true,"x-tool":true}},"/v1/standing/upkeep":{"post":{"operationId":"post_standing_upkeep","summary":"Reports what keeping this entity costs every year, itemised.","description":"Reports what keeping this entity costs every year, itemised.\n\nThis is the figure that decides where to incorporate, and the one a formation\nprice cannot show: Delaware is cheaper to form than Wyoming for a corporation\nand dearer to keep, so a founder shown only the formation fee is shown the half\nthat reverses. Each state line carries the authority that publishes it and the\ndate it was checked, and a franchise tax that scales is marked a minimum rather\nthan quoted as final.","tags":["standing"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/standing.upkeepIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/standing.Upkeep"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"standing","x-public":true,"x-tool":true}},"/v1/studio/brands":{"get":{"operationId":"get_studio_brands","summary":"Lists the brands you may read — palettes and type systems as design tokens.","description":"Lists the brands you may read — palettes and type systems as design tokens.","tags":["studio"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit is how many rows one page holds, 1 to 100 (default 50).","schema":{"format":"int64","type":"integer"}},{"name":"cursor","in":"query","required":false,"description":"Cursor is the previous page's next.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.BrandPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true},"post":{"operationId":"post_studio_brands","summary":"Saves a brand: its tokens in the W3C design-token format (color, font, type, space, radius groups) and up to 16 logo items.","description":"Saves a brand: its tokens in the W3C design-token format (color, font, type,\nspace, radius groups) and up to 16 logo items. A run started with it reads the\ntokens as brand.*.","tags":["studio"],"requestBody":{"content":{"application/json":{"example":{"name":"Acme","tokens":{"color":{"primary":{"$type":"color","$value":"#ff5a1f"}}}},"schema":{"$ref":"#/components/schemas/studio.BrandWrite"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.Brand"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true}},"/v1/studio/brands/{id}":{"delete":{"operationId":"delete_studio_brands_by_id","summary":"Deletes one of your brands.","description":"Deletes one of your brands.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource's id, from the path.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true},"get":{"operationId":"get_studio_brands_by_id","summary":"Reads one brand you may read.","description":"Reads one brand you may read.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource's id, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.Brand"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true},"patch":{"operationId":"patch_studio_brands_by_id","summary":"Changes one of your brands; absent fields stay as they are.","description":"Changes one of your brands; absent fields stay as they are.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.BrandPatch"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.Brand"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true}},"/v1/studio/chat":{"post":{"operationId":"post_studio_chat","summary":"One chat turn that plans and launches runs, streamed","description":"Sends one message in a thread (a new thread when `thread` is absent). The assistant answers in text and, when the message asks for something to be made, plans it as runs and starts them; each is exactly the run POST /v1/studio/runs would start, checked and paid for the same way.\n\nAnswers text/event-stream: `thread` {thread} first; `delta` {text} as the answer is written; `run` {seq, run} for each run the turn started (follow it on its own events); `error` (a problem document) when a planned run could not start — a wallet that cannot cover it is status 402 — and the turn goes on; `done` {thread, message, runs} last, with the stored message. 402 before the stream when the wallet cannot pay for the turn itself.","tags":["studio"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatTurn"}}}},"responses":{"2XX":{"content":{"text/event-stream":{"schema":{"format":"binary","type":"string"}}},"description":"Success"}},"x-app":"studio","x-public":true}},"/v1/studio/documents":{"get":{"operationId":"get_studio_documents","summary":"Lists the documents and decks you may read, most recently changed first.","description":"Lists the documents and decks you may read, most recently changed first.","tags":["studio"],"parameters":[{"name":"kind","in":"query","required":false,"description":"Kind is doc or deck.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"format":"int64","type":"integer"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.DocumentPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true},"post":{"operationId":"post_studio_documents","summary":"Writes a document (kind doc, its IR blocks) or a deck (kind deck, its slides).","description":"Writes a document (kind doc, its IR blocks) or a deck (kind deck, its slides).\nRender it with a run: template document or slides, input.document its id.","tags":["studio"],"requestBody":{"content":{"application/json":{"example":{"ir":{"slides":[{"layout":"title","title":"Q3 review"}]},"kind":"deck","title":"Q3 review"},"schema":{"$ref":"#/components/schemas/studio.DocumentWrite"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.Document"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true}},"/v1/studio/documents/{id}":{"delete":{"operationId":"delete_studio_documents_by_id","summary":"Deletes one of your documents.","description":"Deletes one of your documents.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource's id, from the path.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true},"get":{"operationId":"get_studio_documents_by_id","summary":"Reads one document you may read.","description":"Reads one document you may read.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource's id, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.Document"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true},"patch":{"operationId":"patch_studio_documents_by_id","summary":"Changes one of your documents; absent fields stay as they are.","description":"Changes one of your documents; absent fields stay as they are.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.DocumentPatch"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.Document"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true}},"/v1/studio/estimate":{"post":{"operationId":"post_studio_estimate","summary":"Prices a run without starting it: the estimate POST /v1/studio/runs would reserve, step by step.","description":"Prices a run without starting it: the estimate POST /v1/studio/runs would\nreserve, step by step. Nothing is reserved and nothing runs.","tags":["studio"],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.RunCreate"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.Estimate"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true}},"/v1/studio/flows":{"get":{"operationId":"get_studio_flows","summary":"Lists the flows you may read, most recently changed first.","description":"Lists the flows you may read, most recently changed first.","tags":["studio"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit is how many rows one page holds, 1 to 100 (default 50).","schema":{"format":"int64","type":"integer"}},{"name":"cursor","in":"query","required":false,"description":"Cursor is the previous page's next.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.FlowPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true},"post":{"operationId":"post_studio_flows","summary":"Saves a graph as a flow of yours.","description":"Saves a graph as a flow of yours. Start it with POST /v1/studio/runs {\"flow\": id}.","tags":["studio"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.FlowWrite"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.Flow"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true}},"/v1/studio/flows/{id}":{"delete":{"operationId":"delete_studio_flows_by_id","summary":"Deletes one of your flows.","description":"Deletes one of your flows.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource's id, from the path.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true},"get":{"operationId":"get_studio_flows_by_id","summary":"Reads one flow you may read.","description":"Reads one flow you may read.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource's id, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.Flow"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true},"patch":{"operationId":"patch_studio_flows_by_id","summary":"Changes one of your flows; absent fields stay as they are.","description":"Changes one of your flows; absent fields stay as they are.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.FlowPatch"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.Flow"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true}},"/v1/studio/gpus":{"get":{"operationId":"get_studio_gpus","summary":"Lists the GPUs your org has linked with `hanzo link` that can take a studio.render step, each with whether it is free now.","description":"Lists the GPUs your org has linked with `hanzo link` that can take a\nstudio.render step, each with whether it is free now. With none online, a\nstudio.render step waits in the queue.","tags":["studio"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit is how many rows one page holds, 1 to 100 (default 50).","schema":{"format":"int64","type":"integer"}},{"name":"cursor","in":"query","required":false,"description":"Cursor is the previous page's next.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.GpuList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true}},"/v1/studio/runs":{"get":{"operationId":"get_studio_runs","summary":"Lists the runs you may read — your own and those your org shares — newest first.","description":"Lists the runs you may read — your own and those your org shares — newest\nfirst. Filter by kind or status.","tags":["studio"],"parameters":[{"name":"kind","in":"query","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Status keeps only runs at this status.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"format":"int64","type":"integer"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.RunPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true},"post":{"operationId":"post_studio_runs","summary":"Starts a run: name exactly one of template, flow or graph, with the input its inputs schema asks for.","description":"Starts a run: name exactly one of template, flow or graph, with the input its\ninputs schema asks for. The run is checked, priced and its estimate reserved\nagainst your org's wallet, then queued; the answer is the run at queued. Follow\nit on GET /v1/studio/runs/{id}/events.\n\nparent makes this run the next version of that run: it takes the parent's graph\nand input, overlaid by what this request states. Send Idempotency-Key to make a\nretried request start one run, not two. 402 when the wallet cannot cover the\nestimate; 422 when the graph or input does not validate.","tags":["studio"],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"input":{"prompt":"a lighthouse at dawn, risograph"},"template":"image"},"schema":{"$ref":"#/components/schemas/studio.RunCreate"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.Run"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true}},"/v1/studio/runs/{id}":{"get":{"operationId":"get_studio_runs_by_id","summary":"Reads one run: its graph, its input, every step's state, the assets it made and what it cost.","description":"Reads one run: its graph, its input, every step's state, the assets it made\nand what it cost. A run you may not read answers 404.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource's id, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.Run"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true},"patch":{"operationId":"patch_studio_runs_by_id","summary":"Renames or shares one of your runs.","description":"Renames or shares one of your runs. Sharing a run lets every member of your\norg read it; its files are Library items, shared from the Library.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.RunPatch"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.Run"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true}},"/v1/studio/runs/{id}/cancel":{"post":{"operationId":"post_studio_runs_by_id_cancel","summary":"Cancels one of your runs: a step in flight is told to stop, nothing new starts, and the reservation settles to what finished steps cost.","description":"Cancels one of your runs: a step in flight is told to stop, nothing new\nstarts, and the reservation settles to what finished steps cost. Cancelling a\nrun that already ended answers it unchanged.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource's id, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.Run"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true}},"/v1/studio/runs/{id}/events":{"get":{"operationId":"get_studio_runs_by_id_events","summary":"Stream a run's progress as Server-Sent Events","description":"Holds text/event-stream open on one run you may read and writes one frame per change until the run ends, then a final `done` frame, and closes. Every frame carries `id:`, the event's sequence number in the run, so a client that reconnects with Last-Event-ID (or ?after=) receives exactly what it missed. A run that already ended replays its events and closes.\n\nFrames (`event:` name, `data:` JSON): `run` {seq, run} on a status change; `step` {seq, run, step} when a step's status, attempt or progress moves; `asset` {seq, run, step, asset} when an output lands, as its Library item with fresh signed URLs; `log` {seq, run, step, text}; `done` {seq, run} when the run ended (succeeded, failed or canceled). Each carries the run, step or asset as it is now. A `: ping` comment every 15 seconds keeps intermediaries from closing the stream.\n\nAuthenticate with `Authorization: Bearer` (a fetch-based reader; a browser EventSource cannot set it) or the session cookie. 404 for a run you may not read; 429 when your org already holds 64 streams.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"2XX":{"content":{"text/event-stream":{"schema":{"format":"binary","type":"string"}}},"description":"Success"}},"x-app":"studio","x-public":true}},"/v1/studio/runs/{id}/retry":{"post":{"operationId":"post_studio_runs_by_id_retry","summary":"Resumes one of your runs that failed or was cancelled: the steps that did not succeed run again in the same run, and the steps that did keep their outputs and are neither run nor charged again.","description":"Resumes one of your runs that failed or was cancelled: the steps that did not\nsucceed run again in the same run, and the steps that did keep their outputs\nand are neither run nor charged again. What is left to run is reserved first\n(402 when it cannot be); 409 while the run is still going or once it succeeded.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource's id, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.Run"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true}},"/v1/studio/runs/{id}/versions":{"get":{"operationId":"get_studio_runs_by_id_versions","summary":"Lists every version of a creation you may read — the runs in this run's lineage — oldest (version 1) first.","description":"Lists every version of a creation you may read — the runs in this run's\nlineage — oldest (version 1) first.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource's id, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.RunPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true}},"/v1/studio/templates":{"get":{"operationId":"get_studio_templates","summary":"Lists templates: the public catalog (org empty) first, then your org's own that you may read.","description":"Lists templates: the public catalog (org empty) first, then your org's own\nthat you may read. Filter by kind. A cursor pages your org's templates.","tags":["studio"],"parameters":[{"name":"kind","in":"query","required":false,"description":"Kind keeps only templates that make this: image, poster, document, slides,\ntype, model, ad, video, film, voice, music or other.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"format":"int64","type":"integer"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.TemplatePage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true},"post":{"operationId":"post_studio_templates","summary":"Saves a template to your org: a graph and the inputs schema its runs are started with.","description":"Saves a template to your org: a graph and the inputs schema its runs are\nstarted with. It is yours until you share it.","tags":["studio"],"requestBody":{"content":{"application/json":{"example":{"graph":{"steps":[{"id":"html","op":"chat","with":{"prompt":"{{input.brief}}"}}]},"kind":"poster","title":"Event poster"},"schema":{"$ref":"#/components/schemas/studio.TemplateWrite"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.Template"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true}},"/v1/studio/templates/{id}":{"delete":{"operationId":"delete_studio_templates_by_id","summary":"Deletes one of your templates.","description":"Deletes one of your templates.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource's id, from the path.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true},"get":{"operationId":"get_studio_templates_by_id","summary":"Reads one template: a catalog slug or one of your org's templates you may read.","description":"Reads one template: a catalog slug or one of your org's templates you may read.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource's id, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.Template"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true},"patch":{"operationId":"patch_studio_templates_by_id","summary":"Changes one of your templates; absent fields stay as they are.","description":"Changes one of your templates; absent fields stay as they are. Catalog\ntemplates cannot be changed.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.TemplatePatch"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.Template"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true}},"/v1/studio/threads":{"get":{"operationId":"get_studio_threads","summary":"Lists your chat threads, most recent first.","description":"Lists your chat threads, most recent first.","tags":["studio"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit is how many rows one page holds, 1 to 100 (default 50).","schema":{"format":"int64","type":"integer"}},{"name":"cursor","in":"query","required":false,"description":"Cursor is the previous page's next.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.ThreadPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true}},"/v1/studio/threads/{id}":{"delete":{"operationId":"delete_studio_threads_by_id","summary":"Deletes one of your threads.","description":"Deletes one of your threads. Its runs and their files stay.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource's id, from the path.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true},"get":{"operationId":"get_studio_threads_by_id","summary":"Reads one of your threads and its messages, oldest first.","description":"Reads one of your threads and its messages, oldest first.","tags":["studio"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the resource's id, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/studio.Thread"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"studio","x-public":true,"x-tool":true}},"/v1/sync":{"get":{"operationId":"get_sync","summary":"Returns every sync link the caller's org has, each with its two endpoints, its direction and trigger policy, the time it last reconciled, and for a repo link its native copy on the forge — the address to clone it from, its default branch and whether it is in step.","description":"Returns every sync link the caller's org has, each with its two endpoints, its\ndirection and trigger policy, the time it last reconciled, and for a repo link its\nnative copy on the forge — the address to clone it from, its default branch and\nwhether it is in step. Scoped to the caller's own org — another tenant's links are\nstructurally unreachable.","tags":["sync"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sync.syncList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sync","x-public":true,"x-tool":true},"post":{"operationId":"post_sync","summary":"Declares a sync between two endpoints and returns it.","description":"Declares a sync between two endpoints and returns it. It is an UPSERT:\nre-declaring the same source and target updates that link rather than piling up\nduplicates, so a console that re-submits is safe. The org comes from the validated\nprincipal, never from the request, so a sync can only ever bind endpoints inside\nthe caller's own org. A git source must be an https clone URL on the provider's own\nhost with no embedded credentials; a target left empty is derived as a native\nrepository named after the source. A source naming only a GitHub account\n(https://github.com/\u003caccount\u003e) links the whole account: every repository the org's\nGitHub installation grants on it gets a repo link of its own, with this link's\ndirection and trigger, and so does every repository created there later. With run=true the first reconcile is queued in\nthe background, so a large initial import never blocks this response.","tags":["sync"],"requestBody":{"content":{"application/json":{"example":{"run":true,"source":{"locator":"https://github.com/acme/site","provider":"github"}},"schema":{"$ref":"#/components/schemas/sync.syncReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sync.syncView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sync","x-public":true,"x-tool":true}},"/v1/sync/{id}":{"delete":{"operationId":"delete_sync_by_id","summary":"Removes one sync and tears down the outbound mirror it derived, answering 204.","description":"Removes one sync and tears down the outbound mirror it derived, answering\n204. The teardown is the point: without it an unsynced repository would keep\nforce-pushing to the upstream it is no longer linked to. Org-scoped, so another\ntenant's id is the same 404 an unknown id gives.","tags":["sync"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the sync to act on, from the path.","schema":{"type":"string"},"example":"sync_1"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sync","x-public":true,"x-tool":true},"get":{"operationId":"get_sync_by_id","summary":"Returns one sync by id.","description":"Returns one sync by id. It is org-scoped: an id belonging to another tenant is\nthe same 404 an unknown id gives, so a probe learns nothing about what exists.","tags":["sync"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the sync to act on, from the path.","schema":{"type":"string"},"example":"sync_1"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sync.syncView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sync","x-public":true,"x-tool":true},"patch":{"operationId":"patch_sync_by_id","summary":"Updates one sync's mutable policy — direction, trigger and actor — in place.","description":"Updates one sync's mutable policy — direction, trigger and actor — in place.\nThe endpoints and the kind are immutable: re-pointing a sync is a delete and a\ncreate, so a link can never silently start syncing somewhere else. A field the\nrequest omits is left as it was. Changing the direction immediately reconciles the\nderived outbound mirror, so turning push off stops the upstream being written to\nrather than merely recording the intent.","tags":["sync"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the sync to update, from the path.","schema":{"type":"string"},"example":"sync_1"}],"requestBody":{"content":{"application/json":{"example":{"direction":"pull","id":"sync_1"},"schema":{"$ref":"#/components/schemas/sync.patchSyncIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sync.syncView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sync","x-public":true,"x-tool":true}},"/v1/sync/{id}/run":{"post":{"operationId":"post_sync_by_id_run","summary":"Reconciles one sync now — the manual re-sync, and the initial import for a link created without run=true.","description":"Reconciles one sync now — the manual re-sync, and the initial import for a link\ncreated without run=true. The work is handed to a bounded background worker and the\ncall answers 202 immediately, so a large mirror-in never holds the request open;\nqueued=true means accepted, not finished.","tags":["sync"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the sync to act on, from the path.","schema":{"type":"string"},"example":"sync_1"}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/sync.syncQueued"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"sync","x-public":true,"x-tool":true}},"/v1/task/board":{"get":{"operationId":"get_task_board","summary":"Returns a board's issues — work items with their column, priority, assignee, labels and schedule.","description":"Returns a board's issues — work items with their column, priority,\nassignee, labels and schedule.\n\nWHICH board is a filter, not an address. Bound to a repository (the key from\nthe path) it is that project's board; left unbound it is the org's whole\nboard; narrowed by label it is a board smaller than any repository — which is\nthe only way an app that lives as a directory inside a shared repository can\nhave one. Every combination is the same rows through the same projection, so\nno two boards can disagree about what a column means.\n\nThe column is a LABEL on the forge, so the board and the forge web UI are the\nsame object seen twice: relabelling in either moves the card in both. A closed\nissue reads as done whatever its labels say.","tags":["task"],"parameters":[{"name":"key","in":"query","required":false,"description":"Key is the project whose issues to list, from the path. EMPTY means every\nproject in the org — the global board. It is a filter like the rest of\nthis struct rather than an address, which is what lets one op answer both\n\"this board\" and \"all the work\" without a second surface disagreeing with\nthe first about what a column is.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Status keeps only issues in that board column: backlog, todo, in_progress,\ndone or canceled. An unknown value is refused with 400.","schema":{"type":"string"}},{"name":"kind","in":"query","required":false,"description":"Kind keeps only work items of that shape: issue, pr or epic. An unknown\nvalue is refused with 400.","schema":{"type":"string"}},{"name":"repo","in":"query","required":false,"description":"Repo keeps only issues bound to that git repository.","schema":{"type":"string"}},{"name":"label","in":"query","required":false,"description":"Label keeps only issues carrying that label, compared case-insensitively.\n\nThis is how a board narrows to something SMALLER than a repository — the\none mechanism for it. An estate whose apps are directories inside one\nrepository (hanzoai/cloud carries ~140 of them) has no repository per app\nto address, so the app is a label: `label=app/meet` is the meet board.\nNothing is provisioned to make one exist; a board is the query.","schema":{"type":"string"}},{"name":"source","in":"query","required":false,"description":"Source keeps only issues opened from that surface: team, git, crm,\nhelpdesk, cms or agent. An unknown value is refused with 400.","schema":{"type":"string"}},{"name":"scheduled","in":"query","required":false,"description":"Scheduled keeps only issues that carry a date — a start, a due date or\nboth. This is the timeline's slice of the board: pass scheduled=true to\nget exactly the rows a gantt has somewhere to draw, instead of fetching\nevery issue and discarding the undated ones client-side.","schema":{"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/task.issueView"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"task","x-public":true,"x-tool":true}},"/v1/task/issues":{"get":{"operationId":"get_task_issues","summary":"Answers across every project in the org.","description":"Answers across every project in the org.\n\nThe org comes from the validated principal and never from the request: a\ncaller able to name the org could read another tenant's backlog, and a search\nis exactly the shape that would quietly return it.","tags":["task"],"parameters":[{"name":"q","in":"query","required":false,"description":"Q matches an issue's title or description. A word from the issue, which is\nwhat someone remembers — not its number, which is what they are looking up.","schema":{"type":"string"}},{"name":"project","in":"query","required":false,"description":"Project narrows to one team key; \"\" searches every project in the org,\nwhich is the point of this op.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Status keeps one board column: backlog, todo, in_progress, done, canceled.","schema":{"type":"string"}},{"name":"kind","in":"query","required":false,"description":"Kind keeps one shape: issue, pr, epic.","schema":{"type":"string"}},{"name":"repo","in":"query","required":false,"description":"Repo keeps issues bound to one git repository.","schema":{"type":"string"}},{"name":"room","in":"query","required":false,"description":"Room keeps issues bound to one collaboration room, spelled\n\"\u003cspace\u003e_\u003croom\u003e\" — the exact value GET /v1/meet/call answers with, so a\nchannel's call and its task list name the room the same way. This is the\nread a channel view runs to draw its own list; it spans every board of the\norg, because the work a channel is about is not confined to one board.","schema":{"type":"string"}},{"name":"source","in":"query","required":false,"description":"Source keeps one origin: team, git, crm, helpdesk, cms, agent. \"git\" is\nhow you ask for the mirrored GitHub issues specifically.","schema":{"type":"string"}},{"name":"assignee","in":"query","required":false,"description":"Assignee keeps issues held by one person. Pass \"me\" for yourself.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps the answer; 0 means the default, and anything above the ceiling\nis clamped rather than refused — a search that errors on being too broad\nteaches people to guess.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/task.issueHits"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"task","x-public":true,"x-tool":true}},"/v1/task/projects":{"get":{"operationId":"get_task_projects","summary":"Returns the boards of your org — the places your work actually is.","description":"Returns the boards of your org — the places your work actually\nis. The key addresses the board's issues.\n\nA BOARD IS A PLACE WORK IS, not an object somebody provisioned. So the list is\nassembled from the work itself: the repositories your org has filed issues on,\nplus the boards the index holds. A repository with nothing on it is not in the\nlist and is still perfectly addressable — GET /projects/\u003cname\u003e reads it and a\ncreate files into it — so nothing is lost by leaving it out.\n\nMeasured, which is why: reading the forge's whole repository inventory put 745\nboards here, of which all but a handful were vendored forks and mirrors\n(.github, .profile, DOMPurify, BoatAttack) that will never carry this org's\nwork. A list that long is not a list — the estate's real roadmap was in it\nsomewhere and no one could see it.\n\nThe forge half is the FORGE's answer for your own account, so two people in\none org can legitimately see different boards.","tags":["task"],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/task.boardView"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"task","x-public":true,"x-tool":true},"post":{"operationId":"post_task_projects","summary":"Refused — a board is a repository on the forge","description":"Answers 405. A task board IS a repository on this deployment's forge, so creating, renaming and deleting one is a FORGE operation carried out with FORGE permissions.\n\nOffering it here would put a second endpoint on the same object, guarded by this surface instead of by the forge — a weaker guard on the same thing. So the route exists and refuses, rather than 404ing: \"not this service's job\" and \"no such thing\" are different facts, and the body names the forge so a caller knows where the job IS done.\n\nWhat this surface DOES own is the work on a board: list the boards you can see, read and file their issues, move a card between columns, and read the schedule a milestone is. Those are the routes beside this one.","tags":["task"],"x-app":"task","x-public":true}},"/v1/task/projects/{key}":{"delete":{"operationId":"delete_task_projects_by_key","summary":"Refused — a board is a repository on the forge","description":"Answers 405. A task board IS a repository on this deployment's forge, so creating, renaming and deleting one is a FORGE operation carried out with FORGE permissions.\n\nOffering it here would put a second endpoint on the same object, guarded by this surface instead of by the forge — a weaker guard on the same thing. So the route exists and refuses, rather than 404ing: \"not this service's job\" and \"no such thing\" are different facts, and the body names the forge so a caller knows where the job IS done.\n\nWhat this surface DOES own is the work on a board: list the boards you can see, read and file their issues, move a card between columns, and read the schedule a milestone is. Those are the routes beside this one.","tags":["task"],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"task","x-public":true},"get":{"operationId":"get_task_projects_by_key","summary":"Returns one board of your org by its key — the repository name.","description":"Returns one board of your org by its key — the repository name.\n404 when your org has no repository under that key, or when your own forge\naccount cannot see it.","tags":["task"],"parameters":[{"name":"key","in":"path","required":true,"description":"Key is the project's org-unique handle: 2-8 uppercase alphanumerics starting\nwith a letter (\"ENG\", \"OPS2\"). Matched case-insensitively.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/task.boardView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"task","x-public":true,"x-tool":true},"patch":{"operationId":"patch_task_projects_by_key","summary":"Refused — a board is a repository on the forge","description":"Answers 405. A task board IS a repository on this deployment's forge, so creating, renaming and deleting one is a FORGE operation carried out with FORGE permissions.\n\nOffering it here would put a second endpoint on the same object, guarded by this surface instead of by the forge — a weaker guard on the same thing. So the route exists and refuses, rather than 404ing: \"not this service's job\" and \"no such thing\" are different facts, and the body names the forge so a caller knows where the job IS done.\n\nWhat this surface DOES own is the work on a board: list the boards you can see, read and file their issues, move a card between columns, and read the schedule a milestone is. Those are the routes beside this one.","tags":["task"],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"task","x-public":true}},"/v1/task/projects/{key}/issues":{"get":{"operationId":"get_task_projects_by_key_issues","summary":"Returns a board's issues — work items with their column, priority, assignee, labels and schedule.","description":"Returns a board's issues — work items with their column, priority,\nassignee, labels and schedule.\n\nWHICH board is a filter, not an address. Bound to a repository (the key from\nthe path) it is that project's board; left unbound it is the org's whole\nboard; narrowed by label it is a board smaller than any repository — which is\nthe only way an app that lives as a directory inside a shared repository can\nhave one. Every combination is the same rows through the same projection, so\nno two boards can disagree about what a column means.\n\nThe column is a LABEL on the forge, so the board and the forge web UI are the\nsame object seen twice: relabelling in either moves the card in both. A closed\nissue reads as done whatever its labels say.","tags":["task"],"parameters":[{"name":"key","in":"path","required":true,"description":"Key is the project whose issues to list, from the path. EMPTY means every\nproject in the org — the global board. It is a filter like the rest of\nthis struct rather than an address, which is what lets one op answer both\n\"this board\" and \"all the work\" without a second surface disagreeing with\nthe first about what a column is.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Status keeps only issues in that board column: backlog, todo, in_progress,\ndone or canceled. An unknown value is refused with 400.","schema":{"type":"string"}},{"name":"kind","in":"query","required":false,"description":"Kind keeps only work items of that shape: issue, pr or epic. An unknown\nvalue is refused with 400.","schema":{"type":"string"}},{"name":"repo","in":"query","required":false,"description":"Repo keeps only issues bound to that git repository.","schema":{"type":"string"}},{"name":"label","in":"query","required":false,"description":"Label keeps only issues carrying that label, compared case-insensitively.\n\nThis is how a board narrows to something SMALLER than a repository — the\none mechanism for it. An estate whose apps are directories inside one\nrepository (hanzoai/cloud carries ~140 of them) has no repository per app\nto address, so the app is a label: `label=app/meet` is the meet board.\nNothing is provisioned to make one exist; a board is the query.","schema":{"type":"string"}},{"name":"source","in":"query","required":false,"description":"Source keeps only issues opened from that surface: team, git, crm,\nhelpdesk, cms or agent. An unknown value is refused with 400.","schema":{"type":"string"}},{"name":"scheduled","in":"query","required":false,"description":"Scheduled keeps only issues that carry a date — a start, a due date or\nboth. This is the timeline's slice of the board: pass scheduled=true to\nget exactly the rows a gantt has somewhere to draw, instead of fetching\nevery issue and discarding the undated ones client-side.","schema":{"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/task.issueView"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"task","x-public":true,"x-tool":true},"post":{"operationId":"post_task_projects_by_key_issues","summary":"Opens a work item on the board, filed as YOU, where the repository lives: an issue on the deployment's forge, or on GitHub for a repository the forge mirrors from there or does not hold at all.","description":"Opens a work item on the board, filed as YOU, where the\nrepository lives: an issue on the deployment's forge, or on GitHub for a\nrepository the forge mirrors from there or does not hold at all. Answers 201\nwith the card: its `number`, its `id`, and the issue's address as `url`. A\ncreate that cannot say what it made answers 502, never an empty 2xx.\n\nThe column and priority are written as LABELS, which is what makes the card\nand the issue the same object: someone relabelling in the web UI has moved\nyour card.\n\nAsked for in a chat thread, the issue is bound to that thread, and what\nhappens to it on GitHub is said there.","tags":["task"],"parameters":[{"name":"key","in":"path","required":true,"description":"Key is the board — the repository name, from the path. `owner/name`, or\n`github.com/owner/name`, names a repository on GitHub that no board on the\nforge stands for.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/task.newIssue"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/task.issueView"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"task","x-public":true,"x-tool":true}},"/v1/task/projects/{key}/issues/{num}":{"get":{"operationId":"get_task_projects_by_key_issues_by_num","summary":"Returns ONE work item in full — its description included.","description":"Returns ONE work item in full — its description included.\n\nThe list reads answer a board, and a board is a summary: the description is\nwhere the actual content of a work item lives — what an issue asks for, what\nan epic's acceptance criteria are — and no read on this surface returned it.\nThe address is the one PATCH already accepts, so an item you can move is now\nan item you can read.\n\nIt reads the forge directly rather than filtering the org fan-out, then falls\nback to the index for a board the forge has never heard of — the same order,\nand the same reason, as GetProject: a row is one kind of thing however it came\nto exist, so a caller does not have to know which store it is in to fetch it.","tags":["task"],"parameters":[{"name":"key","in":"path","required":true,"description":"Key is the board — the repository name, or an index board's key.","schema":{"type":"string"}},{"name":"num","in":"path","required":true,"description":"Num is the issue's number on that board.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/task.issueView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"task","x-public":true,"x-tool":true},"patch":{"operationId":"patch_task_projects_by_key_issues_by_num","summary":"Edits a work item — rename it, rewrite it, move it to another column, re-prioritise it, hand it to somebody, or comment on it.","description":"Edits a work item — rename it, rewrite it, move it to another\ncolumn, re-prioritise it, hand it to somebody, or comment on it. Absent fields\nare left alone. An issue on GitHub is edited there.\n\nMOVING A CARD IS A RELABEL. The column lives in the forge's label set, so the\nmove replaces that set rather than writing a status column here that a\nforge-side change could contradict. Moving to `done` also CLOSES the issue,\nbecause a done card and an open issue are a contradiction.\n\nAssigning it to `agent` hands it to the coding agent: see `assignee`.","tags":["task"],"parameters":[{"name":"key","in":"path","required":true,"description":"Key is the board — the repository name, from the path.","schema":{"type":"string"}},{"name":"num","in":"path","required":true,"description":"Num is the issue number on that repository, from the path.","schema":{"format":"int64","type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/task.issueEdit"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/task.issueView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"task","x-public":true,"x-tool":true}},"/v1/task/projects/{key}/issues/{num}/claim":{"post":{"operationId":"post_task_projects_by_key_issues_by_num_claim","summary":"Takes an issue: it becomes yours and it moves to in_progress.","description":"Takes an issue: it becomes yours and it moves to in_progress.\n\nThe holder is the CALLER, never an argument. \"Assign this to someone else\" is\na different act with different authority, and it already exists as a PATCH;\nconflating them would let anyone hand work to anyone by naming them.\n\nClaiming something already held by someone else is refused rather than\nsilently taken — two agents on one issue is the failure this prevents, and a\nclaim that quietly wins a race is worse than one that says no.","tags":["task"],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}},{"name":"num","in":"path","required":true,"schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/task.issueHit"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"task","x-public":true,"x-tool":true}},"/v1/task/projects/{key}/issues/{num}/comments":{"get":{"operationId":"get_task_projects_by_key_issues_by_num_comments","summary":"Is one issue's conversation, oldest first, read as the caller.","description":"Is one issue's conversation, oldest first, read as the caller.\nAn issue that lives on GitHub names its home and is read there.","tags":["task"],"parameters":[{"name":"key","in":"path","required":true,"description":"Key is the board — the repository name, or an index board's key.","schema":{"type":"string"},"example":"site"},{"name":"num","in":"path","required":true,"description":"Num is the issue's number on that board.","schema":{"format":"int64","type":"integer"},"example":1}],"responses":{"200":{"content":{"application/json":{"example":{"data":[{"author":"ann","body":"on it","createdAt":"2026-10-04T10:00:00Z","id":5}]},"schema":{"$ref":"#/components/schemas/task.commentList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"task","x-public":true,"x-tool":true}},"/v1/task/rooms/{room}":{"get":{"operationId":"get_task_rooms_by_room","summary":"Summarises one room's work.","description":"Summarises one room's work.\n\nThe room is opaque here and is deliberately not resolved: this package cannot\nsay whether a room exists — apps/team owns that document — so an unknown room\nanswers an EMPTY board rather than a 404. That is the honest answer and the\nuseful one: a channel that has never had an item filed in it and a channel id\nthat was mistyped both have no work, and inventing a distinction would require\nthis surface to hold a second copy of the room list (HIP-0523 §2 forbids it,\nand it would drift the first time a room was renamed).\n\nTenancy is the validated principal's org and nothing else, so a caller cannot\nread another tenant's channel by naming its room.","tags":["task"],"parameters":[{"name":"room","in":"path","required":true,"description":"Room is the room, spelled \"\u003cspace\u003e_\u003croom\u003e\" — the same value\nGET /v1/meet/call answers with, so a channel's call and its work name the\nroom identically. From the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/task.roomWork"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"task","x-public":true,"x-tool":true}},"/v1/tax/filings":{"get":{"operationId":"get_tax_filings","summary":"Lists the caller org's IRS return exports and where each stands, without their files.","description":"Lists the caller org's IRS return exports and where each stands, without their\nfiles. Org admins only.","tags":["tax"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.filingList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true},"post":{"operationId":"post_tax_filings","summary":"Exports the caller org's return for a tax year and form, as the files the IRIS Taxpayer Portal takes, and records the export.","description":"Exports the caller org's return for a tax year and form, as the files the IRIS\nTaxpayer Portal takes, and records the export. Org admins of the payer only: the\nfiles carry TINs in full, so a SuperAdmin acting inside the org is refused here\nexactly as at the TIN read.\n\nIt carries every furnished (or owed) form of that year and kind not already in\nan earlier export that IRIS did not reject — a rejected submission filed\nnothing, so its forms go out again as originals. Originals are in one set of\nfiles and corrections of forms already exported in another, at most 250 records\na file, each written to every rule Pub 5717 §3.5 sets and checked against them\nbefore it is answered. The files carry full TINs: the export is on the audit\ntrail and the files are not stored, only rebuilt from the sealed forms when read\nagain.\n\nIt DOES NOT FILE WITH THE IRS. Submitting through IRIS needs the payer's own\nTransmitter Control Code and a person at the portal; the answer lists those\nsteps, and POST /v1/tax/filings/{id}/receipt records what IRIS answered.","tags":["tax"],"requestBody":{"content":{"application/json":{"example":{"kind":"1099-NEC","year":2026},"schema":{"$ref":"#/components/schemas/tax.exportIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.Filing"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/filings/{id}":{"get":{"operationId":"get_tax_filings_by_id","summary":"Reads one IRS return export WITH its files, rebuilt from the sealed forms and proven identical to what was exported.","description":"Reads one IRS return export WITH its files, rebuilt from the sealed forms and\nproven identical to what was exported. The files carry full TINs: org admins of\nthe payer only — a SuperAdmin is refused — and every read is on the audit trail.","tags":["tax"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the filing id, \"iris_\"-prefixed.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.Filing"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/filings/{id}/receipt":{"post":{"operationId":"post_tax_filings_by_id_receipt","summary":"Records what IRIS answered for an exported return — the Receipt ID on submission, then the acknowledgment.","description":"Records what IRIS answered for an exported return — the Receipt ID on\nsubmission, then the acknowledgment. Org admins only.\n\nThis is the payer's report of its own act at the IRIS portal, made under its\nown Transmitter Control Code; nothing here reaches IRIS, and a status is only\never what the payer recorded. Moves: exported → submitted (with the Receipt ID\nand TCC) → accepted, accepted_with_errors or rejected.","tags":["tax"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the filing, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"receiptId":"2026-12345678901-abc123def","status":"submitted","tcc":"D1234"},"schema":{"$ref":"#/components/schemas/tax.receiptIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.Filing"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/forms":{"get":{"operationId":"get_tax_forms","summary":"Lists the 1099s the caller org prepared as payer, oldest first, voided and superseded ones included — a return that was furnished stays on the record.","description":"Lists the 1099s the caller org prepared as payer, oldest first, voided and\nsuperseded ones included — a return that was furnished stays on the record.\nOrg admins only.","tags":["tax"],"parameters":[{"name":"year","in":"query","required":false,"description":"Year narrows the list to one tax year; absent lists every year.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.formList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true},"post":{"operationId":"post_tax_forms","summary":"Prepares the caller org's 1099 drafts for a tax year, as the PAYER: one 1099-NEC and/or 1099-MISC per payee whose reportable payments on Hanzo's rails reach the year's threshold, from the same derivation GET /v1/tax/payments answers.","description":"Prepares the caller org's 1099 drafts for a tax year, as the PAYER: one\n1099-NEC and/or 1099-MISC per payee whose reportable payments on Hanzo's rails\nreach the year's threshold, from the same derivation GET /v1/tax/payments\nanswers. Org admins only.\n\nEach draft carries the payee as its W-9 names it — under a live grant, and\notherwise only its org id — its boxes, box 4, the due dates, the payments it\nsums, and backup withholding at 24% when the payer holds no TIN for the payee\n(IRC §3406(a)(1)(A)) — an uncertified W-9 is stated as a warning, not a\nwithholding, because these payments do not require the certification. Preparing\nagain refreshes a draft or reviewed form in place (a reviewed one goes back to\ndraft, to be reviewed again); one payee has at most one live form per kind and\nyear, so a second preparation racing the first is refused, never doubled. A form\nalready furnished is left alone and named in skipped — change it by correcting\nit. Nothing is furnished to anyone and nothing is filed with the IRS.","tags":["tax"],"requestBody":{"content":{"application/json":{"example":{"year":2026},"schema":{"$ref":"#/components/schemas/tax.prepareIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.Prepared"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/forms/{id}":{"get":{"operationId":"get_tax_forms_by_id","summary":"Reads one 1099 the caller org prepared as payer, every box and both parties, TINs masked.","description":"Reads one 1099 the caller org prepared as payer, every box and both parties,\nTINs masked. Org admins only; another org's form is not found.","tags":["tax"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the form id, \"f1099_\"-prefixed.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.Form"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/forms/{id}/correct":{"post":{"operationId":"post_tax_forms_by_id_correct","summary":"Corrects a furnished (or owed) 1099 with a NEW form that supersedes it.","description":"Corrects a furnished (or owed) 1099 with a NEW form that supersedes it. Org\nadmins only.\n\nThe furnished form is never changed: the correction is a second form, marked\nCORRECTED, carrying the original's account number and naming the form it\nsupersedes, and it goes through review and furnishing like any other. State the\ncorrected boxes, or omit them to derive the year again from the payments and the\npayee's current W-9. A form already superseded is corrected by correcting its\nsuccessor. It files nothing with the IRS.","tags":["tax"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the furnished form to correct, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"boxes":[{"box":"1a","cents":250000}],"reason":"a December settlement was refunded"},"schema":{"$ref":"#/components/schemas/tax.correctIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.Form"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/forms/{id}/furnish":{"post":{"operationId":"post_tax_forms_by_id_furnish","summary":"Furnishes Copy B of a reviewed 1099 to its payee.","description":"Furnishes Copy B of a reviewed 1099 to its payee. Org admins only.\n\nWhen the payee's tax profile consents to electronic delivery, Copy B is\ndelivered into the payee's /v1/tax/inbox and the form is furnished. Otherwise it\nis OWED on paper at the payee's address: mailing it is the payer's, and\nPOST /v1/tax/forms/{id}/mailed records it. Either way the statement is final\nfrom this call — the form can no longer change, only be corrected. Calling it\nagain on a form furnished electronically re-delivers Copy B if the inbox lacks\nit, and changes nothing else.\n\nIt does not file anything with the IRS, and it does not send the notice of\nposting Pub 1099 Part M asks a furnisher to give an electronic recipient; the\nstatement is in the recipient's inbox, and telling them so is the payer's.","tags":["tax"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the form id, \"f1099_\"-prefixed.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.Form"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/forms/{id}/mailed":{"post":{"operationId":"post_tax_forms_by_id_mailed","summary":"Records that the payer mailed a paper Copy B it owed.","description":"Records that the payer mailed a paper Copy B it owed. Org admins only.\n\nMailing is the payer's act, done outside Hanzo; this is the record of it, made\nby the person who did it and kept on the audit trail. Nothing here mails\nanything.","tags":["tax"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the form id, \"f1099_\"-prefixed.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.Form"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/forms/{id}/pdf":{"get":{"operationId":"get_tax_forms_by_id_pdf","summary":"Download a 1099 the org prepared, as a PDF","description":"Answers one 1099 the caller org prepared as payer as a one-page PDF — `application/pdf` under a Content-Disposition naming the form — rendered from the form's own content: the payer's copy by default, or Copy B (For Recipient) with `?copy=B` for a statement owed on paper. The recipient's TIN is truncated; the payer's prints in full, as the law requires on every form.\n\nThe render is a pure function of the form, so the same form renders the same bytes every time. Org admins only; another org's form is not found. It files nothing and mails nothing.","tags":["tax"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"tax","x-public":true}},"/v1/tax/forms/{id}/review":{"post":{"operationId":"post_tax_forms_by_id_review","summary":"Marks a draft 1099 reviewed — a person has checked it.","description":"Marks a draft 1099 reviewed — a person has checked it. Only a reviewed form can\nbe furnished. Org admins only.","tags":["tax"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the form id, \"f1099_\"-prefixed.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.Form"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/forms/{id}/void":{"post":{"operationId":"post_tax_forms_by_id_void","summary":"Voids a draft or reviewed 1099, which is then never furnished or filed.","description":"Voids a draft or reviewed 1099, which is then never furnished or filed. A form\nalready furnished cannot be voided: it is corrected, and a correction to zero\nis how a furnished return is withdrawn (Pub 1099 Part H). Org admins only.","tags":["tax"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the form id, \"f1099_\"-prefixed.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.Form"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/inbox":{"get":{"operationId":"get_tax_inbox","summary":"Lists the Copy B statements furnished to the caller org — every 1099 a payer on Hanzo delivered to it electronically, corrected ones beside the ones they supersede.","description":"Lists the Copy B statements furnished to the caller org — every 1099 a payer on\nHanzo delivered to it electronically, corrected ones beside the ones they\nsupersede. Any member may read it; nothing here can be changed or removed.","tags":["tax"],"parameters":[{"name":"year","in":"query","required":false,"description":"Year narrows the list to one tax year; absent lists every year.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.statementList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/inbox/{id}":{"get":{"operationId":"get_tax_inbox_by_id","summary":"Reads one Copy B furnished to the caller org.","description":"Reads one Copy B furnished to the caller org. Any member may read it; another\norg's statement is not found.","tags":["tax"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the form id, \"f1099_\"-prefixed.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.Statement"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/inbox/{id}/pdf":{"get":{"operationId":"get_tax_inbox_by_id_pdf","summary":"Download a Copy B furnished to the org, as a PDF","description":"Answers one Copy B furnished to the caller org as a one-page PDF — `application/pdf` under a Content-Disposition naming the form — rendered from the statement exactly as it was furnished, which can never change. The recipient's own TIN is truncated; the payer's prints in full.\n\nAny member of the recipient org may download it; another org's statement is not found.","tags":["tax"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"tax","x-public":true}},"/v1/tax/payments":{"get":{"operationId":"get_tax_payments","summary":"Returns the caller org's tax year as a PAYER: every payment it made to another org in that calendar year, on any rail, as the event plane records it, each classified — reportable or not, in which 1099 box, and the rule that decided it, with its source — and each payee's totals tested against the year's threshold.","description":"Returns the caller org's tax year as a PAYER: every payment it made to another\norg in that calendar year, on any rail, as the event plane records it, each\nclassified — reportable or not, in which 1099 box, and the rule that decided it,\nwith its source — and each payee's totals tested against the year's threshold.\n\nThe rules applied: a payment settled by a card or a third-party settlement\nnetwork is reported on Form 1099-K by the settlement entity, not here; a payment\nfor merchandise is not reported; a payment to a corporation is generally not\nreported, except for legal services; a payment in a digital asset is reported at\nits fair market value on the date paid; a box is reported only at or above the\nyear's threshold — $600 through 2025, $2,000 for 2026 under P.L. 119-21, and not\nguessed for a year the IRS has not yet published. A payee's classification comes\nonly from a W-9 it granted the caller; without one, nothing establishes an\nexemption.\n\nOrg admins only. It reads; it prepares nothing and files nothing.","tags":["tax"],"parameters":[{"name":"year","in":"query","required":false,"description":"Year is the calendar year the payments were made in, e.g. 2026.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.Ledger"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/profile":{"get":{"operationId":"get_tax_profile","summary":"Returns the caller org's own tax profile — every line of its Form W-9, W-8BEN or W-8BEN-E, every number masked to its last four characters, where the certification stands, whether a W-8 is valid and when it expires, and whether the org consents to receive its 1099s electronically.","description":"Returns the caller org's own tax profile — every line of its Form W-9, W-8BEN or\nW-8BEN-E, every number masked to its last four characters, where the\ncertification stands, whether a W-8 is valid and when it expires, and whether\nthe org consents to receive its 1099s electronically.\n\nAny member may read it. 404 until an admin writes one. No full number is ever in\nthis answer.","tags":["tax"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.Profile"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true},"put":{"operationId":"put_tax_profile","summary":"Writes the caller org's tax profile — its Form W-9, or its Form W-8BEN or W-8BEN-E when it is a foreign person — and answers it, every number masked.","description":"Writes the caller org's tax profile — its Form W-9, or its Form W-8BEN or\nW-8BEN-E when it is a foreign person — and answers it, every number masked. Org\nadmins only.\n\nA U.S. TIN is validated before it is kept — nine digits; an EIN's prefix must be\none the IRS assigns; an SSN never begins 000, 666 or 9xx and has no zero group\nor serial; an ITIN's middle digits are in the IRS ranges. A foreign TIN is the\nissuing jurisdiction's and is checked only for its characters. Every number is\nsealed under this org's own data key before it is written. Validating the\nFORMAT is all this does: whether the IRS has the number on file under this name\nis IRS TIN Matching, which a payer runs through IRS e-Services.\n\nA W-8 is refused where the form itself says it is the wrong one: a U.S. citizen,\na U.S. permanent residence or an entity organized in the United States is a U.S.\nperson and files a W-9. A treaty claim needs a U.S. or foreign TIN on the form\n(Instructions for Form W-8BEN, line 5; for Form W-8BEN-E, line 8), and names the\ncountry of the permanent residence address.\n\nChanging any fact on the form makes a new version, and the certification no\nlonger covers it: certify again. For a W-8 that is the \"change in circumstances\"\nthe instructions end its validity on. Changing only the consent does not.","tags":["tax"],"requestBody":{"content":{"application/json":{"example":{"address":{"city":"San Francisco","line1":"1 Market St","state":"CA","zip":"94105"},"classification":"c_corp","electronicConsent":true,"name":"Acme Robotics, Inc.","tin":"12-3456789","tinType":"ein"},"schema":{"$ref":"#/components/schemas/tax.profileIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.Profile"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/profile/certify":{"post":{"operationId":"post_tax_profile_certify","summary":"Signs the caller org's certification — Form W-9 Part II, Form W-8BEN Part III or Form W-8BEN-E Part XXX — through /v1/legal's e-signature.","description":"Signs the caller org's certification — Form W-9 Part II, Form W-8BEN Part III or\nForm W-8BEN-E Part XXX — through /v1/legal's e-signature. The org's own admins\nonly, and the admin is the signer: a SuperAdmin acting inside the org is not a\nperson who can certify for it.\n\nThe first call renders the certification — the IRS's own certification text over\nthis profile's facts, every number truncated — as a /v1/legal document and opens\nits signature request with the calling admin as signer; the answer is `pending` with\nthe document id. The signer completes it where every /v1/legal signature is\ncompleted (POST /v1/legal/documents/{id}/sign/complete). Calling this again then\nasks legal whether the document is signed and by whom: signed by the signer, the\nprofile is recorded certified; not yet signed, it answers `pending` again; signed\nby anyone else — another member, a key — or voided, it is not the signer's\ncertification, and a fresh request is opened in its place.\n\nA certification covers one profile version: writing any fact on the form\nafterwards voids it. A certified W-8 is valid through the last day of the third\ncalendar year after the year it was signed (Instructions for Form W-8BEN and\nW-8BEN-E, Rev. 10-2021); certifying it again after that renews it. It is not a\nstatement that a TIN matches IRS records — that is IRS TIN Matching, which only\na payer enrolled in IRS e-Services can run.","tags":["tax"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.Profile"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/w9":{"get":{"operationId":"get_tax_w9","summary":"Lists the caller org's W-9 relationships on both sides: the W-9s it asked its payees for, with where each stands, and the requests other orgs made for its own W-9.","description":"Lists the caller org's W-9 relationships on both sides: the W-9s it asked its\npayees for, with where each stands, and the requests other orgs made for its\nown W-9. Org admins only. No W-9 content is in the list; read one to see it.","tags":["tax"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.w9List"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true},"post":{"operationId":"post_tax_w9","summary":"Asks another org for its W-9, as the org that pays it.","description":"Asks another org for its W-9, as the org that pays it. Org admins only.\n\nA request is refused unless the caller has paid that org on Hanzo's rails, or\nhas asked /v1/principal whether it may — a W-9 is asked for by a payer, of a payee,\nand the payments, or a payment the caller is about to make, are what say which\ncompanies those are. The form is needed BEFORE the first payment: withholding\nis decided when a payment is made, not when it is reported. The request lands with the payee, whose admin grants or\ndeclines it; until it is granted the caller sees its status and nothing of the\npayee's W-9. Asking again updates the category, and re-opens a request the\npayee declined or revoked.\n\nCategory is the caller's statement of what it pays this payee for, and decides\nthe 1099 box: services and attorney go to 1099-NEC box 1a, rents, royalties\nand other to 1099-MISC boxes 1, 2 and 3; merchandise is not reported.","tags":["tax"],"requestBody":{"content":{"application/json":{"example":{"category":"services","payee":"acme"},"schema":{"$ref":"#/components/schemas/tax.w9Request"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.W9"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/w9/{id}":{"get":{"operationId":"get_tax_w9_by_id","summary":"Reads one W-9 relationship from the caller's side.","description":"Reads one W-9 relationship from the caller's side. Org admins only.\n\nAs the PAYER, the answer carries the payee's W-9 — every line, the TIN masked\nto its last four digits, and whether it is certified — but only while the\npayee's grant is live; before it is granted, and after it is declined or\nrevoked, there is no W-9 in the answer. As the PAYEE, it is the request and\nwhere it stands.","tags":["tax"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the relationship's id, \"w9_\"-prefixed.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.W9"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/w9/{id}/decline":{"post":{"operationId":"post_tax_w9_by_id_decline","summary":"Declines a request for this org's W-9.","description":"Declines a request for this org's W-9. The payer keeps seeing only the status.\nOrg admins of the payee only.","tags":["tax"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the relationship's id, \"w9_\"-prefixed.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.W9"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/w9/{id}/grant":{"post":{"operationId":"post_tax_w9_by_id_grant","summary":"Grants the payer that asked a live read of this org's W-9 — every line, the TIN masked, and the full TIN to that payer's org admins alone, each read audited.","description":"Grants the payer that asked a live read of this org's W-9 — every line, the TIN\nmasked, and the full TIN to that payer's org admins alone, each read audited.\nOrg admins of the payee only. Needs a tax profile to grant.","tags":["tax"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the relationship's id, \"w9_\"-prefixed.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.W9"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/w9/{id}/match":{"post":{"operationId":"post_tax_w9_by_id_match","summary":"Records the result of IRS TIN Matching for a payee, as the payer.","description":"Records the result of IRS TIN Matching for a payee, as the payer. Org admins of\nthe payer only, on a live grant.\n\nIt does not run TIN Matching. That is an IRS e-Services program a payer enrolls\nin and runs itself, on the name and TIN it holds; this records what the IRS\nanswered so it sits beside the W-9 and on the audit trail. Nothing here ever\nrecords a match the payer did not report.","tags":["tax"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the relationship, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"result":"matched"},"schema":{"$ref":"#/components/schemas/tax.matchIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.W9"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/w9/{id}/revoke":{"post":{"operationId":"post_tax_w9_by_id_revoke","summary":"Revokes a W-9 this org granted.","description":"Revokes a W-9 this org granted. From the moment it is revoked the payer reads\nnothing of the W-9 and no full TIN. A 1099 the payer already prepared keeps the\nTIN it was prepared with — the payer must keep it to file — and that TIN is\nnever answered in full outside the payer's IRS filing export. Org admins of the\npayee only.","tags":["tax"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the relationship's id, \"w9_\"-prefixed.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.W9"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/tax/w9/{id}/tin":{"get":{"operationId":"get_tax_w9_by_id_tin","summary":"Reads a payee's TIN in full — and, for a payee on a W-8, its foreign TIN, which the payer's Form 1042-S carries.","description":"Reads a payee's TIN in full — and, for a payee on a W-8, its foreign TIN, which\nthe payer's Form 1042-S carries. Only an org admin of the PAYER, only while the\npayee's grant is live, and every read is on the audit trail before a number is\nanswered — a read the trail cannot record is refused.\n\nThis is the one place a TIN leaves the platform in full, apart from the IRS\nfiling export. SuperAdmin is not admitted: platform authority is not a reason\nto read a company's TIN.","tags":["tax"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the relationship's id, \"w9_\"-prefixed.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tax.tinOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tax","x-public":true,"x-tool":true}},"/v1/taxonomy":{"get":{"operationId":"get_taxonomy","summary":"Returns the product catalogue as this caller sees it: the PLATFORM catalogue — Hanzo's own products, the part that is true for everyone — plus the caller's own org's rows, every category in display order and each carrying the products filed under it in theirs.","description":"Returns the product catalogue as this caller sees it: the PLATFORM\ncatalogue — Hanzo's own products, the part that is true for everyone — plus the\ncaller's own org's rows, every category in display order and each carrying the\nproducts filed under it in theirs. Another customer's rows are never in it. It\nis readable signed out, and a signed-out visitor gets the platform catalogue\nalone, which is what the marketing landing renders from.\n\nWhere the caller's org and the platform hold the same id, the caller's own row\nis the one served. That rule exists because ids are unique per ORG and not\nglobally — two customers may each have a \"crm\", and refusing the second would\ntell one of them the other exists — so a collision with the platform is possible\nby construction and something has to win deterministically. Yours does: your own\ncatalogue is the one you edited.\n\n`?brand=` narrows it the way a brand's own console does: only the categories\nthat brand admits, and within them only the taxa scoped to it. An unpublished\nrow is served only to whoever may edit it — a SuperAdmin for the platform's, an\norg admin for their own — so a product can be staged before anyone sees it\nwithout becoming invisible to the person staging it.","tags":["taxonomy"],"parameters":[{"name":"brand","in":"query","required":false,"description":"Brand returns only what that brand's console shows — the categories it\nadmits, and within them the taxa scoped to it. Empty returns everything.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/taxonomy.Taxonomy"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"taxonomy","x-public":true,"x-tool":true}},"/v1/taxonomy/categories/{id}":{"delete":{"operationId":"delete_taxonomy_categories_by_id","summary":"Removes one empty category.","description":"Removes one empty category. A category that still has taxa\nfiled under it is refused with 409 and a count: deleting the label off a group\nmust never silently take the products wearing it, and the alternative — orphan\nrows naming a category that no longer exists — is a catalogue that cannot be\nrendered. Move or delete its taxa first. An id no category holds is a 404.","tags":["taxonomy"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the slug to act on, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/taxonomy.deleted"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"taxonomy","x-public":true,"x-tool":true},"put":{"operationId":"put_taxonomy_categories_by_id","summary":"Creates or replaces one category and returns it as stored.","description":"Creates or replaces one category and returns it as stored. The id in\nthe URL is the one it is filed under whatever the body says, so a category can\nnever be written under a name it was not addressed by — which also makes create\nand replace the same act, and is why there is no POST beside this.\n\nPlatform SuperAdmin only: one catalogue serves every tenant, so an org admin who\ncould rename a category would rename it for all of them.","tags":["taxonomy"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the category slug to write, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"label":"Observe","order":6,"summary":"Traces, metrics, logs and alerts."},"schema":{"$ref":"#/components/schemas/taxonomy.categoryIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/taxonomy.Category"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"taxonomy","x-public":true,"x-tool":true}},"/v1/taxonomy/taxa/{id}":{"delete":{"operationId":"delete_taxonomy_taxa_by_id","summary":"Removes one product from the catalogue.","description":"Removes one product from the catalogue. An id no taxon holds is a\n404. To take a product out of view without losing what was written about it, set\n`published` to false instead.","tags":["taxonomy"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the slug to act on, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/taxonomy.deleted"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"taxonomy","x-public":true,"x-tool":true},"put":{"operationId":"put_taxonomy_taxa_by_id","summary":"Creates or replaces one product and returns it as stored.","description":"Creates or replaces one product and returns it as stored. The id in the\nURL is the one it is filed under whatever the body says. The category must\nalready exist — a taxon naming a category that does not is refused with 400\nrather than stored where nothing can render it.\n\nA taxon opens exactly one way: `route` for a product the console renders\nitself, or `href` for one that genuinely lives at its own domain. Giving both,\nor neither, is refused.\n\nPlatform SuperAdmin only.","tags":["taxonomy"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the taxon slug to write, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"category":"data","description":"Managed vector search.","icon":"Database","name":"Vector","order":3,"route":"/vector","tags":["search"]},"schema":{"$ref":"#/components/schemas/taxonomy.taxonIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/taxonomy.Taxon"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"taxonomy","x-public":true,"x-tool":true}},"/v1/team/account":{"post":{"operationId":"post_team_account","summary":"Read the caller's account and switch space","description":"The account control plane the Team client speaks: one POST carries a `method` verb and its `params`, and answers {\"result\": …}. The verbs are the session's own reads and the space switch — getLoginInfoByToken, getUserWorkspaces, selectWorkspace, getWorkspaceInfo, getMemberships, getPerson, getSocialIds, getRegionInfo, isReadOnlyGuest — plus sendInvite, which adds a member to a space and is refused for a caller who is not its owner or admin.\n\nA REFUSAL IS HTTP 200 carrying {\"error\": {severity, code, params}} — the platform Status the client translates — not a 4xx. An unreadable body, an unauthorized session and an unknown verb all arrive that way, so a caller that reads only the status code reads every failure here as a success.\n\nNO CREDENTIAL IS EVER HANDLED HERE. login, signUp, the OTP verbs, password change and reset, join and the guest-token exchange each answer Unauthorized with \"sign in at hanzo.id\" — a stated policy, not an unknown method, so the refusal is a fact a test can pin. Sessions come from the OAuth pair under /account/auth.\n\nAuth is the team session token: Authorization: Bearer, else the HttpOnly account-token cookie. The tenant is that token's SIGNED org claim, never a header, and selectWorkspace resolves only among the orgs the token proves membership of. It also demands an explicit workspaceUrl — it never falls back to a first space, and a slug that resolves in two of the caller's orgs answers Ambiguous rather than picking one.","tags":["team"],"x-app":"team","x-public":true}},"/v1/team/account/auth/{provider}":{"get":{"operationId":"get_team_account_auth_by_provider","summary":"Start a sign-in at hanzo.id","description":"STARTS the OAuth hop: answers 302 to hanzo.id's authorize endpoint and sets the short-lived HttpOnly state cookie that binds the flow to this browser. NO TOKEN COMES BACK FROM THIS CALL — the session is minted by the callback below, and a client that expects JSON here gets a redirect with no body.\n\nA browser is the intended caller. Anything else must follow the Location AND keep the Set-Cookie, because the callback refuses a flow whose state it cannot match. That cookie carries the random nonce plus the client's navigateUrl, so the round trip needs no second channel, and it lives ten minutes — the whole budget for the hop.\n\nThe provider segment only picks a hint: the redirect_uri is ALWAYS the canonical openid callback, the one IAM has registered. Measured end to end, hanzo.id strips that hint today, so /auth/google and /auth/openid land on the same Hanzo sign-in page — the federation shortcut is an upstream fix, not a second endpoint here.","tags":["team"],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"team","x-public":true}},"/v1/team/account/auth/{provider}/callback":{"get":{"operationId":"get_team_account_auth_by_provider_callback","summary":"Complete a sign-in and hand the browser its session","description":"COMPLETES the OAuth hop: hanzo.id redirects the browser here with ?code and ?state, and the answer is another 302 — back to the client's login route carrying the freshly minted team session token in the query. Never JSON, and never a token in this response's own body.\n\nTHE STATE IS CHECKED FIRST, before the code is even looked at: the flow cookie is read and cleared one-shot, and a callback whose ?state does not equal the nonce it held is bounced with error=state_mismatch and NEVER exchanged. That is what makes a forged or replayed callback inert. Only then is the code exchanged server-side — team is a confidential client with a client_secret, so there is no PKCE and the code never passes through the browser's JS.\n\nThe tenant is derived from the IAM access token VERIFIED RS256 against the JWKS, the same trust anchor the identity boundary uses; a token whose owner claim is empty fails closed with no login at all. Every org that token proves gets a space ensured, so a member of two orgs is a counted seat in both. The IAM access token is also parked in an HttpOnly cookie for the same-origin agents proxy — page JS never reads it.\n\nEVERY failure is a redirect, not a status: a denied consent, a missing code, a failed exchange, an unreadable userinfo, an unverifiable org and a token-mint failure each bounce to the login page with an ?error code naming the step.","tags":["team"],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"team","x-public":true}},"/v1/team/account/cookie":{"delete":{"operationId":"delete_team_account_cookie","summary":"Signs this browser out of team by expiring the HttpOnly account-token cookie the OAuth callback set.","description":"Signs this browser out of team by expiring the HttpOnly\naccount-token cookie the OAuth callback set. It is the counterpart of the\ncookie PUT, it takes nothing — the cookie it clears is named by this service,\nnever by the caller — and it is unconditional: a caller with no cookie, an\nexpired one or a forged one all get the same acknowledgement, because clearing\nsomething that is not there is the same outcome as clearing something that is.\n\nIt clears ONLY the team session cookie. The IAM access-token cookie the same\ncallback set is a different credential with a different lifetime and is left\nalone, so this is a team sign-out, not a platform one.","tags":["team"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.cookieAck"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true},"put":{"operationId":"put_team_account_cookie","summary":"Store the session token as this browser's cookie","description":"Writes the team session token into the HttpOnly `account-token` cookie — Secure, SameSite=Lax, whole-origin scope, thirty days — and answers {\"result\": true}. This is how the client turns the token it caught off the OAuth bounce into a credential page JS can no longer read, which IS the security property: script that cannot see the cookie cannot exfiltrate it, and every later call on the files, billing and collaborator planes authenticates from it when no bearer is sent.\n\nThe token is VERIFIED — signature and expiry, against this service's own signing secret — BEFORE it is stored. Anything this service did not sign is 401 and nothing is written; persisting a caller-supplied value unchecked would be a session-fixation hole, where an attacker pins a cookie the victim's browser then presents as its own.\n\nThe token may arrive as `token` in the JSON body or, when the body is absent or unparseable, from the Authorization bearer — an unreadable body is NOT an error here. The sibling DELETE clears this same cookie and signs the browser out of team only: the IAM cookie set alongside it is a different credential with its own lifetime and is left alone.","tags":["team"],"responses":{"2XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/cookieAck"}}},"description":"Success"}},"x-app":"team","x-public":true}},"/v1/team/account/providers":{"get":{"operationId":"get_team_account_providers","summary":"Returns the identity providers this deployment starts a login with.","description":"Returns the identity providers this deployment starts a login\nwith. It is always exactly one — hanzo.id. Which identities that provider accepts\n(Google, GitHub, passkey, password) is IAM's question, answered on IAM's own\npage next to the identity check and the training-data consent that must\nprecede a first session; listing them here would be a second place holding\nthat answer, and the two drift the moment IAM gains or drops one.","tags":["team"],"responses":{"200":{"content":{"application/json":{"example":[{"displayName":"Hanzo","name":"openid"}],"schema":{"items":{"$ref":"#/components/schemas/team.ProviderInfo"},"type":"array"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/billing/plan":{"get":{"operationId":"get_team_billing_plan","summary":"Returns the plan and seat counts for the caller's OWN org, resolved from the VERIFIED team session token — never a client header.","description":"Returns the plan and seat counts for the caller's OWN org, resolved\nfrom the VERIFIED team session token — never a client header. Seats and guests\nare the org's distinct active human members (a bot member is not a seat); the\nplan comes from the licensing entitlement and is empty when that read is\nunavailable, so the page shows an honest dash rather than a fabricated tier. A\ncaller with no verified session gets 401, and a real seat-read failure is a\n502 rather than a false \"0 members\".","tags":["team"],"responses":{"200":{"content":{"application/json":{"example":{"active":true,"guestLimit":3,"guests":1,"plan":"pro","seats":3,"upgradeUrl":"https://billing.hanzo.ai"},"schema":{"$ref":"#/components/schemas/team.planInfo"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/billing/ui":{"get":{"operationId":"get_team_billing_ui","summary":"Open the wallet page","description":"Serves the usage-and-wallet page the Team front links to — HTML, not JSON. It is a static React build compiled into this binary, so there is no upstream to be down and no build step at request time.\n\nSESSION-GATED: without a verified team session token — bearer, else the HttpOnly account cookie — the caller gets 401 and not one byte of the page, so an anonymous browser meets a refusal rather than a shell that then fails to load anything.\n\nThe page is markup only. It reads money SAME-ORIGIN from cloud's own balance and usage endpoints, which pin the org from the IAM cookie the team OAuth callback set — nothing under this path proxies a money read, so there is no second auth mechanism here to get wrong. A deployment whose page was never built answers 503 naming the missing bundle, never a blank 200.","tags":["team"],"responses":{"2XX":{"content":{"text/html; charset=utf-8":{"schema":{"format":"binary","type":"string"}}},"description":"Success"}},"x-app":"team","x-public":true}},"/v1/team/collaborator":{"get":{"operationId":"get_team_collaborator","summary":"Open the live collaborative-editing socket","description":"Upgrades to the hocuspocus WebSocket the Team editor syncs its Y.js documents over: binary frames of document name, message type and payload, with ONE socket multiplexing every document a tab has open. The server is a relay and an ordered update log, not a CRDT engine — it replays the log to each joining peer and broadcasts every update to the rest, which converges because Y.js updates are commutative and idempotent. There is no body; the response is a protocol upgrade.\n\nBOTH LANES SHARE ONE ROOT. The client derives them from one configured URL — this socket at its root, the markup-snapshot RPC one segment in — so pointing the editor at this service is one value, and the two lanes cannot drift apart.\n\nAUTH IS IN-BAND, PER DOCUMENT, NOT ON THE UPGRADE. The handshake gates only on browser Origin (403 outside the team surfaces; no Origin at all is admitted, which is what a non-browser sends), and then the first frame for a document must be an Auth message carrying the same session or space token every other team route verifies — a browser WebSocket cannot set an Authorization header, which is why the token rides inside the protocol. Anything else on an unauthenticated document is answered with one permission denial and nothing further.\n\nEvery document is authorized on its own: the document's space must be the token's space when the token pins one, and the caller must be a member of it. A mismatch, an unknown space and a non-member deny alike with \"document not found\". Rooms are keyed by org and space and the persisted log's key embeds both, so a foreign document id can neither join a room nor read a blob.\n\nThe server pings every twenty seconds and drops a socket silent for sixty, so a backgrounded tab — whose JS timers are throttled but whose network stack still auto-pongs — stays connected instead of dying into a reconnect loop.","tags":["team"],"x-app":"team","x-public":true}},"/v1/team/collaborator/rpc/{documentId}":{"post":{"operationId":"post_team_collaborator_rpc_by_documentid","summary":"CollabRPC is the collaborative-markup snapshot plane the Team front's editor speaks: createContent stores a document field's markup at a fresh, immutable blob ref and returns it, updateContent stores a new snapshot and answers nothing, and getContent reads back the exact snapshot a ref names.","description":"CollabRPC is the collaborative-markup snapshot plane the Team front's editor\nspeaks: createContent stores a document field's markup at a fresh, immutable\nblob ref and returns it, updateContent stores a new snapshot and answers\nnothing, and getContent reads back the exact snapshot a ref names.\n\ncreateContent ALSO seeds the live-editing update log from the front-supplied\nY.js update, so a dialog-authored description is visible in the collaborative\neditor — which replays that log — and not only in snapshot reads.\nupdateContent never touches that log: peers may be live-editing the document,\nand their edits are not this call's to overwrite.\n\nEvery call is scoped to the caller's VERIFIED session or space token: the\ndocumentId's space must be the token's space when the token names one,\nand the caller must be a member of it. An unknown space, another tenant's\nspace and a space the caller is not in all answer the same 404, so a\nprobe learns nothing about what exists.","tags":["team"],"parameters":[{"name":"documentId","in":"path","required":true,"description":"DocumentID addresses the document field, as\n\"\u003cspaceUuid\u003e|\u003cobjectClass\u003e|\u003cobjectId\u003e|\u003cobjectAttr\u003e\" — the\ncollaborator-client encodeDocumentId shape, from the path.","schema":{"type":"string"},"example":"6579…|tracker:class:Issue|issue-1|description"}],"requestBody":{"content":{"application/json":{"example":{"documentId":"6579…|tracker:class:Issue|issue-1|description","method":"getContent","payload":{"source":"issue-1-description-1730000000000"}},"schema":{"$ref":"#/components/schemas/team.collabRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.collabResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/dms":{"post":{"operationId":"post_team_dms","summary":"Opens the direct message between the caller and the people named, or answers the one that already exists — there is one conversation per set of people, however many times it is asked for.","description":"Opens the direct message between the caller and the people named,\nor answers the one that already exists — there is one conversation per set of\npeople, however many times it is asked for.\n\nEvery person named must be a member of the space or one of the org's agents;\na direct message with an agent is a conversation it answers every message in,\nand a guest may not open one.\nAnswers 201 when this call opened it and 200 when it was already there.","tags":["team"],"requestBody":{"content":{"application/json":{"example":{"members":["9f2c…"]},"schema":{"$ref":"#/components/schemas/team.teamDirectOpen"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamDirect"}}},"description":"ok"},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamDirect"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/docs":{"get":{"operationId":"get_team_docs","summary":"Returns the documents of a space the caller may see, with the teamspaces they are grouped in.","description":"Returns the documents of a space the caller may see, with the\nteamspaces they are grouped in.\n\nThese are the Team client's own document rows, so a page created there is\nhere with no sync. Each carries the `collaborator` id its body opens with on\nthe /v1/team/collaborator socket. A private teamspace's documents are listed\nonly for its members.","tags":["team"],"parameters":[{"name":"space","in":"query","required":false,"description":"Space is the space uuid. Optional for a caller in exactly one space.","schema":{"type":"string"}},{"name":"teamspace","in":"query","required":false,"description":"Teamspace narrows the answer to one teamspace.","schema":{"type":"string"}},{"name":"parent","in":"query","required":false,"description":"Parent narrows the answer to one document's children.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamDocs"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true},"post":{"operationId":"post_team_docs","summary":"Creates a document, as the caller, after its siblings.","description":"Creates a document, as the caller, after its siblings.\n\nIt is created through the Team client's own write path, so it appears in an\nopen Documents sidebar live, and its author is subscribed to it: a comment on\nit lands in their inbox. Its body starts empty — open the returned\n`collaborator` id on the /v1/team/collaborator socket to write it.\n\nA space whose caller can write no teamspace at all gets one on its first\ndocument: a public \"General\" teamspace every current member of the space is\nin, which is what the Team client would otherwise make somebody create by hand\nbefore the first page. Guests and agents are not made members of it.","tags":["team"],"requestBody":{"content":{"application/json":{"example":{"parent":"d41c","title":"Runbook"},"schema":{"$ref":"#/components/schemas/team.teamDocNew"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamDoc"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/docs/{id}":{"delete":{"operationId":"delete_team_docs_by_id","summary":"Removes a document with everything nested under it and every comment on any of them — the Team client's own delete, which takes the subtree with it.","description":"Removes a document with everything nested under it and every\ncomment on any of them — the Team client's own delete, which takes the\nsubtree with it. Its author, an owner of its teamspace or an admin of the\nspace may delete it. Answers 204.\n\nThe document model has no archived state for a page (only a teamspace can be\narchived), so there is nothing softer to offer here than removal.","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the document, from the path.","schema":{"type":"string"}},{"name":"space","in":"query","required":false,"description":"Space is the space uuid holding it.","schema":{"type":"string"},"example":"0e3c…"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true},"get":{"operationId":"get_team_docs_by_id","summary":"Returns one document the caller may see.","description":"Returns one document the caller may see.","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the document, from the path.","schema":{"type":"string"},"example":"d41c"},{"name":"space","in":"query","required":false,"description":"Space is the space uuid holding it.","schema":{"type":"string"},"example":"0e3c…"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamDoc"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true},"patch":{"operationId":"patch_team_docs_by_id","summary":"Renames a document or moves it — under another document, to the top of its teamspace, or to another teamspace with everything nested under it.","description":"Renames a document or moves it — under another document, to the top\nof its teamspace, or to another teamspace with everything nested under it.\n\nAnyone who can write the teamspace may rename or move a page, as in the Team\nclient. A move goes after its new siblings, and a document cannot be moved\nunder itself or under one of its own descendants.","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the document, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"parent":"","space":"0e3c…","title":"Runbook (2026)"},"schema":{"$ref":"#/components/schemas/team.teamDocEdit"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamDoc"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/docs/{id}/comments":{"get":{"operationId":"get_team_docs_by_id_comments","summary":"Returns the comments on a document, oldest first — the same message shape a room's conversation answers.","description":"Returns the comments on a document, oldest first — the same\nmessage shape a room's conversation answers.","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the document, from the path.","schema":{"type":"string"}},{"name":"space","in":"query","required":false,"description":"Space is the space uuid holding it.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamMessages"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true},"post":{"operationId":"post_team_docs_by_id_comments","summary":"Comments on a document, as the caller.","description":"Comments on a document, as the caller.\n\nIt is a message attached to the document, written through the Team client's\nown path: the people subscribed to the document and anyone mentioned are\nnotified, and an agent mentioned answers with a comment of its own. It can be\nreplied to, reacted to, edited and deleted with the message ops.","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the document, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"space":"0e3c…","text":"step 3 is out of date, \u003c@9f2c…\u003e"},"schema":{"$ref":"#/components/schemas/team.teamCommentWrite"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamMessage"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/events":{"get":{"operationId":"get_team_events","summary":"Stream live changes to what the caller may see, as Server-Sent Events","description":"Holds one text/event-stream open per caller and pushes each change as it is written — by the Team client, a typed op or an agent — filtered to the rooms, documents and inbox the caller may see under the same rule the ops apply. Authenticate with `Authorization: Bearer` (a fetch-based SSE reader; a browser EventSource cannot set it). `?space=` narrows the stream to one space; without it the stream covers every space the caller is a member of at connect.\n\nEach frame is `event: \u003cname\u003e` and a JSON `data:` line carrying `space` and one of:\n- `message.created`, `message.updated` — `message`, the message as the message ops answer it (a room message, a thread reply or a document comment; a count or reaction change is an update);\n- `message.deleted` — `id`, and `room`/`doc`/`thread` where known;\n- `reaction.changed` — `message`, with its reactions as they now stand;\n- `room.changed` — `room`, as the room listing answers it, sent to those who can see it after the change (somebody removed from a private room is not told; the room list is the truth);\n- `doc.changed` — `doc`, as the document ops answer it (`removed: true` and `id` when deleted); body edits happen on the collaborator socket and are not streamed here;\n- `inbox.created`, `inbox.updated` — `item`, one of the caller's own notifications.\n\nA `: ping` comment is written every 25 seconds. There is no resume: the server keeps no event sequence, so frames carry no `id` and Last-Event-ID is ignored; on reconnect, re-read the ops. A stream that falls too far behind is closed rather than allowed to slow a writer, and so is one whose caller is no longer a member of the space an event is in. 401 without a verified team credential; 404 for a named space the caller is not in.","tags":["team"],"responses":{"2XX":{"content":{"text/event-stream":{"schema":{"format":"binary","type":"string"}}},"description":"Success"}},"x-app":"team","x-public":true}},"/v1/team/files/{space}":{"post":{"operationId":"post_team_files_by_space","summary":"Upload a file into a space","description":"Stores one file in a space's blob store and answers the blob id it is addressable by, as plain text — the front discards that body, it is there for a caller driving this by hand.\n\nThe body is a multipart form with a `file` part, and THAT PART'S FILENAME IS THE BLOB ID: the client mints it (a uuid v4) and the server stores under it, so a part whose filename is not a uuid is refused rather than assigned one. A file over 100 MiB is 413 and an empty one is 400.\n\nThe caller must hold a verified session or space token AND be a member of the space; an unknown space, another tenant's space and a space the caller is not in all answer the same 404, so a probe learns nothing about what exists. The stored key embeds the verified org and the space, so an upload cannot land in another tenant's box whatever id it names. A storage backend that is unavailable fails closed with 502 rather than reporting a write it never made.","tags":["team"],"parameters":[{"name":"space","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/octet-stream":{"schema":{"format":"binary","type":"string"}}}},"responses":{"2XX":{"content":{"text/plain; charset=utf-8":{"schema":{"format":"binary","type":"string"}}},"description":"Success"}},"x-app":"team","x-public":true}},"/v1/team/files/{space}/{filename}":{"delete":{"operationId":"delete_team_files_by_space_by_filename","summary":"Removes one blob from a space's file store.","description":"Removes one blob from a space's file store. The caller must\nhold a verified session AND be a member of the space; anything else — an\nunknown space, another tenant's space, a space the caller is not\nin — answers the same 404, so a probe learns nothing about what exists.\n\nIt is IDEMPOTENT: deleting a present or an absent blob both answer 204, so a\ndelete never confirms a blob's existence and a foreign blob id (a physical key\nthe caller can never name into another tenant's box) is a harmless no-op. A\nstorage backend that is unavailable fails closed with 502 rather than lying\nabout success.","tags":["team"],"parameters":[{"name":"space","in":"path","required":true,"description":"Space is the space uuid the blob belongs to, from the path.","schema":{"type":"string"},"example":"6579…"},{"name":"filename","in":"path","required":true,"description":"Filename is the last path segment, which the front sets to the blob id\nwhen it sends no explicit `file`.","schema":{"type":"string"}},{"name":"file","in":"query","required":false,"description":"File is the blob id, and wins over the path segment when both are present.","schema":{"type":"string"},"example":"0d4f…"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true},"get":{"operationId":"get_team_files_by_space_by_filename","summary":"Download a space file","description":"Streams one blob's raw BYTES back — this is the read side of the space file store, not a JSON envelope around it.\n\nTHE BLOB IS NAMED BY THE `file` QUERY PARAMETER, NOT BY :filename. The path segment is only the name a browser saves the download under; a request without ?file= is a 400 no matter what the path says.\n\nThe Content-Type is derived from the STORED BYTES, never from the name: only png, jpeg, gif and webp, recognized by their magic bytes, are served inline under their true type, and everything else is served inert as application/octet-stream with an attachment disposition. Every response carries nosniff, so a file uploaded under an .svg or .html name cannot be talked into executing in a viewer's origin. Blobs are immutable, so a hit caches privately for a year.\n\nSame gate as the upload: verified token, membership of the space. A genuine miss, another tenant's space, a space the caller is not in, and a blob id belonging to a different space are ONE answer — 404 — because the physical key is org- and space-scoped and a foreign id is simply a key that does not exist. An unavailable backend is a 502, never an empty 200.","tags":["team"],"parameters":[{"name":"space","in":"path","required":true,"schema":{"type":"string"}},{"name":"filename","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"2XX":{"content":{"application/octet-stream":{"schema":{"format":"binary","type":"string"}}},"description":"Success"}},"x-app":"team","x-public":true}},"/v1/team/inbox":{"get":{"operationId":"get_team_inbox","summary":"Returns the caller's notifications, newest first, each with the room or document it is about and the message that caused it.","description":"Returns the caller's notifications, newest first, each with the\nroom or document it is about and the message that caused it.\n\nThese are the rows the Team client's Inbox reads, so a notification cleared\nthere is cleared here. Only the caller's own notifications are ever listed.","tags":["team"],"parameters":[{"name":"space","in":"query","required":false,"description":"Space is the space uuid. Optional for a caller in exactly one space.","schema":{"type":"string"}},{"name":"archived","in":"query","required":false,"description":"Archived lists the archived notifications instead of the live ones.","schema":{"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamInbox"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/inbox/read":{"post":{"operationId":"post_team_inbox_read","summary":"Marks every live notification of the caller's read, and says how many it changed.","description":"Marks every live notification of the caller's read, and\nsays how many it changed.","tags":["team"],"requestBody":{"content":{"application/json":{"example":{"space":"0e3c…"},"schema":{"$ref":"#/components/schemas/team.teamInboxAll"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamInboxCleared"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/inbox/{id}/archive":{"post":{"operationId":"post_team_inbox_by_id_archive","summary":"Archives one of the caller's notifications — read, and out of the live inbox — and answers it.","description":"Archives one of the caller's notifications — read, and\nout of the live inbox — and answers it. It is listed again with\n`archived=true`.","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the notification, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"space":"0e3c…"},"schema":{"$ref":"#/components/schemas/team.teamInboxAt"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamInboxItem"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/inbox/{id}/read":{"post":{"operationId":"post_team_inbox_by_id_read","summary":"Marks one of the caller's notifications read and answers it.","description":"Marks one of the caller's notifications read and answers it.\nAnother person's notification is a 404, as one that does not exist is.","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the notification, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"space":"0e3c…"},"schema":{"$ref":"#/components/schemas/team.teamInboxAt"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamInboxItem"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/members":{"get":{"operationId":"get_team_members","summary":"Returns the people and agents in a space, with the name, avatar, role and presence a client draws them with.","description":"Returns the people and agents in a space, with the name, avatar,\nrole and presence a client draws them with.\n\nPeople come from IAM, the membership authority; agents from the org's agent\nregistry; avatars from the Person documents the Team client edits. An IAM that\ndoes not answer is a 502 rather than an empty roster, and an agent registry\nthat does not answer is named in `degraded` beside the people who did load.\nThe caller must be a member of the space.","tags":["team"],"parameters":[{"name":"space","in":"query","required":false,"description":"Space is the space uuid. Optional for a caller in exactly one space.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamMembers"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/messages/{id}":{"delete":{"operationId":"delete_team_messages_by_id","summary":"Removes a message, with its replies, reactions, files and the inbox notifications that point at it.","description":"Removes a message, with its replies, reactions, files and the\ninbox notifications that point at it. Its author may delete it, and so may an\nowner or admin of the space.\n\nEach removal is a platform remove through the Team client's write path, so the\nmessage disappears from every open client live. Answers 204.","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the message, from the path.","schema":{"type":"string"}},{"name":"space","in":"query","required":false,"description":"Space names the space holding it. A message id is unique within a space,\nnot across the org.","schema":{"type":"string"},"example":"0e3c…"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true},"patch":{"operationId":"patch_team_messages_by_id","summary":"Rewrites what a message says.","description":"Rewrites what a message says. Only its author may edit it.\n\nThe edit is an ordinary update of the message document through the Team\nclient's own write path, stamped with editedOn, so an open client shows the\nnew text and the \"edited\" mark live. Somebody the new text mentions for the\nfirst time is notified.","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the message, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"space":"0e3c…","text":"deploying at 3pm instead"},"schema":{"$ref":"#/components/schemas/team.teamMessageEdit"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamMessage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/messages/{id}/reactions/{emoji}":{"delete":{"operationId":"delete_team_messages_by_id_reactions_by_emoji","summary":"Takes back the caller's reaction to a message and answers the message with its reactions as they now stand.","description":"Takes back the caller's reaction to a message and answers the message\nwith its reactions as they now stand. Taking back a reaction the caller never\nmade changes nothing and is not an error.","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the message, from the path.","schema":{"type":"string"}},{"name":"emoji","in":"path","required":true,"description":"Emoji is the reaction, from the path (percent-encoded on the wire).","schema":{"type":"string"}},{"name":"space","in":"query","required":false,"description":"Space names the space holding the message.","schema":{"type":"string"},"example":"0e3c…"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamMessage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true},"put":{"operationId":"put_team_messages_by_id_reactions_by_emoji","summary":"Adds the caller's reaction to a message and answers the message with its reactions as they now stand.","description":"Adds the caller's reaction to a message and answers the message with\nits reactions as they now stand. Reacting twice with one emoji is one\nreaction: the second call changes nothing.\n\nThe emoji is the last path segment, percent-encoded — PUT\n/v1/team/messages/7a1c/reactions/%F0%9F%91%8D for 👍.","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the message, from the path.","schema":{"type":"string"}},{"name":"emoji","in":"path","required":true,"description":"Emoji is the reaction, from the path (percent-encoded on the wire).","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"space":"0e3c…"},"schema":{"$ref":"#/components/schemas/team.teamReactionWrite"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamMessage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/messages/{id}/replies":{"get":{"operationId":"get_team_messages_by_id_replies","summary":"Returns a message's thread, oldest first, each reply with its reactions and files.","description":"Returns a message's thread, oldest first, each reply with its\nreactions and files.","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the message, from the path.","schema":{"type":"string"}},{"name":"space","in":"query","required":false,"description":"Space names the space holding it. A message id is unique within a space,\nnot across the org.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamMessages"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true},"post":{"operationId":"post_team_messages_by_id_replies","summary":"Answers a message in its thread, as the caller.","description":"Answers a message in its thread, as the caller.\n\nA reply is a thread message attached to the one it answers, written through\nthe Team client's own path: the parent's reply count and last-reply time move\nwith it, the people already in the thread and anyone mentioned are notified,\nand an agent mentioned in a reply answers in the same thread. A reply cannot\nitself be replied to — threads are one level deep, as in the Team client.","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the message being answered, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"space":"0e3c…","text":"on it"},"schema":{"$ref":"#/components/schemas/team.teamReplyWrite"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamMessage"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/public":{"get":{"operationId":"get_team_public","summary":"Lists the rooms orgs have published, across every org.","description":"Lists the rooms orgs have published, across every org.\n\nIt is NOT part of GET /rooms, and the separation is the point: that address\nanswers the CALLER'S rooms, so folding these in would put strangers' channels\nin somebody's own sidebar.\n\nIt reads the directory and never a tenant's store. Every field it can answer\nwith is one an org published by making a room public, so there is nothing here\nto scope by org — a directory only its own org can read is not a directory.\nAn authenticated principal is still required, because an anonymous crawler is\nnot who this is for.","tags":["team"],"parameters":[{"name":"q","in":"query","required":false,"description":"Q matches a room's name or its topic.","schema":{"type":"string"}},{"name":"org","in":"query","required":false,"description":"Org narrows to one org's published rooms.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps the page, 50 when unstated and 200 at most. An unparseable\nvalue reads as unstated rather than as zero — zero pages is not an answer\nanybody asked for.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.publicRooms"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/rooms":{"get":{"operationId":"get_team_rooms","summary":"Returns the rooms the caller may see, with the kind and work facet each carries.","description":"Returns the rooms the caller may see, with the kind and work\nfacet each carries.\n\nA signed-in TEAM MEMBER reads every room of every space they are in that is\nopen to them: public channels, and the private channels and direct messages\nthat name them. An APPLICATION of the org (its own machine credential) reads\nthe public channels of the org's spaces and nothing that belongs to\nparticular people. Anybody else without a team session is 401.\n\nIt reads the SAME Chunter documents the transactor serves, so a room opened\nin the Team client appears here with no sync, and a facet written here is read\nby anything holding the document.","tags":["team"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamRooms"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true},"post":{"operationId":"post_team_rooms","summary":"Opens a named room and answers it as the store now holds it.","description":"Opens a named room and answers it as the store now holds it.\n\nIt writes through the SAME applyTx path the Team client uses, so a room opened\nhere is broadcast to every live client of the space and appears in an open\nsidebar without a reload — the same property listRooms rests on, read from the\nwrite side.\n\nA SIGNED-IN TEAM MEMBER opens it as themselves: they are its first member and\nits owner, every other member named must be somebody the space knows (a person\nin it, or one of the org's agents), and a guest may not open rooms at all. An\napplication of the org opens it as the org, with exactly the members it names.\nAnybody else without a team session is 401.\n\nTWO TRANSACTIONS, NOT ONE, when the request states a facet. The document and\nits mixin are separate writes in this model (bindRoom writes only the second),\nand composing them here rather than inventing a combined tx keeps one write\npath for each. A create that lands and a facet that does not is visible as a\nroom with default intent, which is the honest partial state.","tags":["team"],"requestBody":{"content":{"application/json":{"example":{"bindings":["issue:1010"],"life":"bound","name":"bugfix-1010"},"schema":{"$ref":"#/components/schemas/team.teamRoomNew"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamRoom"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/rooms/{id}":{"patch":{"operationId":"patch_team_rooms_by_id","summary":"Renames a channel, sets its topic, or archives or reopens it, and answers the room as it now stands.","description":"Renames a channel, sets its topic, or archives or reopens it, and\nanswers the room as it now stands.\n\nIts owners and the space's admins may edit a room; a room nobody owns — one\nopened by an integration — may be edited by anyone in it, and a direct\nmessage by either person in it. Archiving withdraws a public channel from the\ncross-org directory in the same write; reopening lists it again.","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the room, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"archived":true,"space":"0e3c…"},"schema":{"$ref":"#/components/schemas/team.teamRoomEdit"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamRoom"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true},"put":{"operationId":"put_team_rooms_by_id","summary":"States what a room is for: its lifecycle intent, and what it is about.","description":"States what a room is for: its lifecycle intent, and what it is\nabout. It answers the room as it now stands.\n\nThe write is a platform MIXIN on the room document, applied through the\nSAME applyTx path the Team client's own writes take and broadcast to every\nconnected client — so a room bound here updates live in an open space\nrather than on the next reload. A team member binds a room they can see; an\napplication of the org binds its public channels only; anybody else without\na team session is 401.","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the room to bind, from the path. The URL is the authority; a body\ncarrying another id cannot redirect the write.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"bindings":["repo:hanzoai/cloud","issue:1010"],"life":"bound","space":"0e3c…"},"schema":{"$ref":"#/components/schemas/team.teamRoomBind"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamRoom"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/rooms/{id}/members":{"get":{"operationId":"get_team_rooms_by_id_members","summary":"Returns the people and agents in one room, as the roster describes them.","description":"Returns the people and agents in one room, as the roster\ndescribes them. The caller must be able to see the room.","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the room, from the path. The URL is the authority.","schema":{"type":"string"}},{"name":"space","in":"query","required":false,"description":"Space names the space holding the room, and is required for the reason the\nbind op requires it: a room id is unique within a space and not across the\norg, so searching every space for a match would make the answer depend on\niteration order.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamRoomMembers"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true},"post":{"operationId":"post_team_rooms_by_id_members","summary":"Adds people to a room and answers the room as it now stands.","description":"Adds people to a room and answers the room as it now stands.\n\nAnyone in the space except a guest may join a public channel by naming\nthemselves. Adding somebody else takes being in the room already (or\nadministering the space, for a room they can see). A direct message's people\nare what it is, so none can be added — open another one. Everyone added must\nbe a member of the space or one of the org's agents; an agent added to a room\nanswers when it is @-mentioned there.","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the room, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"members":["9f2c…"],"space":"0e3c…"},"schema":{"$ref":"#/components/schemas/team.teamRoomJoin"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamRoom"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/rooms/{id}/members/{account}":{"delete":{"operationId":"delete_team_rooms_by_id_members_by_account","summary":"Takes one person out of a room — the caller leaving, when the account is their own.","description":"Takes one person out of a room — the caller leaving, when the\naccount is their own. Removing somebody else takes owning the room or\nadministering the space. Leaving a room you are not in, or removing somebody\nwho is not there, changes nothing. A direct message cannot be left: its people\nare what it is. Answers 204.","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the room, from the path.","schema":{"type":"string"}},{"name":"account","in":"path","required":true,"description":"Account is the account uuid to remove, from the path. Your own is leaving.","schema":{"type":"string"}},{"name":"space","in":"query","required":false,"description":"Space is the space uuid holding the room.","schema":{"type":"string"},"example":"0e3c…"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/rooms/{id}/messages":{"get":{"operationId":"get_team_rooms_by_id_messages","summary":"Returns the tail of one room's conversation, oldest first, each message with its reactions, files and thread count.","description":"Returns the tail of one room's conversation, oldest first, each\nmessage with its reactions, files and thread count.\n\nIt reads the SAME Chunter documents the transactor serves, so a message typed\nin the Team client is here with no sync. A team member reads any room they\nmay see; an application of the org reads public channels only; anybody else\nwithout a team session is 401. A room the caller may not read answers 404\nrather than 403, so a probe learns nothing about what exists.","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the room, from the path. The URL is the authority.","schema":{"type":"string"}},{"name":"space","in":"query","required":false,"description":"Space names the space holding the room, and is required for the reason the\nbind op requires it: a room id is unique within a space and not across the\norg, so searching every space for a match would make the answer depend on\niteration order.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamMessages"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true},"post":{"operationId":"post_team_rooms_by_id_messages","summary":"Says one thing in a room, as the caller.","description":"Says one thing in a room, as the caller.\n\nThe write goes through the SAME applyTx path the Team client's own messages\ntake and is broadcast to every connected client of the space, so a message\nsent here appears live in an open room rather than on the next reload. It\nanswers the message as the store now HOLDS it.\n\n`\u003c@account-uuid\u003e` in the text is stored as the platform's mention, so the\nperson is notified in their inbox. Mentioning one of the org's agents — or\nwriting in a direct message with one — wakes it: it runs as itself, on behalf\nof the caller, and posts its answer into the same room. The caller must be\nable to see the room, and an archived room refuses new messages (409).","tags":["team"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the room to say it in, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"space":"0e3c…","text":"deploying now, \u003c@9f2c…\u003e can you watch the dashboards?"},"schema":{"$ref":"#/components/schemas/team.teamMessageWrite"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.teamMessage"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/transactor/statistics":{"get":{"operationId":"get_team_transactor_statistics","summary":"Returns the transactor's live sessions for the space the caller's credential names — the endpoint the front's space switcher and server panel poll on the transactor base.","description":"Returns the transactor's live sessions for the space the caller's\ncredential names — the endpoint the front's space switcher and server panel\npoll on the transactor base. `token` carries the same two lanes the socket's path\nsegment does: a space UUID names the space and is authorized against the\nmembership rows, an HS256 space token names it in its signed claims.\nactiveSessions carries ONLY that one space, never another tenant's sessions.\nAn unverifiable credential, or one the caller is no member under, is 401.","tags":["team"],"parameters":[{"name":"token","in":"query","required":false,"description":"Token is the space token minted by selectWorkspace.","schema":{"type":"string"},"example":"eyJhbGciOiJIUzI1NiJ9…"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/team.statsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"team","x-public":true,"x-tool":true}},"/v1/team/transactor/{token}":{"get":{"operationId":"get_team_transactor_by_token","summary":"Open the space data-plane socket","description":"Upgrades to the WebSocket the Team client runs an entire space over: every frame is a ZAP envelope wrapping one JSON-RPC message — findAll/findOne reads against the space's documents, tx writes that broadcast to the other live sessions, hello negotiating JSON rather than msgpack. The response is a protocol upgrade, so there is no body to read.\n\nTHE PATH SEGMENT IS THE CREDENTIAL. It is the space token selectWorkspace minted — bearer-equivalent, and sitting in a URL that proxies and access logs record, which is exactly why it expires in twelve hours and is re-minted on demand rather than being long-lived like the session token. It is decoded and verified (signature and expiry) BEFORE the upgrade, so a bad one is a 401 and never a socket that is accepted and then dropped, and it must carry both an account and a space claim. Nothing ambient authorizes this socket: a WebSocket is exempt from CORS, so a cookie-borne credential would make the Origin check the only access control on the whole data plane.\n\nThe tenant is the token's SIGNED org claim and it keys every store path, so no header can name another space's data. The upgrade ALSO refuses a browser Origin outside the team surfaces with 403 — otherwise any page could open an authenticated socket with a token it lured out of a logged-in browser — while a request with no Origin at all is admitted, because that is what a non-browser client sends.\n\nOn connect the space's system spaces are seeded once and the roster is reconciled every time, so the org's human members and its bots are present as space people without a separate sync call.","tags":["team"],"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"team","x-public":true}},"/v1/tel/calls":{"get":{"operationId":"get_tel_calls","summary":"Lists the calls this org has placed or received, newest first.","description":"Lists the calls this org has placed or received, newest first. Like the\nmessage list beside it, these are our own records rather than the carrier's.","tags":["tel"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tel.callList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tel","x-public":true,"x-tool":true},"post":{"operationId":"post_tel_calls","summary":"Dials.","description":"Dials. An `agent` names a Hanzo assistant to answer it; the call is\nrefused up front when no assistant plane is configured, because a call that\nconnects to silence has already cost the person who answered it.","tags":["tel"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tel.callInput"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tel.Call"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tel","x-public":true,"x-tool":true}},"/v1/tel/calls/{id}":{"delete":{"operationId":"delete_tel_calls_by_id","summary":"Ends a call this org placed.","description":"Ends a call this org placed. The holding is read for THIS org before the\ncarrier is asked, for the reason releaseNumber gives one surface up: an id\nbelonging to another tenant would otherwise be hung up by whoever guessed it.","tags":["tel"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tel","x-public":true,"x-tool":true}},"/v1/tel/messages":{"get":{"operationId":"get_tel_messages","summary":"Lists the messages this org has sent or received, newest first.","description":"Lists the messages this org has sent or received, newest first. Records from\nour own store, not the carrier's — so it is what this platform did on the\norg's behalf, which is the set an audit or a bill has to agree with.","tags":["tel"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tel.messageList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tel","x-public":true,"x-tool":true},"post":{"operationId":"post_tel_messages","summary":"Sends a message from one of this org's own numbers.","description":"Sends a message from one of this org's own numbers.\n\n`from` must be a number the org HOLDS, checked against the store rather than\ntaken on trust — a caller that could send from any number could impersonate\none, and the carrier would deliver it. `to` is required, and the body needs\ntext or media, because a message with neither is delivered as nothing and\nbilled as something.","tags":["tel"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tel.messageInput"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tel.SMS"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tel","x-public":true,"x-tool":true}},"/v1/tel/numbers":{"get":{"operationId":"get_tel_numbers","summary":"Lists the phone numbers this org HOLDS — the ones it has bought and not released.","description":"Lists the phone numbers this org HOLDS — the ones it has bought and not\nreleased. Distinct from the availability search one path down\n(`/numbers/available`), which asks the carrier what could be bought: this\nanswers only from our own store, so it is what an org owns rather than what\nit could own.","tags":["tel"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tel.numberList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tel","x-public":true,"x-tool":true},"post":{"operationId":"post_tel_numbers","summary":"Provisions with the carrier FIRST and records second.","description":"Provisions with the carrier FIRST and records second. The other order\nrecords a holding that may not exist, and a number the platform believes it owns\nbut cannot use is worse than one it failed to buy.","tags":["tel"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tel.buyInput"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tel.Number"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tel","x-public":true,"x-tool":true}},"/v1/tel/numbers/available":{"get":{"operationId":"get_tel_numbers_available","summary":"Asks the carrier what is available to buy.","description":"Asks the carrier what is available to buy. Nothing is recorded —\na search is not a holding, and treating it as one is how inventory leaks.","tags":["tel"],"parameters":[{"name":"Country","in":"query","required":false,"schema":{"type":"string"}},{"name":"Area","in":"query","required":false,"schema":{"type":"string"}},{"name":"Type","in":"query","required":false,"schema":{"type":"string"}},{"name":"Limit","in":"query","required":false,"schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tel.numberList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tel","x-public":true,"x-tool":true}},"/v1/tel/numbers/{id}":{"delete":{"operationId":"delete_tel_numbers_by_id","summary":"Checks the holding is THIS org's before it reaches the carrier.","description":"Checks the holding is THIS org's before it reaches the carrier.\nWithout that read, an id belonging to another tenant would be released by\nwhoever guessed it.","tags":["tel"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tel","x-public":true,"x-tool":true}},"/v1/tel/summary":{"get":{"operationId":"get_tel_summary","summary":"Counts what this org holds on the telephony plane: its numbers, its calls and its messages.","description":"Counts what this org holds on the telephony plane: its numbers, its calls and\nits messages. The one read a dashboard makes before it asks for any list, so\nit answers three totals and no rows.","tags":["tel"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tel.summary"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tel","x-public":true,"x-tool":true}},"/v1/template":{"get":{"operationId":"get_template","summary":"Lists the public starter-kit catalog plus, for a validated caller, that org's own private kits.","description":"Lists the public starter-kit catalog plus, for a validated caller, that\norg's own private kits. No request field can widen the scope: the org comes\nfrom the validated principal, so an anonymous or cross-org caller structurally\nsees the public catalog only.","tags":["template"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/template.kitList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"template","x-public":true,"x-tool":true},"post":{"operationId":"post_template","summary":"Creates a starter kit PRIVATE to the caller's org and answers 201 with the stored kit.","description":"Creates a starter kit PRIVATE to the caller's org and answers 201 with\nthe stored kit. The owner is stamped by the server, so a body \"org\" is never\ntrusted; publishing over a public-catalog slug is 409, so a slug still names\nexactly one kit.","tags":["template"],"requestBody":{"content":{"application/json":{"example":{"framework":"Next.js 14","slug":"acme-portal","title":"Acme Internal Portal"},"schema":{"$ref":"#/components/schemas/template.publishKitIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/template.StarterKit"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"template","x-public":true,"x-tool":true}},"/v1/template/{slug}":{"delete":{"operationId":"delete_template_by_slug","summary":"Deletes the caller org's OWN starter kit.","description":"Deletes the caller org's OWN starter kit. A slug they do not own is a\n404, never a delete: the DELETE binds org.","tags":["template"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the starter kit to act on, from the path.","schema":{"type":"string"},"example":"acme-portal"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"template","x-public":true,"x-tool":true},"get":{"operationId":"get_template_by_slug","summary":"Returns one starter kit: the caller org's own by that slug, else the public catalog's.","description":"Returns one starter kit: the caller org's own by that slug, else the public\ncatalog's. A slug another org owns reads as not found.","tags":["template"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the starter kit to act on, from the path.","schema":{"type":"string"},"example":"folio"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/template.StarterKit"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"template","x-public":true,"x-tool":true},"put":{"operationId":"put_template_by_slug","summary":"Overwrites the caller org's OWN starter kit at the path slug, answering the stored kit.","description":"Overwrites the caller org's OWN starter kit at the path slug, answering\nthe stored kit. A slug they do not own is 404, never a create: the UPDATE binds\norg, so a PUT can never reach another org's kit.","tags":["template"],"parameters":[{"name":"slug","in":"path","required":true,"description":"Slug is the kit to replace, from the path.","schema":{"type":"string"},"example":"acme-portal"}],"requestBody":{"content":{"application/json":{"example":{"slug":"acme-portal","title":"Acme Internal Portal v2"},"schema":{"$ref":"#/components/schemas/template.replaceKitIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/template.StarterKit"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"template","x-public":true,"x-tool":true}},"/v1/tool":{"get":{"operationId":"get_tool","summary":"Lists every tool the caller's org and project can reach, from every source, each flagged with whether it is activated.","description":"Lists every tool the caller's org and project can reach, from every\nsource, each flagged with whether it is activated. This is the discovery\nsurface: one flat set of names spanning connector actions, user functions,\nzap-service routes, agents, skills and the org's own external MCP servers,\ndeduplicated by name so the highest-precedence source wins a collision. It\nlists; it does not call — dispatch is POST /v1/tool/call.","tags":["tool"],"parameters":[{"name":"source","in":"query","required":false,"description":"Source keeps only tools from one source — connector, function, zap-service,\nagent, skill or mcp. Empty keeps every source.","schema":{"type":"string"}},{"name":"activated","in":"query","required":false,"description":"Activated keeps only the tools activated for the caller's org and project,\nand only when it is exactly the string \"true\".","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tool.toolList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tool","x-public":true,"x-tool":true}},"/v1/tool/activation":{"get":{"operationId":"get_tool_activation","summary":"Reports which tools are switched on for the caller's org and project.","description":"Reports which tools are switched on for the caller's org and\nproject. Activation is what makes a tool dispatchable and what makes it visible\nto an agent, so this is the set the MCP tool list is drawn from — every other\ntool in the registry is discoverable but refused at call time.","tags":["tool"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tool.activationSet"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tool","x-public":true,"x-tool":true},"put":{"operationId":"put_tool_activation","summary":"Switches tools on and off for the caller's org and project, and answers with the resulting activated set.","description":"Switches tools on and off for the caller's org and project, and\nanswers with the resulting activated set. It is the ONE write path that turns\nskills, plugins and connectors into callable tools — an unactivated tool is\nlisted by discovery but refused 403 at dispatch. Activate is applied before\nDeactivate, so a name in both lists ends up off. More than 256 toggles in one\nrequest is refused 413.\n\nSwitching a skill (skill_\u003cname\u003e) or a tool of an MCP server the org registered\n(\u003cserver\u003e_\u003ctool\u003e) changes what every agent run in the org carries, so it takes\nan admin of the org or a SuperAdmin: a member naming one is refused 403 and\nnothing in the request is switched. Every change is on the org's audit trail\nbefore it is made, and one the trail cannot record is refused 503.","tags":["tool"],"requestBody":{"content":{"application/json":{"example":{"activate":["cloud_get_ping"],"deactivate":[]},"schema":{"$ref":"#/components/schemas/tool.activationReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tool.activationSet"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tool","x-public":true,"x-tool":true}},"/v1/tool/call":{"post":{"operationId":"post_tool_call","summary":"Runs one of the caller's activated tools and answers with its output.","description":"Runs one of the caller's activated tools and answers with its output.\n\nThis is the endpoint onto the tool plane's DYNAMIC half — the half no build-time\ncatalogue can hold, because it is per-tenant: an org's connected connector\nactions, its authored skills, its agents and functions, and the tools of every\nexternal MCP server it registered. A tool's existence, its price and its\nactivation are all rows, not code, so they cannot be known until the caller is.\n\nOne policy, the registry's: resolve by precedence, refuse an unactivated tool\n403, settle a priced one through the x402 client or fail closed 402, then\ndispatch to the winning source bound to the caller's own (org, project). One\nmetered unit, one audit record. A caller can only ever dispatch its own tools.\n\nDiscovery is GET /v1/tool — ?activated=true for the callable set.","tags":["tool"],"requestBody":{"content":{"application/json":{"example":{"arguments":{"channel":"#general","text":"hi"},"name":"slack_post_message"},"schema":{"$ref":"#/components/schemas/tool.toolCall"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tool.toolResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tool","x-public":true,"x-tool":true}},"/v1/tool/catalog":{"get":{"operationId":"get_tool_catalog","summary":"Lists the MCP servers the public registries publish, as we hold them: our canonical copy of registry.modelcontextprotocol.io, plus what we decided about each entry.","description":"Lists the MCP servers the public registries publish, as we hold\nthem: our canonical copy of registry.modelcontextprotocol.io, plus what we\ndecided about each entry.\n\nThis is the SHELF an org picks from. A listing with a streamable-http endpoint\ncan be enabled as-is — POST /v1/tool/mcp/servers with its id — and its tools then\njoin the org's tool plane and the fleet's MCP server. A listing that only ships a\nstdio package needs a process to run it, which is why the transports are on\nevery entry rather than implied.\n\nHidden entries are absent: they are the ones we took off the shelf. A platform\nSuperAdmin sees them, because the same query answers \"what is on the shelf\" and\n\"what is in the catalog\" and two queries would drift apart.\n\nIt is PAGED — 50 by default, 200 at most. The public registry publishes tens of\nthousands of servers, so an unbounded answer is a twenty-megabyte response and a\nstorefront that renders in a minute. total is the whole match, not the page.\n\nIt needs no credential: the shelf is a copy of public registries, the same for\nevery org, and a storefront shows it to a visitor before anyone signs in.","tags":["tool"],"parameters":[{"name":"q","in":"query","required":false,"description":"Q matches the name, title or description, case-insensitively.","schema":{"type":"string"}},{"name":"featured","in":"query","required":false,"description":"Featured keeps only the listings we put on the front of the shelf, and only\nwhen it is exactly the string \"true\".","schema":{"type":"string"}},{"name":"official","in":"query","required":false,"description":"Official keeps only the vendors' OWN servers — not third-party copies of\nthem — and only when it is exactly the string \"true\".","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit bounds the page: default 50, maximum 200. A value that is not a\npositive integer reads as the default.","schema":{"format":"int64","type":"integer"}},{"name":"offset","in":"query","required":false,"description":"Offset skips that many listings.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tool.mcpCatalog"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"security":[],"x-app":"tool","x-public":true,"x-tool":true}},"/v1/tool/catalog/{id}":{"get":{"operationId":"get_tool_catalog_by_id","summary":"Returns one catalog entry in full: the publisher's description, its repository and site, every package form with the runtime that launches it, and every hosted endpoint.","description":"Returns one catalog entry in full: the publisher's description, its\nrepository and site, every package form with the runtime that launches it, and\nevery hosted endpoint. It is what a branding page renders, and what tells a\ncaller whether the listing can be enabled here and now (a streamable-http\nremote) or needs somewhere to run first (a stdio package).\n\nA HIDDEN listing is not served to an org — a shelf that renders what it does\nnot list would be a way around the shelf — but is served to a SuperAdmin, who\nis the one deciding whether to put it back. Like the shelf, it needs no\ncredential.","tags":["tool"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the listing, from the path. It is the publisher's reverse-DNS name\nwith its one slash written as an underscore — \"com.stripe_mcp\".","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tool.MCPListing"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"security":[],"x-app":"tool","x-public":true,"x-tool":true}},"/v1/tool/kit":{"get":{"operationId":"get_tool_kit","summary":"Answers the caller's kit: what their coding runs carry of the org's tool plane.","description":"Answers the caller's kit: what their coding runs carry of the org's tool\nplane. Skills are the documents of those an admin of the org activated; servers\nare those an admin registered, each by its id with the tools of it an admin\nactivated — never an address or a credential, which stay on the plane. Both\nleave out what the caller muted, and muted names it. It is the one read a run\nmakes, so what it answers is what the caller's runs carry.","tags":["tool"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tool.Kit"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tool","x-public":true,"x-tool":true},"put":{"operationId":"put_tool_kit","summary":"Mutes and unmutes names of the org's kit for the caller's own runs, and answers the caller's kit after.","description":"Mutes and unmutes names of the org's kit for the caller's own runs, and\nanswers the caller's kit after. The layer only narrows: a name the org's kit\ndoes not carry is refused 400, since muting it would say nothing, and unmuting\nnever gives the caller more than an admin put in place. It is the caller's own,\nso any member may write it. More than 256 names is refused 413.","tags":["tool"],"requestBody":{"content":{"application/json":{"example":{"mute":["skill_deploy","linear"],"unmute":[]},"schema":{"$ref":"#/components/schemas/tool.muteReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tool.Kit"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tool","x-public":true,"x-tool":true}},"/v1/tool/mcp/servers":{"get":{"operationId":"get_tool_mcp_servers","summary":"Lists the external MCP servers the caller's org has registered.","description":"Lists the external MCP servers the caller's org has registered.\nEach record carries the URL and the name of the header its credential is\ninjected into; the credential VALUE lives only in KMS and is never returned,\nso hasSecret is the whole of what this surface says about it. Each also says\nwhether its tools could be listed — status, a reason when they could not, and\nhow many there are — so a server that contributes nothing says why.\n\nThe whole URL is answered to an admin of the org or a SuperAdmin, who register\nservers. A member is answered its scheme and host: which server it is, and not\na path or query an admin may have put a key in.","tags":["tool"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tool.mcpServerList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tool","x-public":true,"x-tool":true},"post":{"operationId":"post_tool_mcp_servers","summary":"Gives the caller's org one more external MCP server, so its tools join the org's tool plane and the fleet's MCP server.","description":"Gives the caller's org one more external MCP server, so its tools\njoin the org's tool plane and the fleet's MCP server. It is the ONE way an org\ngains a server, whether it typed the URL in or enabled a catalog listing: both\nwrite the SAME record, and `source` says which it was. A second registration\npath would be a second place for a server to exist, and then a second place to\nforget to check the credential.\n\nThe credential VALUE is sealed in KMS under a per-org ref; the row keeps only\nthe URL, the header name to inject it into, and a has-secret flag — so a secret\nwith no KMS configured is refused 503 rather than stored in the clear. The URL\nis SSRF-validated here and re-checked by the dialer at connect time, which is\nthe DNS-rebinding defense.\n\nEnabling a listing the org already enabled REVISES that server rather than\nadding a near-duplicate beside it, so a retried enable is the same one server.\nAnswers 201 with the stored record.\n\nA server and the tools of it the org activates are carried into every agent run\nin the org, so registering one — or revising one, credential included — takes\nan admin of the org or a SuperAdmin; a member is refused 403. The registration\nis on the org's audit trail before it is made, and one the trail cannot record\nis refused 503.","tags":["tool"],"requestBody":{"content":{"application/json":{"example":{"authHeader":"Authorization","listing":"com.stripe_mcp","secret":"Bearer …"},"schema":{"$ref":"#/components/schemas/tool.createServerReq"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tool.MCPServer"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tool","x-public":true,"x-tool":true}},"/v1/tool/mcp/servers/{id}":{"delete":{"operationId":"delete_tool_mcp_servers_by_id","summary":"Deregisters one of the caller org's external MCP servers, so its tools leave the registry.","description":"Deregisters one of the caller org's external MCP servers, so its\ntools leave the registry. Scoped to the caller's org, so an id belonging to\nanother tenant is a 404 and not a delete. Answers 204 with no body; a server\nthis org does not have is 404. Like registering one it takes an admin of the\norg or a SuperAdmin, and is on the org's audit trail before it is made.","tags":["tool"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the server to deregister, from the path.","schema":{"type":"string"}}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tool","x-public":true,"x-tool":true}},"/v1/tool/plugins":{"get":{"operationId":"get_tool_plugins","summary":"Reports what this deployment actually mounted: every subsystem the composition root declared and whether it is switched on.","description":"Reports what this deployment actually mounted: every subsystem the\ncomposition root declared and whether it is switched on. A plugin here is\nMOUNTED CODE that extends the deployment's own surface — not a tool an agent\ncalls — so this is an inventory and not a tool source. It is read off the same\nboot snapshot every traced request resolves its subsystem label against, so it\ncannot drift from what is serving. Enabled-only by default, because a caller\nasking what this deployment can do wants what is running; ?all=true adds the\nconfigured-but-off ones.","tags":["tool"],"parameters":[{"name":"all","in":"query","required":false,"description":"All includes the configured-but-disabled subsystems too, but only when it is\nexactly the string \"true\". Otherwise only the running ones are reported.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tool.pluginMountList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tool","x-public":true,"x-tool":true}},"/v1/tool/plugins/authored":{"get":{"operationId":"get_tool_plugins_authored","summary":"Lists the plugins the caller's org BUILT, newest first, each with the TypeScript as authored.","description":"Lists the plugins the caller's org BUILT, newest first,\neach with the TypeScript as authored. That is a different set with a different\nlifecycle from GET /v1/tool/plugins, which reports the subsystems this deployment\nmounted. The bundled CommonJS the runtime executes is never included, and\nneither is any credential — a plugin names the connectors provider it needs and\nreads the credential from ctx.auth at run time.","tags":["tool"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tool.authoredPluginList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tool","x-public":true,"x-tool":true}},"/v1/tool/plugins/authored/{id}":{"delete":{"operationId":"delete_tool_plugins_authored_by_id","summary":"Removes one of the caller org's built plugins, so the runtime can no longer load it.","description":"Removes one of the caller org's built plugins, so the\nruntime can no longer load it. Scoped to the caller's org, so an id belonging\nto another tenant answers 404 and is not deleted.","tags":["tool"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the plugin to remove, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tool.pluginDeleted"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tool","x-public":true,"x-tool":true}},"/v1/tool/plugins/build":{"post":{"operationId":"post_tool_plugins_build","summary":"Builds and stores one plugin for the caller's org.","description":"Builds and stores one plugin for the caller's org. The 201 carries\nthe bundle's size, whether a model wrote the source, and the plugin as stored.\n\nPost `source` to build TypeScript as-is, or `spec` — an OpenAPI document or\nplain prose describing the endpoints — to have one generated; the generated\nsource comes back in the answer, so a caller reads what will run before it\nruns. Exactly one of the two, and `name` must be one lowercase path segment;\nboth or neither is 400.\n\nCOMPILING IS THE GATE. The source goes through the same pipeline the committed\nconnectors do — esbuild to one CommonJS program, then compiled in the goja\nruntime that will actually execute it — and anything that fails is rejected and\nNEVER stored. So a plugin in the store is one this deployment has already\nloaded once, not one a model claimed was fine. A failed build answers 422\ncarrying the diagnostics a caller needs to fix it: the bundler's error\n(`detail`), the source that failed, and whether the model wrote it.\n\nCREDENTIALS ARE NOT PART OF A PLUGIN. A plugin names the connectors `provider`\nit needs and reads that credential from `ctx.auth` at run time, under KMS\ncustody. Source that carries something key-shaped is REFUSED rather than\nsilently persisted — a scrubbed key looks like it worked.","tags":["tool"],"requestBody":{"content":{"application/json":{"example":{"name":"acme","provider":"acme","spec":"POST /v1/things creates a thing"},"schema":{"$ref":"#/components/schemas/tool.buildRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tool.buildOut"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tool","x-public":true,"x-tool":true}},"/v1/tool/skills":{"get":{"operationId":"get_tool_skills","summary":"Lists the skills the caller's org can reach — the brand's embedded catalogue plus the org's own authored ones — with each one's activation flag.","description":"Lists the skills the caller's org can reach — the brand's embedded\ncatalogue plus the org's own authored ones — with each one's activation flag.\nA skill is discovery and activation metadata attached to an agent, never called\ndirectly, so every entry here is non-dispatchable. It is GET /v1/tool narrowed\nto one source, not a second store: a name a caller sees here is the same entry,\nwith the same activation state, that discovery reports.","tags":["tool"],"parameters":[{"name":"activated","in":"query","required":false,"description":"Activated keeps only the tools activated for the caller's org and project,\nand only when it is exactly the string \"true\".","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tool.sourceToolList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tool","x-public":true,"x-tool":true},"post":{"operationId":"post_tool_skills","summary":"Adds or revises one of the caller org's own skills, and answers 201 with the stored record.","description":"Adds or revises one of the caller org's own skills, and answers 201\nwith the stored record. The id is derived from the name, so writing the same\nname again REVISES that skill rather than accumulating near-duplicates that\nwould then collide in the registry. An org's skills are private to it by\nconstruction — they live in a different store from the brand's embedded\ncatalogue and have no path into the public gallery — and a brand skill always\nwins a name collision against an org's.\n\nAn activated skill is carried into every agent run in the org, so writing one\ntakes an admin of the org or a SuperAdmin; a member is refused 403. The write is\non the org's audit trail before it is made, and one the trail cannot record is\nrefused 503.","tags":["tool"],"requestBody":{"content":{"application/json":{"example":{"content":"# Triage\n…","description":"how we triage","name":"triage"},"schema":{"$ref":"#/components/schemas/tool.skillIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tool.skillWritten"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tool","x-public":true,"x-tool":true}},"/v1/tool/skills/authored":{"get":{"operationId":"get_tool_skills_authored","summary":"Lists the caller org's OWN skills with their SKILL.md bodies.","description":"Lists the caller org's OWN skills with their SKILL.md\nbodies. GET /v1/tool/skills is the registry view — the brand's catalogue plus this\norg's, with activation flags and no bodies; this is the EDITABLE set, so it\ncarries the content that view omits and nothing the org did not write.","tags":["tool"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tool.authoredSkillList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tool","x-public":true,"x-tool":true}},"/v1/tool/skills/{id}":{"delete":{"operationId":"delete_tool_skills_by_id","summary":"Removes one of the caller org's authored skills.","description":"Removes one of the caller org's authored skills. Scoped to the\ncaller's org, so an id belonging to another tenant is never reached. Removing\nwhat is not there is not an error — the caller's intent is \"gone\", and it is.\nLike writing one it takes an admin of the org or a SuperAdmin, and is on the\norg's audit trail before it is made.","tags":["tool"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the skill to remove, from the path. It is the skill's name.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/tool.skillDeleted"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"tool","x-public":true,"x-tool":true}},"/v1/train/artifacts":{"get":{"operationId":"get_train_artifacts","summary":"Answers the org's objects — its uploads and its jobs' outputs, one per sha256 — with what produced each, whether it is published and when retention deletes it.","description":"Answers the org's objects — its uploads and its jobs'\noutputs, one per sha256 — with what produced each, whether it is published and\nwhen retention deletes it.","tags":["train"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.objectsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true},"post":{"operationId":"post_train_artifacts","summary":"Records rows the org is about to upload, named by the SHA-256 of their bytes, and answers the same grant an executor's artifact gets: a presigned PUT S3 accepts only with that checksum and length, encrypted under the org's key — a PUT per 64 MiB part over 64 MiB — or stored: true when the org already holds those bytes.","description":"Records rows the org is about to upload, named by the\nSHA-256 of their bytes, and answers the same grant an executor's artifact\ngets: a presigned PUT S3 accepts only with that checksum and length, encrypted\nunder the org's key — a PUT per 64 MiB part over 64 MiB — or stored: true when\nthe org already holds those bytes. A job names them as `dataset.uri`\n`artifact:\u003csha256\u003e`, and its create reads the upload back before it is\naccepted. Storage is billed by the GB-month while the org keeps them, so an\nupload is refused 402/503 when the uploader's wallet cannot pay a month of\nkeeping these bytes with what it already keeps in the org and what the org has\npending.","tags":["train"],"requestBody":{"content":{"application/json":{"example":{"kind":"dataset","name":"tickets","sha256":"…","size":1048576},"schema":{"$ref":"#/components/schemas/train.uploadIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.registerOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/train/artifacts/{sha256}":{"delete":{"operationId":"delete_train_artifacts_by_sha256","summary":"Deletes one of the org's objects — an upload or a job's output — from the store: every artifact naming it then reads deleted, and its storage is no longer billed.","description":"Deletes one of the org's objects — an upload or a job's\noutput — from the store: every artifact naming it then reads deleted, and its\nstorage is no longer billed. A published object is 409 published, and one a\njob that has not ended reads or produced is 409 in_use. Another org's sha256\nis not found, exactly as an unknown one is.","tags":["train"],"parameters":[{"name":"sha256","in":"path","required":true,"description":"SHA256 names the object, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.deletedOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true},"get":{"operationId":"get_train_artifacts_by_sha256","summary":"Answers one of the org's objects, as the list does, with an address that fetches its bytes for ten minutes once it is stored: how an executor reads an `artifact:\u003csha256\u003e` dataset its job names, and how the org downloads what it uploaded.","description":"Answers one of the org's objects, as the list does, with an\naddress that fetches its bytes for ten minutes once it is stored: how an\nexecutor reads an `artifact:\u003csha256\u003e` dataset its job names, and how the org\ndownloads what it uploaded. Another org's sha256 is not found, exactly as an\nunknown one is.","tags":["train"],"parameters":[{"name":"sha256","in":"path","required":true,"description":"SHA256 names the object, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.Object"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/train/clients":{"get":{"operationId":"get_train_clients","summary":"Answers the org's live clients as the engine reports them.","description":"Answers the org's live clients as the engine reports them. A\nclient the engine no longer holds is dropped.","tags":["train"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.clientList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true},"post":{"operationId":"post_train_clients","summary":"Loads base_model on the engine with a LoRA adapter and answers the client, loading; poll it until ready.","description":"Loads base_model on the engine with a LoRA adapter and answers\nthe client, loading; poll it until ready. The wire is the engine's own\ncreate → forward_backward → optim_step → sample → save_weights loop, so a loop\nwritten against the engine runs here with only the path changed. The\ncapability fields are validated as a job's are: adaptation is lora, protect is\nrefused, and kai is not a client base. A client holds a model in the memory every\norg's inference shares, so only a SuperAdmin creates one until the engine isolates\norgs. An org holds at most TRAIN_CLIENTS live clients and the engine at most\nTRAIN_ENGINE_CLIENTS across every org; past that the answer is 503 engine_full.","tags":["train"],"requestBody":{"content":{"application/json":{"example":{"base_model":"HuggingFaceTB/SmolLM2-135M","lora_config":{"alpha":32,"rank":16}},"schema":{"$ref":"#/components/schemas/train.createClientIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/train/clients/{id}":{"delete":{"operationId":"delete_train_clients_by_id","summary":"Drops one of the org's clients and frees its memory on the engine.","description":"Drops one of the org's clients and frees its memory on the engine.","tags":["train"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID names the client.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true},"get":{"operationId":"get_train_clients_by_id","summary":"Answers one of the org's clients with its loss history.","description":"Answers one of the org's clients with its loss history.","tags":["train"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID names the client.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/train/clients/{id}/forward_backward":{"post":{"operationId":"post_train_clients_by_id_forward_backward","summary":"Accumulates the gradients of a batch on the client.","description":"Accumulates the gradients of a batch on the client.","tags":["train"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID names the client.","schema":{"type":"string"},"example":"tc-…"}],"requestBody":{"content":{"application/json":{"example":{"data":[{"completion":"4","prompt":"2+2="}],"id":"tc-…"},"schema":{"$ref":"#/components/schemas/train.forwardIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/train/clients/{id}/optim_step":{"post":{"operationId":"post_train_clients_by_id_optim_step","summary":"Applies the optimizer to the accumulated gradients.","description":"Applies the optimizer to the accumulated gradients.","tags":["train"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID names the client.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.optimIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/train/clients/{id}/sample":{"post":{"operationId":"post_train_clients_by_id_sample","summary":"Decodes from the client's current weights.","description":"Decodes from the client's current weights.","tags":["train"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID names the client.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.sampleIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/train/clients/{id}/save_weights":{"post":{"operationId":"post_train_clients_by_id_save_weights","summary":"Writes the client's adapter on the engine.","description":"Writes the client's adapter on the engine.","tags":["train"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID names the client.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.saveIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/train/jobs":{"get":{"operationId":"get_train_jobs","summary":"Answers the org's jobs, newest first, narrowed by ?status=.","description":"Answers the org's jobs, newest first, narrowed by ?status=.","tags":["train"],"parameters":[{"name":"status","in":"query","required":false,"description":"Status narrows to one status.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit bounds the answer; default 50, at most 500.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.jobsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true},"post":{"operationId":"post_train_jobs","summary":"Creates a job that teaches base_model one capability: the data, the objective, how the trained parameters are represented (adaptation), what they must not damage and by how much (protect), where it runs and how far (resources), the suites it is judged on (evaluation) and what it produces (output).","description":"Creates a job that teaches base_model one capability: the data,\nthe objective, how the trained parameters are represented (adaptation), what they\nmust not damage and by how much (protect), where it runs and how far\n(resources), the suites it is judged on (evaluation) and what it produces\n(output). It is validated in one order — shape, base, the agreement of the\nartifacts it names, then each choice against what that base runs today — and\nthe first failure is the answer: a 400 problem carrying `code`, and `supported`\nwhen a choice is not run for that base. A dataset the org uploaded\n(`artifact:\u003csha256\u003e`) is read back here if it has not been. A job that names\nthe org's machines is queued for them; one that names none is queued for\nHanzo's executor, charged to the caller's wallet by the device-second inside its\nbudget, which it must name, and is refused 402 when that wallet cannot hold its\nfirst window on its own. An org has at most 64 jobs that have not ended (409\njob_limit). auto is resolved here and `adaptation.chose` says to what and why.","tags":["train"],"requestBody":{"content":{"application/json":{"example":{"adaptation":{"mode":"full"},"base_model":"kai","dataset":{"uri":"stage:a11"},"evaluation":{"suites":["labels"]},"output":{"kind":"capability","name":"open-labels"},"protect":{"budget":{"accuracy":0.02,"ece":0.03},"distillation":true,"projection":{"strength":0.5},"suites":["typed_decisions"]},"resources":{"machines":["dgx"],"steps":2000},"revision":"a7"},"schema":{"$ref":"#/components/schemas/train.Spec"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.Job"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/train/jobs/claim":{"post":{"operationId":"post_train_jobs_claim","summary":"ClaimTrainTask is an executor's long poll for work: it names the machine it runs on, its devices and what its build runs, and is answered, within 25 seconds, one task it can run — a job's lead first; a join once its lead has said where it coordinates — or 204.","description":"ClaimTrainTask is an executor's long poll for work: it names the machine it\nruns on, its devices and what its build runs, and is answered, within 25\nseconds, one task it can run — a job's lead first; a join once its lead has\nsaid where it coordinates — or 204. The answer carries the task's lease, once,\nwhich every report for the task must carry; the device-seconds held for it;\nand how often it must report. An executor acting as a principal of an org\nclaims that org's tasks placed on its machine and can claim no other org's. A\nplatform claim (SuperAdmin alone) is Hanzo's executor: it is answered a task of\nany org's job that names no machines, its first window held against the job's\npayer first, and the claim is put on the platform's audit trail.","tags":["train"],"requestBody":{"content":{"application/json":{"example":{"bases":["kai"],"devices":["cuda"],"machine":"dgx","supports":{"adaptations":["full","readout"],"outputs":["capability","checkpoint"],"protect":["projection","distillation"],"terms":["pairwise_margin","hard_margin","consistency"]}},"schema":{"$ref":"#/components/schemas/train.claimIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.Assignment"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/train/jobs/{id}":{"get":{"operationId":"get_train_jobs_by_id","summary":"Answers one job: what it asked for, its status and tasks, its artifacts, its result and verdict, and whether it was published.","description":"Answers one job: what it asked for, its status and tasks, its\nartifacts, its result and verdict, and whether it was published. A job of\nanother org is not found, exactly as an unknown id is.","tags":["train"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID names the job.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.Job"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/train/jobs/{id}/artifacts":{"get":{"operationId":"get_train_jobs_by_id_artifacts","summary":"Answers a job's artifacts — checkpoint, capability, lora, basis or merged, each named by the SHA-256 of its bytes — with a download address that lives ten minutes for each one stored.","description":"Answers a job's artifacts — checkpoint, capability, lora,\nbasis or merged, each named by the SHA-256 of its bytes — with a download\naddress that lives ten minutes for each one stored. One deleted, by the org or\nby retention, reads deleted and has none.","tags":["train"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID names the job.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.artifactsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true},"post":{"operationId":"post_train_jobs_by_id_artifacts","summary":"Records an output its executor is about to store, named by the SHA-256 of its bytes, and answers a presigned PUT for exactly that object under the org's prefix — S3 accepts it only with the checksum and encrypts it under the org's key — or, over 64 MiB, a presigned PUT per 64 MiB part, or stored: true when the org already holds those bytes.","description":"Records an output its executor is about to store, named by\nthe SHA-256 of its bytes, and answers a presigned PUT for exactly that object\nunder the org's prefix — S3 accepts it only with the checksum and encrypts it\nunder the org's key — or, over 64 MiB, a presigned PUT per 64 MiB part, or\nstored: true when the org already holds those bytes. The executor then reports\nan artifact event naming it, and the object is read back, those bytes and\nsealed under the org's key, before it counts as stored.","tags":["train"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID names the job, from the path.","schema":{"type":"string"},"example":"job_0123456789abcdef"}],"requestBody":{"content":{"application/json":{"example":{"id":"job_0123456789abcdef","kind":"capability","lease":"trl_…","name":"open-labels","sha256":"…","size":1048576,"task":"tsk_0123456789abcdef"},"schema":{"$ref":"#/components/schemas/train.registerIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.registerOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/train/jobs/{id}/cancel":{"post":{"operationId":"post_train_jobs_by_id_cancel","summary":"Stops a job that has not ended.","description":"Stops a job that has not ended. Its executors learn it on their\nnext report and stop their trainers; a job that already ended is a 409.","tags":["train"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID names the job.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.Job"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/train/jobs/{id}/events":{"get":{"operationId":"get_train_jobs_by_id_events","summary":"Answers a job's events after a cursor — status changes, the coordinator's address, metrics, log lines, artifacts and the result — waiting up to `wait` seconds for the first new one, so a caller following a run holds one request at a time.","description":"Answers a job's events after a cursor — status changes, the\ncoordinator's address, metrics, log lines, artifacts and the result — waiting up\nto `wait` seconds for the first new one, so a caller following a run holds one\nrequest at a time.","tags":["train"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID names the job.","schema":{"type":"string"}},{"name":"after","in":"query","required":false,"description":"After is the last seq the caller holds; 0 reads from the start.","schema":{"format":"int64","type":"integer"}},{"name":"wait","in":"query","required":false,"description":"Wait is how many seconds to hold the request for a first new event, at most 25.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.eventsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true},"post":{"operationId":"post_train_jobs_by_id_events","summary":"ReportTrainTask is an executor's report for the task it holds: status changes, the lead's coordinator address, metrics, log lines, stored artifacts and, last, the lead's result.","description":"ReportTrainTask is an executor's report for the task it holds: status changes,\nthe lead's coordinator address, metrics, log lines, stored artifacts and, last,\nthe lead's result. It must carry the task's lease; a report under any other is\n409 lease_lost and the executor stops. A report with no events is a heartbeat,\ndue at least every `report` seconds the claim answered — a task silent for the\nlease's life is lost, and a lost lead fails its job. Each report meters the\ntask by the clock: its devices times the seconds since it was claimed, no more\nthan is held, charged to the job's payer for a job Hanzo runs. The answer says\nhow many device-seconds are held now. When the next window cannot be held and\nwhat is held runs low, the job ends stopped and the answer says cancel: kill\nthe trainer and report nothing more. Once the job has ended a report records\nnothing and answers the job's status; cancel says it was cancelled or stopped.","tags":["train"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID names the job, from the path.","schema":{"type":"string"},"example":"job_0123456789abcdef"}],"requestBody":{"content":{"application/json":{"example":{"events":[{"name":"nll","step":100,"type":"metric","value":0.66}],"id":"job_0123456789abcdef","lease":"trl_…","task":"tsk_0123456789abcdef"},"schema":{"$ref":"#/components/schemas/train.reportIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.reportOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/train/jobs/{id}/metrics":{"get":{"operationId":"get_train_jobs_by_id_metrics","summary":"Answers a job's metric series — loss, throughput and each validation suite's numbers as the executor reported them — one per name, each point [step, value, unix seconds].","description":"Answers a job's metric series — loss, throughput and each\nvalidation suite's numbers as the executor reported them — one per name, each\npoint [step, value, unix seconds].","tags":["train"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID names the job.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.metricsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/train/jobs/{id}/publish":{"post":{"operationId":"post_train_jobs_by_id_publish","summary":"Publishes a job's output under a name.","description":"Publishes a job's output under a name. Only a succeeded job's\noutput is publishable; a rejected one broke its regression budget and needs\nforce, which the record keeps. The output must be stored. A capability is\npublished with its route — the question keys it answers and, per key, the\nexact question (`{\"type\": \"choice\"|\"score\"|\"noul\", \"labels\": [...]}`) — the\nbase SHA-256 its result names, and its form: head for a readout, full for\nevery other adaptation. A route that claims a question another of the org's\npublished capabilities claims is 409 route_conflict. A name the org already\npublished moves to this job. A head's tar is copied first to the serving store,\nthe models bucket's capabilities/\u003corg\u003e/\u003csha256\u003e, where the decision service\nfetches it; ai attaches the org's published capabilities to its decisions.","tags":["train"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID names the job.","schema":{"type":"string"},"example":"job_0123456789abcdef"}],"requestBody":{"content":{"application/json":{"example":{"id":"job_0123456789abcdef","name":"triage","route":{"keys":["topic"],"options":{"topic":{"labels":["billing","bug","other"],"type":"choice"}}}},"schema":{"$ref":"#/components/schemas/train.publishIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.Job"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/train/models":{"get":{"operationId":"get_train_models","summary":"Answers each base the caller can train today, in one shape: the base, the methods it trains by (adaptations), where it runs (runs: Hanzo's devices or the org's machines) with what one device-second costs there in nano-USD, then the resources that run it (nouns), its executor and devices, and the protections, objective terms, outputs and dataset schemes it takes.","description":"Answers each base the caller can train today, in one shape:\nthe base, the methods it trains by (adaptations), where it runs (runs: Hanzo's\ndevices or the org's machines) with what one device-second costs there in\nnano-USD, then the resources that run it (nouns), its executor and devices, and\nthe protections, objective terms, outputs and dataset schemes it takes. Bases\nare ordered by name, a base's runs by place, then price. A create is validated\nagainst the same rows, and a noun the caller cannot start is not listed: the\nengine's clients are a SuperAdmin's.","tags":["train"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/train.catalog"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"train","x-public":true,"x-tool":true}},"/v1/translate":{"post":{"operationId":"post_translate","summary":"Translate a string or a batch into one target language","description":"Returns one translation per input string, in input order, each carrying where it sits on the review ladder and whether it came from your memory rather than an engine — plus a usage block of REAL counts (strings, cached, translated, failed, and the source characters of the strings an engine translated). Send `text` for one string or `batch` for many, never both. When you name no `source`, the detected one is reported back.\n\nTHE TRANSLATION MEMORY IS CONSULTED FIRST AND IT IS NORMATIVE, NOT A CACHE. Every string keys on (source text, declared source language, target, glossary version, tier, format, model); a hit is returned VERBATIM and never re-translated, which is what makes a locale rebuild idempotent under a non-deterministic model and the bill proportional to what actually changed. The same text through another model or another format is another entry. A string translated with its source detected also answers a later call that declares one, so declaring `source` never throws away work done without it; one translated under a declared source answers only that source. Misses go to the engine and are written back at state `machine`. Editing a glossary term changes the key, so a stale rendering can never be served.\n\nIT CANNOT TRAMPLE REVIEWED WORK. A write from this route may create an entry or refresh one still at `machine`, and nothing else — a string a human moved to approved or published through the memory review lane survives every rebuild, and comes back here unchanged. The memory is the caller's OWN org's, a separate store per org: the source text you send is customer content and lands nowhere else. Read it back or review it at /v1/translate/memory.\n\n`tier` picks the engine and defaults to quality — the model plane, which carries context, terminology and tone, and which bills its own tokens, so nothing is charged twice here. `bulk` is the high-volume engine and is metered HERE, on the source characters of the strings it translated: a fully-cached rebuild, or a string that failed, costs zero. BULK NEVER FALLS BACK TO QUALITY — on a deployment that does not serve it the answer is 503 for that tier, so a caller is never quietly served, or charged, at a tier it did not ask for. A bulk request beyond its balance is refused with the nested {\"error\":{\"code\",\"message\"}} body at 402/503.\n\n`model` names the model the quality tier runs on, through the same metered model plane as the default (enso-auto), which decides whether your org may use it exactly as it does for chat. That is how an org points translation at a model it serves itself, on its own linked GPU say: by the alias it registered for it. A name from an upstream model family is rewritten to the default before it runs, so a model of your own must be named by your org's alias; the reply's `model` names the one it runs on. `model` with `tier: bulk` is 400.\n\n`target` IS CHECKED FOR SHAPE, NOT FOR SUPPORT: anything BCP-47-shaped is accepted (`es`, `pt-BR`), anything else is 400. There is no unsupported-language error — a well-formed tag no engine can actually render is passed straight through, and whatever comes back is what gets stored and returned. `format` (text, html, markdown) tells the engine what markup to preserve; `glossary` fixes terms verbatim.\n\nA BATCH IS TRANSLATED IN PARTS of about 8 KB, each its own completion with a ceiling sized to it. A part that comes back cut short (any finish other than stop), malformed, or covering the wrong number of strings is asked again one string at a time. Every translation must keep its source's shape: the same {placeholders}, printf conversions in the same order, the same ICU arguments and selectors with an other branch (the words in their branches are translated), the same tags with the same attributes (alt, title, aria-label and placeholder are words), the same link targets and URLs; a string whose shape moved is asked once more. A string that still fails comes back with `error` naming what went wrong (a lost placeholder, an added URL) and no text, is not stored, and fails nothing else.\n\nTHE WORK IS BOUNDED: at most two model calls per part, one held for every part still to come, a stop after two parts in a row return nothing, 90 seconds per call, and a stop when the caller disconnects. Strings the call did not reach come back with `error` saying why. What came back is stored, so sending the batch again asks only for the rest. When no string at all can be returned, or the engine fails, the answer is 502 with code `translate_failed`.\n\nRequires a validated principal — 401 without one, and the org is always that principal's. At most 512 strings per call and 32768 characters per string (400 past either), and 262144 characters in all (413 past it: split the batch).","tags":["translate"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Brief"}}}},"responses":{"2XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Delivery"}}},"description":"Success"}},"x-app":"translate","x-public":true}},"/v1/translate/memory":{"get":{"operationId":"get_translate_memory","summary":"Returns the org's own translation-memory entries, newest first, optionally narrowed to one target language and/or one position on the review ladder.","description":"Returns the org's own translation-memory entries, newest first, optionally\nnarrowed to one target language and/or one position on the review ladder. It is\nthe review lane's read: what a human reviewer works through.\n\nThe org is ALWAYS the validated principal's org, never a request field, so one\ntenant can never read another's memory — the entries hold customer source text.","tags":["translate"],"parameters":[{"name":"target","in":"query","required":false,"description":"Target narrows to one target language tag (BCP-47, e.g. \"es\" or \"pt-BR\").","schema":{"type":"string"}},{"name":"state","in":"query","required":false,"description":"State narrows to one position on the review ladder: machine, suggested,\napproved or published.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned. Non-positive or unparseable means the server\ndefault (200); the ceiling is 1000.","schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/translate.MemoryPage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"translate","x-public":true,"x-tool":true},"put":{"operationId":"put_translate_memory","summary":"Records a human decision on one translation-memory entry, and returns the entry as stored.","description":"Records a human decision on one translation-memory entry, and returns the\nentry as stored. A human write always wins over the stored value, and once it lands\nat approved or published no machine write can move it again — which is what makes a\nlocale rebuild safe to run against reviewed work.\n\nThe org is ALWAYS the validated principal's org, never a request field, so a review\ncan only ever land in the caller's own memory.","tags":["translate"],"requestBody":{"content":{"application/json":{"example":{"source":"Hello","state":"approved","target":"es","text":"Hola"},"schema":{"$ref":"#/components/schemas/translate.ReviewRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/translate.MemoryEntry"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"translate","x-public":true,"x-tool":true}},"/v1/treasury":{"get":{"operationId":"get_treasury","summary":"Returns the reserve fund's health and the current revenue-share policy for any validated caller.","description":"Returns the reserve fund's health and the current revenue-share\npolicy for any validated caller. It is a TRANSPARENCY view — a partner or\nauthor can see that the pool backing their payouts is solvent — and NOT per-org\nmoney, which is the customer's own commerce balance at /v1/billing/balance. The\npolicy is read-only here; only a SuperAdmin sets it.","tags":["treasury"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/treasury.TreasuryReport"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"treasury","x-public":true,"x-tool":true}},"/v1/treasury/accounts":{"get":{"operationId":"get_treasury_accounts","summary":"Returns the ledger accounts the caller may see, with their balances.","description":"Returns the ledger accounts the caller may see, with their\nbalances. It is tenant-isolated SERVER-SIDE: an ordinary caller sees ONLY\naccounts under its own \"org:\u003ctenant\u003e:\" prefix, never house accounts and never\nanother tenant's. A SuperAdmin may widen with ?scope=house (the reserve,\nrevenue and payout house accounts) or ?org=\u003ctenant\u003e — the only way to cross the\ntenant boundary, and only for platform sudo. The answer is honestly empty until\na tenant has ledger postings.","tags":["treasury"],"parameters":[{"name":"scope","in":"query","required":false,"description":"Scope is \"house\" to read the reserve/revenue/payout house accounts. SuperAdmin only.","schema":{"type":"string"}},{"name":"org","in":"query","required":false,"description":"Org names another tenant to read. SuperAdmin only; ignored when scope=house.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/treasury.accountsOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"treasury","x-public":true,"x-tool":true}},"/v1/trust":{"get":{"operationId":"get_trust","summary":"Reads YOUR organization's whole trust centre, including the addresses of your own gated documents.","description":"Reads YOUR organization's whole trust centre, including the addresses of your\nown gated documents. Same shape as the published endpoint; the difference is that\nthis one is resolved from your validated bearer and shows you your own\nartifacts.","tags":["trust"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/trust.centre"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"trust","x-public":true,"x-tool":true}},"/v1/trust/controls":{"get":{"operationId":"get_trust_controls","summary":"Lists every control your organization publishes, with the counts.","description":"Lists every control your organization publishes, with the counts.\n\nA control names what it asserts, the mechanism behind it, the repository and\nfile where that mechanism is enforced, how it is verified, and the framework\nclauses it maps to. Status is automated, partial or absent — and an absent one\nstill names the clause it would satisfy, which is a roadmap, while never\nmoving a coverage number.","tags":["trust"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/trust.controlList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"trust","x-public":true,"x-tool":true}},"/v1/trust/controls/{id}":{"get":{"operationId":"get_trust_controls_by_id","summary":"Reads one control by id.","description":"Reads one control by id.","tags":["trust"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the control's id, dotted lowercase — \"iam.pkce.s256\".","schema":{"type":"string"},"example":"iam.pkce.s256"}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"trust","x-public":true,"x-tool":true}},"/v1/trust/coverage":{"get":{"operationId":"get_trust_coverage","summary":"Reads coverage: per framework, how many clauses have an automated control behind them, how many are partial, and how many have none — each carrying the unit it is counted in, because \"12 of 20\" is not a fact until you know what the 20 are.","description":"Reads coverage: per framework, how many clauses have an automated control\nbehind them, how many are partial, and how many have none — each carrying the\nunit it is counted in, because \"12 of 20\" is not a fact until you know what\nthe 20 are.\n\nNothing here is a verdict. There is no boolean, and a control that only a\nperson has read counts one rung weaker than it claims to be, because only a\ncheck that can FAIL is evidence.","tags":["trust"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/trust.trustCoverage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"trust","x-public":true,"x-tool":true}},"/v1/trust/coverage/{framework}":{"get":{"operationId":"get_trust_coverage_by_framework","summary":"Reads one framework clause by clause: every clause the standard publishes, what covers it, and which controls stand behind it — so a coverage number can be checked line by line rather than taken on trust.","description":"Reads one framework clause by clause: every clause the standard publishes,\nwhat covers it, and which controls stand behind it — so a coverage number can\nbe checked line by line rather than taken on trust.","tags":["trust"],"parameters":[{"name":"framework","in":"path","required":true,"description":"Framework is the framework id — \"soc2\", \"iso27001\", \"nist80053\".","schema":{"type":"string"},"example":"soc2"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/trust.clauseCoverage"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"trust","x-public":true,"x-tool":true}},"/v1/trust/documents":{"get":{"operationId":"get_trust_documents","summary":"Lists your organization's documents.","description":"Lists your organization's documents. Because this is your own centre, a gated\nartifact carries its address here; through the published endpoint it does not.","tags":["trust"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/trust.trustDocuments"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"trust","x-public":true,"x-tool":true}},"/v1/trust/evidence":{"get":{"operationId":"get_trust_evidence","summary":"Reads the audit rows that stand behind one control, over a window.","description":"Reads the audit rows that stand behind one control, over a window.\n\nThe inventory decides what evidences what: a control names the audit actions\nthat are its trail, and this resolves the control id to those actions and\nreads them. So evidence cannot drift from the inventory, and it is scoped to\nyour own organization — the query carries no organization field for a caller\nto fill in.\n\nA control that nothing in the trail evidences says so plainly rather than\nanswering an empty page, because an empty page reads like a clean quarter. A\ndeployment with no audit store answers 501 and says the trail was not read,\nfor the same reason.","tags":["trust"],"parameters":[{"name":"control","in":"query","required":false,"description":"Control is the control id whose trail to read. Required.","schema":{"type":"string"},"example":"iam.refresh.rotation"},{"name":"from","in":"query","required":false,"description":"From is the inclusive lower bound, an RFC 3339 date or instant\n(\"2026-01-01\" or \"2026-01-01T00:00:00Z\"). Empty leaves it unbounded. A\nmalformed bound is refused rather than silently widening the window.","schema":{"type":"string"},"example":"2026-01-01"},{"name":"to","in":"query","required":false,"description":"To is the upper bound, same form and same tolerance.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Limit caps the rows returned, 1..1000, default 100. It is a string because\nan unparseable value is refused rather than read as zero.","schema":{"type":"string"},"example":"50"}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"trust","x-public":true,"x-tool":true}},"/v1/trust/faq":{"get":{"operationId":"get_trust_faq","summary":"Lists your knowledge base — the questions a reviewer asks, answered once.","description":"Lists your knowledge base — the questions a reviewer asks, answered once.","tags":["trust"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/trust.faqList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"trust","x-public":true,"x-tool":true}},"/v1/trust/frameworks":{"get":{"operationId":"get_trust_frameworks","summary":"Lists the frameworks coverage is computed against, and how many clauses each publishes.","description":"Lists the frameworks coverage is computed against, and how many clauses each\npublishes. That count is the denominator of every coverage number, which is\nwhat keeps an uncovered clause visible instead of dropping out of the\nfraction.","tags":["trust"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/trust.frameworkList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"trust","x-public":true,"x-tool":true}},"/v1/trust/policies":{"get":{"operationId":"get_trust_policies","summary":"Lists your organization's published policies.","description":"Lists your organization's published policies.","tags":["trust"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/trust.policyList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"trust","x-public":true,"x-tool":true}},"/v1/trust/profile":{"get":{"operationId":"get_trust_profile","summary":"Reads your organization's trust-centre profile — the name, tagline and summary a visitor sees, whether the centre is published, and where to send somebody who wants a gated document.","description":"Reads your organization's trust-centre profile — the name, tagline and\nsummary a visitor sees, whether the centre is published, and where to send\nsomebody who wants a gated document.","tags":["trust"],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"trust","x-public":true,"x-tool":true}},"/v1/trust/published/{org}":{"get":{"operationId":"get_trust_published_by_org","summary":"Reads a published trust centre — the whole thing in one answer: the organization's profile, its control inventory, coverage computed against each framework's whole published clause list, its documents, subprocessors, policies, knowledge base, updates and risk profile.","description":"Reads a published trust centre — the whole thing in one answer: the\norganization's profile, its control inventory, coverage computed against each\nframework's whole published clause list, its documents, subprocessors,\npolicies, knowledge base, updates and risk profile.\n\nThis is the PUBLIC endpoint and needs no credential, because a published trust\ncentre is a public document. It answers only for an organization that has\npublished one — an organization that has not is not found rather than empty,\nsince an empty centre and a centre nobody meant to show read the same and are\nnot the same thing.\n\nA gated document appears here with its title, its type and its date and NO\naddress: the listing says the artifact exists and that reading it takes a\ngrant. Nothing an independent auditor signed is ever released through this\nendpoint.","tags":["trust"],"parameters":[{"name":"org","in":"path","required":true,"description":"Org is the organization's slug — the name in its address.","schema":{"type":"string"},"example":"hanzo"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/trust.centre"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"security":[],"x-app":"trust","x-public":true,"x-tool":true}},"/v1/trust/risk":{"get":{"operationId":"get_trust_risk","summary":"Reads your risk profile — the label and value pairs describing what your organization handles and how.","description":"Reads your risk profile — the label and value pairs describing what your\norganization handles and how.","tags":["trust"],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"trust","x-public":true,"x-tool":true}},"/v1/trust/subprocessors":{"get":{"operationId":"get_trust_subprocessors","summary":"Lists the third parties your organization sends data to, each naming what it is for.","description":"Lists the third parties your organization sends data to, each naming what it\nis for.","tags":["trust"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/trust.subprocessorList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"trust","x-public":true,"x-tool":true}},"/v1/trust/updates":{"get":{"operationId":"get_trust_updates","summary":"Lists your trust-centre updates, newest as you ordered them.","description":"Lists your trust-centre updates, newest as you ordered them.","tags":["trust"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/trust.updateList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"trust","x-public":true,"x-tool":true}},"/v1/trust/{kind}/{id}":{"delete":{"operationId":"delete_trust_by_kind_by_id","summary":"Removes one record from a section of your organization's trust centre.","description":"Removes one record from a section of your organization's trust centre. A\nrecord that is not there is a 404, never a silent success. A control that\nbelongs to the deployment's own inventory is removed by a commit, not by a\nrequest.","tags":["trust"],"parameters":[{"name":"kind","in":"path","required":true,"description":"Kind is the section — profile, control, document, subprocessor, policy,\nfaq, update or risk. Anything else is not found. The URL is the authority:\na value here is bound from the path, which zip binds last.","schema":{"type":"string"},"example":"faq"},{"name":"id","in":"path","required":true,"description":"ID is the record's id within that section. The single-valued sections\n(profile, risk) hold one record whatever id is named.","schema":{"type":"string"},"example":"where-is-data-held"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/trust.dropped"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"trust","x-public":true,"x-tool":true},"put":{"operationId":"put_trust_by_kind_by_id","summary":"Writes one record into a section of YOUR organization's trust centre — profile, control, document, subprocessor, policy, faq, update or risk.","description":"Writes one record into a section of YOUR organization's trust centre —\nprofile, control, document, subprocessor, policy, faq, update or risk.\n\nA control written here is held to exactly the rule a control committed to the\ndeployment's own inventory is held to, by the same validator: its prose may\nnot claim a certificate and may not name a framework (a framework belongs in\nthe mappings, where it arrives attached to a number), anything short of\nautomated must say what is missing, and a mapping to a clause no framework\ndeclares is refused rather than scored as nothing.\n\nA document defaults to GATED. An artifact an independent auditor signed — an\nattestation report, a certificate, a penetration test, an auditor letter —\ncannot be made public at all; it is released through a grant. A\nself-assessment can, because the organization is the one attesting it.\n\nThe deployment's OWN control inventory is governed in git and is not writable\nhere: naming one of its ids is a conflict, not an overwrite.","tags":["trust"],"parameters":[{"name":"kind","in":"path","required":true,"description":"Kind is the section being written. The URL is the authority.","schema":{"type":"string"},"example":"subprocessor"},{"name":"id","in":"path","required":true,"description":"ID is the record's id. Omit it on a create and one is minted; the\nsingle-valued sections (profile, risk) hold one record whatever is named.","schema":{"type":"string"},"example":"acme-cloud"}],"requestBody":{"content":{"application/json":{"example":{"data":{"name":"A cloud","purpose":"Compute"},"id":"acme-cloud","kind":"subprocessor"},"schema":{"$ref":"#/components/schemas/trust.sectionWrite"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/trust.written"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"trust","x-public":true,"x-tool":true}},"/v1/usage":{"post":{"operationId":"post_usage","summary":"Ingests a batch of account-usage samples — what a developer's OWN AI accounts have consumed of their OWN plans, metered from each provider's own login — and appends them to the warehouse series.","description":"Ingests a batch of account-usage samples — what a developer's OWN AI\naccounts have consumed of their OWN plans, metered from each provider's own\nlogin — and appends them to the warehouse series. Answers 202.\n\nSend either a `samples` array or one sample's fields at the top level. Every\nsample needs a provider, a machine and a known window class; an unknown window or\nkind is refused rather than silently rewritten, because a dash filled with a class\nnobody reported is worse than an error. There is no timestamp field: the server\nowns the observation clock, and a sample says which window it measured with\nwindowStart or resetsAt.\n\nIt is FAIL-SOFT on storage: a warehouse outage costs a poll of history\n(stored:false), never a failed request. It records usage ONLY — the link registry\nis refreshed separately via POST /v1/link, so there is one and only one way to\nupdate an account row.","tags":["usage"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/usage.reportReq"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/usage.reportResp"}}},"description":"accepted"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"usage","x-public":true,"x-tool":true}},"/v1/usage/analytics":{"get":{"operationId":"get_usage_analytics","summary":"Is the entitlement-GATED per-provider breakdown of the caller org's LLM usage — the paid lens over the same warehouse ledger GET /v1/usage/summary reads its totals from.","description":"Is the entitlement-GATED per-provider breakdown of the caller org's LLM\nusage — the paid lens over the same warehouse ledger GET /v1/usage/summary reads\nits totals from. Basic own-org usage stays ungated at /v1/usage/summary.\n\nA plan that does not grant the analytics datastore is refused with 402, and an\nunresolvable plan fails closed to the free floor, which does not grant it. The\nwindow is clamped forward to the plan's retention entitlement, so a tenant can\nnever read older than its plan allows even with a custom start. The response is\nmarked no-store.\n\nINTERIM (mirrors apps/world's limits echo): no org→plan resolver exists in cloud\nyet — the subscription lookup is owned by the billing plane and the gateway\nprincipal carries no plan claim — so the caller passes the plan and the gate\nresolves THAT plan's access.","tags":["usage"],"parameters":[{"name":"end","in":"query","required":false,"description":"End is the exclusive window end, RFC3339. Read only when Range is custom.","schema":{"type":"string"}},{"name":"plan","in":"query","required":false,"description":"Plan is the plan id whose entitlement decides access and retention. INTERIM:\ncloud has no org-to-plan resolver yet, so the caller names the plan; when\nthat resolver lands this becomes the caller org's own plan.","schema":{"type":"string"}},{"name":"range","in":"query","required":false,"description":"Range is the window: a count and a unit — 24h, 7d, 90d, any \u003cN\u003eh or \u003cN\u003ed —\nor day, week, month, all, custom. Empty means 24h. The window is then\nclamped forward to the plan's retention entitlement.","schema":{"type":"string"}},{"name":"start","in":"query","required":false,"description":"Start is the inclusive window start, RFC3339. Read only when Range is\ncustom, and clamped forward to the plan's retention floor.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/usage.usageAnalyticsView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"usage","x-public":true,"x-tool":true}},"/v1/usage/analytics/access":{"get":{"operationId":"get_usage_analytics_access","summary":"Echoes a plan's resolved analytics entitlement so a dashboard can configure itself against the LIVE catalog instead of hardcoding tier numbers.","description":"Echoes a plan's resolved analytics entitlement so a dashboard can\nconfigure itself against the LIVE catalog instead of hardcoding tier numbers. An\nempty plan resolves the free floor, and a catalog resolution failure serves that\nsame floor rather than erroring — so this always answers 200. It is a read-only\ncontract echo and carries no tenant data.","tags":["usage"],"parameters":[{"name":"plan","in":"query","required":false,"description":"Plan is a plan id from the live @hanzo/plans catalog. Empty resolves the\nfree floor, and so does an id the catalog does not know — this never fails\non an unknown plan.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/usage.usageAnalyticsAccess"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"usage","x-public":true,"x-tool":true}},"/v1/usage/samples":{"get":{"operationId":"get_usage_samples","summary":"Is the PER-PROVIDER view: one connected account's own consumption of its own plan — \"my plan is 47% through its 6h window, resets at 14:20\".","description":"Is the PER-PROVIDER view: one connected account's own consumption of its\nown plan — \"my plan is 47% through its 6h window, resets at 14:20\".\n\n`current` is the newest instance of each lane (the headline); `windows` is the\nhistory behind it. Both come from ONE deduped read, so they can never disagree.\nThe rows are the caller's OWN linked accounts, scoped to the validated principal\nand its subject — never another user's, and never another org's.","tags":["usage"],"parameters":[{"name":"account","in":"query","required":false,"description":"Account narrows to ONE linked account of that provider. Empty covers every\naccount the caller has linked there.","schema":{"type":"string"}},{"name":"provider","in":"query","required":false,"description":"Provider is the upstream to read, e.g. anthropic. Required.","schema":{"type":"string"}},{"name":"range","in":"query","required":false,"description":"Range is the window to read: a count and a unit — 1h, 24h, 90d, any \u003cN\u003eh or\n\u003cN\u003ed — or day, week, month, all. Empty means 24h. A label that is not a\ncount, or one reaching past the 730-day horizon, is refused rather than\nsilently replaced.","schema":{"type":"string"}},{"name":"window","in":"query","required":false,"description":"Window narrows to ONE window class: 6h, day, week or month. Empty covers\nevery class.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/usage.dashResp"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"usage","x-public":true,"x-tool":true}},"/v1/usage/summary":{"get":{"operationId":"get_usage_summary","summary":"Answers GET /v1/usage/summary: the caller's own usage footprint over one window — the categorized spend roll-up from the commerce ledger, the org's LLM usage totals from the warehouse (with what the prompt cache served and saved), the org's Kai decisions, and the caller's OWN linked provider accounts beside the org's Hanzo-routed usage.","description":"Answers GET /v1/usage/summary: the caller's own usage footprint over one\nwindow — the categorized spend roll-up from the commerce ledger, the org's LLM\nusage totals from the warehouse (with what the prompt cache served and saved),\nthe org's Kai decisions, and the caller's OWN linked provider accounts beside\nthe org's Hanzo-routed usage.\n\nEvery source degrades INDEPENDENTLY to honest zeros and says so in `sources` and\nin its own `available` flag, so a partial deploy reports \"no data\" rather than\nfabricating spend. The account rows and the Hanzo rows are concatenated and never\nsummed: a plan's percent is not money.\n\nThe response is org-scoped from the validated principal and marked no-store — a\nsigned-out caller is refused.","tags":["usage"],"parameters":[{"name":"range","in":"query","required":false,"description":"Range is the window: a count and a unit — 24h, 7d, 90d, any \u003cN\u003eh or \u003cN\u003ed —\nor day, week, month, all, custom. Empty means 24h. A label this surface\ndoes not know, or one reaching past the 730-day horizon, is refused rather\nthan silently replaced.","schema":{"type":"string"}},{"name":"start","in":"query","required":false,"description":"Start is the inclusive window start, RFC3339. Read only when Range is\ncustom.","schema":{"type":"string"}},{"name":"end","in":"query","required":false,"description":"End is the exclusive window end, RFC3339. Read only when Range is custom.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/usage.usageSummary"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"usage","x-public":true,"x-tool":true}},"/v1/validator":{"get":{"operationId":"get_validator","summary":"Returns the validator slots the caller's org has claimed.","description":"Returns the validator slots the caller's org has claimed.\n\nOne entry per claimed slot with its node identity, its live-ish node status and\nthe owner-gated registration queued for it, if any. Slots are org-scoped by the\nvalidated identity, so a caller can only ever see their own — a slot claimed by\nanother org is not merely hidden from this list, it is unreachable through the\nwhole surface.","tags":["validator"],"parameters":[{"name":"limit","in":"query","required":false,"description":"Limit is how many slots to return, as a decimal string in the `?limit=`\nquery. Absent, unparseable or non-positive means 200; over 1000 is clamped\nto 1000. It is a string rather than a number because the parse that has\nalways served this route trims surrounding whitespace, and one parse rule is\nbetter than two.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/validator.validatorList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"validator","x-public":true,"x-tool":true},"post":{"operationId":"post_validator","summary":"Claims a validator slot and provisions its node, after proving the caller's wallet owns the slot's NFT.","description":"Claims a validator slot and provisions its node, after proving the\ncaller's wallet owns the slot's NFT.\n\nThe pipeline, all server-enforced: burn the single-use challenge (so a replayed\nor forged nonce dies before any chain read), recover the signer from the message\nthis server rebuilds, require that wallet to hold Validator-tier GenesisNFT\n#tokenId on Ethereum mainnet, generate a fresh luxd staking identity and seal it\ninto KMS, write a LuxNetwork CR for a NEW node, and ENQUEUE an owner-gated\nregistration. The registration is never auto-submitted to any P-Chain — the\nowner co-signs it out of band — and the stake weight is set at co-sign time,\nnever derived from the NFT.\n\nIt fails CLOSED at every gate: a bad signature, a non-owner, a non-tier slot or\nan unavailable KMS all leave no claim persisted and no key material exposed.\nRe-claiming a slot this org already holds re-applies the node CR and returns 200\nwith the existing identity (keys and NodeID are stable); a slot held by another\norg is 409. A cluster-less deployment still claims the slot, seals the keys and\nqueues the registration, reporting the node as \"node_pending\".","tags":["validator"],"requestBody":{"content":{"application/json":{"example":{"nonce":"5f3a…","signature":"0x…","tokenId":7},"schema":{"$ref":"#/components/schemas/validator.validatorClaim"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/validator.slotView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"validator","x-public":true,"x-tool":true}},"/v1/validator/challenge":{"get":{"operationId":"get_validator_challenge","summary":"Issues the single-use nonce and the exact message a wallet must sign to claim a validator slot.","description":"Issues the single-use nonce and the exact message a wallet must sign\nto claim a validator slot.\n\nThe nonce is bound to (validated org, slot) and stored server-side, so a\nsignature obtained for one org or one slot can never be replayed for another,\nand the message POST /v1/validator verifies is rebuilt from those same server\nfacts rather than trusted from the caller. Redeem it with\nPOST /v1/validator before it expires; it can be redeemed once.\n\nA tokenId outside the Validator tier is refused here rather than after signing.","tags":["validator"],"parameters":[{"name":"tokenId","in":"query","required":false,"description":"TokenID is the Validator-tier GenesisNFT token id, as a decimal string in\nthe `?tokenId=` query. A value that is not a positive integer is 400. It is\na string rather than a number because the parse that has always served this\nroute trims surrounding whitespace, and one parse rule is better than two.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/validator.challengeView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"validator","x-public":true,"x-tool":true}},"/v1/validator/{tokenId}":{"get":{"operationId":"get_validator_by_tokenid","summary":"Returns one claimed validator slot, scoped to the caller's org.","description":"Returns one claimed validator slot, scoped to the caller's org.\n\nA slot another org holds, and a slot nobody holds, are both 404 — never a\ndifferent status, so this route cannot be used to probe which slots are taken.","tags":["validator"],"parameters":[{"name":"tokenId","in":"path","required":true,"description":"TokenID is the slot's GenesisNFT token id, from the path, as a decimal\nstring. A value that is not a positive integer is 400. It is a string\nrather than a number because the parse that has always served this route\ntrims surrounding whitespace, and one parse rule is better than two.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/validator.slotView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"validator","x-public":true,"x-tool":true}},"/v1/videos/generations":{"post":{"operationId":"post_videos_generations","summary":"Implements POST /v1/videos/generations — the ASYNC create.","description":"Implements POST /v1/videos/generations — the ASYNC create.\n\nBody: {\"model\": \"...\", \"prompt\": \"...\", \"size\"?: \"1280x720\", \"seconds\"?: int}\n\nIt authenticates the caller, resolves the model to its upstream provider via\nthe shared routing table (zen3-video* / wan2-2-t2v-a14b → the spark-video\nbackend), reserves the per-video budget (the balance gate), creates ONE\nupstream job, registers it in the in-pod store, and returns the OpenAI-shaped\nvideo object with status \"queued\" IMMEDIATELY. The client then polls\nGET /v1/videos/{id} and downloads GET /v1/videos/{id}/content. Nothing is\nbilled here — the debit lands on completion.","tags":["ai"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.VideoStatus"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/videos/{id}":{"get":{"operationId":"get_videos_by_id","summary":"Implements GET /v1/videos/{id} — poll a job's status.","description":"Implements GET /v1/videos/{id} — poll a job's status.\n\nIt authenticates the caller, verifies they OWN the job (the caller's billing\nsubject must equal the job's), performs ONE upstream status poll, and — the\nfirst time the job is observed completed — settles the reservation with the\nactual cost and records the billable usage event (exactly once). Returns the\nOpenAI-shaped video object.","tags":["ai"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ai.VideoStatus"}}},"description":"Success."},"401":{"description":"No credential, or one this service does not accept."},"403":{"description":"A valid credential that may not do this."}},"x-app":"ai","x-public":true}},"/v1/videos/{id}/content":{"get":{"operationId":"get_videos_by_id_content","summary":"Implements GET /v1/videos/{id}/content — download the finished MP4.","description":"Implements GET /v1/videos/{id}/content — download the finished MP4.\n\nIt authenticates + ownership-checks the caller, then proxies the upstream\n/content endpoint (bounded by the download concurrency ceiling) and streams the\nraw video bytes back inline. A successful download also bills the job once (for\nthe client that downloads without first polling to completion) — idempotent\nwith the poll path via job.markCompleted.","tags":["ai"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-app":"ai","x-public":true}},"/v1/wallet":{"get":{"operationId":"get_wallet","summary":"Returns the caller org's wallets, newest first, optionally NARROWED within the org by project, agent or account.","description":"Returns the caller org's wallets, newest first, optionally NARROWED\nwithin the org by project, agent or account. The org is always the bound\nisolation boundary — the filters only ever narrow inside it, so a caller can\nnever widen past its own org.","tags":["wallet"],"parameters":[{"name":"project","in":"query","required":false,"description":"Project narrows to wallets scoped to one project. Must be a url-safe segment.","schema":{"type":"string"}},{"name":"agent","in":"query","required":false,"description":"Agent narrows to wallets scoped to one agent. Must be a url-safe segment.","schema":{"type":"string"}},{"name":"account","in":"query","required":false,"description":"Account narrows to wallets under one account id. Must be a url-safe segment.","schema":{"type":"string"},"example":"acct_9f8c1d"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/wallet.walletList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"wallet","x-public":true,"x-tool":true},"post":{"operationId":"post_wallet","summary":"Provisions a new signing identity under one of the caller org's accounts and answers the stored wallet including its on-chain address.","description":"Provisions a new signing identity under one of the caller org's\naccounts and answers the stored wallet including its on-chain address. The\ncustody backend generates the key material — a KMS-sealed secp256k1 key, an\nMPC threshold key on the ring, or a Safe smart wallet owned by one — and the\nHANDLE to it is kept server-side and never returned. A custody kind the\ndeployment has not wired fails CLOSED with 503: a signature is never\nfabricated. The wallet is scoped to the org, the caller's ambient project, and\noptionally an agent and the named account; those narrowings are what its key\nref is derived from, so each must be a url-safe segment.","tags":["wallet"],"requestBody":{"content":{"application/json":{"example":{"accountId":"acct_9f8c1d","chain":"eip155:36963","custody":"kms","name":"ops hot wallet","tier":"hot"},"schema":{"$ref":"#/components/schemas/wallet.createWalletIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/wallet.Wallet"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"wallet","x-public":true,"x-tool":true}},"/v1/wallet/accounts":{"get":{"operationId":"get_wallet_accounts","summary":"Returns the caller org's wallet accounts, newest first.","description":"Returns the caller org's wallet accounts, newest first. Accounts\nare physically org-scoped, so another tenant's are not reachable from here.","tags":["wallet"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/wallet.accountList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"wallet","x-public":true,"x-tool":true},"post":{"operationId":"post_wallet_accounts","summary":"Opens a named wallet account for the caller's org.","description":"Opens a named wallet account for the caller's org. An account is\na GROUPING of wallets, not a key or a balance: wallets are created under one\nand can be listed by it. The org is stamped by the server from the validated\nprincipal, so a request can never open an account in another tenant.","tags":["wallet"],"requestBody":{"content":{"application/json":{"example":{"name":"treasury"},"schema":{"$ref":"#/components/schemas/wallet.createAccountIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/wallet.WalletAccount"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"wallet","x-public":true,"x-tool":true}},"/v1/wallet/{id}":{"get":{"operationId":"get_wallet_by_id","summary":"Returns one of the caller org's wallets: its scope, custody kind, tier, chain and on-chain address.","description":"Returns one of the caller org's wallets: its scope, custody kind,\ntier, chain and on-chain address. The custody handle to the signing material is\nnever part of the answer. A wallet id another org owns reads as not found, so\nthe response cannot confirm that it exists.","tags":["wallet"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"wal_4b1e77"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/wallet.Wallet"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"wallet","x-public":true,"x-tool":true}},"/v1/wallet/{id}/keys":{"post":{"operationId":"post_wallet_by_id_keys","summary":"Rolls one wallet's signing material through its own custody backend and answers the wallet with whatever address that produced.","description":"Rolls one wallet's signing material through its own custody backend\nand answers the wallet with whatever address that produced. For KMS custody a\nfresh secp256k1 key is generated and sealed, which CHANGES the address — funds\nand approvals at the old address do not move. For a Safe the address is\ncounterfactual and the owner shares are ring-managed, so rotation is a no-op\nand the address is unchanged. A backend that is not configured fails closed\nwith 503 rather than leaving the wallet half-rotated.","tags":["wallet"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"wal_4b1e77"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/wallet.Wallet"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"wallet","x-public":true,"x-tool":true}},"/v1/wallet/{id}/sign":{"post":{"operationId":"post_wallet_by_id_sign","summary":"Produces a secp256k1 signature from one of the caller org's wallets over a 32-byte digest, through whichever custody backend that wallet uses.","description":"Produces a secp256k1 signature from one of the caller org's wallets over\na 32-byte digest, through whichever custody backend that wallet uses. Give it\neither a `digest` (32 bytes as hex, signed verbatim) or a `message` (hashed\nwith Keccak256 first) — exactly one is required. The private key never leaves\nits backend: KMS custody opens the sealed key in-process, MPC custody produces\na threshold signature on the ring. The answer carries the digest that was\nsigned alongside the signature, so a caller can verify what it got.","tags":["wallet"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"wal_4b1e77"}],"requestBody":{"content":{"application/json":{"example":{"id":"wal_4b1e77","message":"approve withdrawal 42"},"schema":{"$ref":"#/components/schemas/wallet.signIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/wallet.signature"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"wallet","x-public":true,"x-tool":true}},"/v1/wallet/{id}/transactions":{"post":{"operationId":"post_wallet_by_id_transactions","summary":"Composes a Safe transaction on the MPC ring and answers its EIP-712 hash together with the owner approval the ring's threshold signature produced.","description":"Composes a Safe transaction on the MPC ring and answers its\nEIP-712 hash together with the owner approval the ring's threshold signature\nproduced. Only a wallet whose custody is \"safe\" can do this — any other custody\nis a 400, because the backend itself is asked whether it can propose rather\nthan the kind being switched on. The ring computes the Safe-tx hash bound to\nthe Safe contract and the chain id, so the hash a caller gets back is the one\nthe Safe will verify. This PROPOSES: it does not execute the transaction.","tags":["wallet"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"wal_4b1e77"}],"requestBody":{"content":{"application/json":{"example":{"chainId":36963,"data":"0x","id":"wal_4b1e77","nonce":7,"to":"0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984","value":"0"},"schema":{"$ref":"#/components/schemas/wallet.safeTxIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/wallet.safeProposal"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"wallet","x-public":true,"x-tool":true}},"/v1/web3/chains":{"get":{"operationId":"get_web3_chains","summary":"Reports the chains this deployment can reach.","description":"Reports the chains this deployment can reach. The list is the\ndeclared registry, so it is exactly what /v1/web3/rpc will accept — a chain that\nappears here is one this deployment actually has an upstream for.","tags":["web3"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/web3.chainList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"web3","x-public":true,"x-tool":true}},"/v1/web3/chains/{chain}":{"get":{"operationId":"get_web3_chains_by_chain","summary":"Reports one chain and whether its upstream is answering.","description":"Reports one chain and whether its upstream is answering. An\nunreachable chain is still a 200 with live:false — the chain is configured,\nwhich is a different fact from the chain being up, and a 502 here would make\na console page error rather than show the outage.","tags":["web3"],"parameters":[{"name":"chain","in":"path","required":true,"description":"Chain is the registry id, as in /v1/web3/chains/lux.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/web3.chainStatus"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"web3","x-public":true,"x-tool":true}},"/v1/web3/rpc/{chain}":{"post":{"operationId":"post_web3_rpc_by_chain","summary":"Forwards a JSON-RPC call to the named chain and returns its answer unchanged.","description":"Forwards a JSON-RPC call to the named chain and returns its answer\nunchanged. Only declared chains are reachable, and only to a caller with a\nvalidated principal — this is the deployment's upstream, not an open relay.","tags":["web3"],"parameters":[{"name":"chain","in":"path","required":true,"description":"Chain is the registry id, from the URL.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/web3.rpcIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/web3.rpcOut"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"web3","x-public":true,"x-tool":true}},"/v1/web3/tokens/{chain}/{address}":{"get":{"operationId":"get_web3_tokens_by_chain_by_address","summary":"Reads an address's native balance on a chain.","description":"Reads an address's native balance on a chain.\n\nERC-20 positions are NOT enumerated here: eth_getBalance answers the native\none, but \"every token this address holds\" is an indexer question — there is no\nRPC call that answers it, and walking a token list would return a number that\nsilently omits whatever the list missed. explorer owns the indexer\nrelationship; this returns the balance the chain itself can prove.","tags":["web3"],"parameters":[{"name":"chain","in":"path","required":true,"description":"Chain is the registry id.","schema":{"type":"string"}},{"name":"address","in":"path","required":true,"description":"Address is the account, 0x-prefixed.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/web3.balances"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"web3","x-public":true,"x-tool":true}},"/v1/webhook":{"get":{"operationId":"get_webhook","summary":"Returns every webhook endpoint the caller's org has registered, newest first, each with its 7-day delivery and failure counts.","description":"Returns every webhook endpoint the caller's org has registered,\nnewest first, each with its 7-day delivery and failure counts. Signing secrets\nare redacted here — a secret leaves the server only on create and on rotate.\nThe listing is physically org-scoped, so another tenant's endpoints are not\nreachable from this route at all.","tags":["webhook"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/webhook.endpointList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"webhook","x-public":true,"x-tool":true},"post":{"operationId":"post_webhook","summary":"Registers a new webhook subscription for the caller's org and answers 201 with the endpoint INCLUDING its freshly minted signing secret.","description":"Registers a new webhook subscription for the caller's org and\nanswers 201 with the endpoint INCLUDING its freshly minted signing secret.\nThis is one of only two responses that ever carry that secret (the other is\nrotate) — store it now, because no later read returns it. The org is stamped by\nthe server from the validated principal, so a body can never register an\nendpoint in another tenant.","tags":["webhook"],"requestBody":{"content":{"application/json":{"example":{"description":"order pipeline","events":["commerce.order.\u003e"],"url":"https://acme.example/hooks/hanzo"},"schema":{"$ref":"#/components/schemas/webhook.createEndpointIn"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/webhook.Endpoint"}}},"description":"created"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"webhook","x-public":true,"x-tool":true}},"/v1/webhook/{id}":{"delete":{"operationId":"delete_webhook_by_id","summary":"Removes one of the caller org's webhook endpoints and answers 204 with no body.","description":"Removes one of the caller org's webhook endpoints and answers\n204 with no body. Delivery stops immediately and the endpoint's signing secret\nis gone with it; its recorded delivery history goes too. An id another org owns\nreads as not found.","tags":["webhook"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"wh_9f8c1d2e"}],"responses":{"204":{"description":"no content"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"webhook","x-public":true,"x-tool":true},"get":{"operationId":"get_webhook_by_id","summary":"Returns one of the caller org's webhook endpoints with its 7-day delivery and failure counts, signing secret redacted.","description":"Returns one of the caller org's webhook endpoints with its 7-day\ndelivery and failure counts, signing secret redacted. An id another org owns\nreads as not found, so the response cannot confirm that it exists.","tags":["webhook"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"wh_9f8c1d2e"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/webhook.Endpoint"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"webhook","x-public":true,"x-tool":true},"put":{"operationId":"put_webhook_by_id","summary":"Replaces the editable fields of one of the caller org's endpoints — url, events, status and description — and answers the stored row with its secret redacted.","description":"Replaces the editable fields of one of the caller org's\nendpoints — url, events, status and description — and answers the stored row\nwith its secret redacted. It is a full replace, not a patch: an omitted field\nis written as its empty value, and an omitted or empty events list resubscribes\nthe endpoint to EVERY event. The signing secret and the creation time are\nimmutable here; rotate the secret with POST /v1/webhook/{id}/secret.","tags":["webhook"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"wh_9f8c1d2e"}],"requestBody":{"content":{"application/json":{"example":{"events":["commerce.order.paid"],"id":"wh_9f8c1d2e","status":"disabled","url":"https://acme.example/hooks/v2"},"schema":{"$ref":"#/components/schemas/webhook.updateEndpointIn"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/webhook.Endpoint"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"webhook","x-public":true,"x-tool":true}},"/v1/webhook/{id}/deliveries":{"get":{"operationId":"get_webhook_by_id_deliveries","summary":"Returns one endpoint's per-attempt delivery log, newest first — the record of what was sent, what the subscriber answered, and how long it took.","description":"Returns one endpoint's per-attempt delivery log, newest first —\nthe record of what was sent, what the subscriber answered, and how long it\ntook. One event that retried three times appears as three rows sharing a\ndelivery id. It is org-scoped exactly like every other route here: the endpoint\nlookup only ever finds THIS org's endpoint, so another org's id is a 404 and\nnever a window onto its logs.","tags":["webhook"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"wh_9f8c1d2e"},{"name":"limit","in":"query","required":false,"description":"Limit caps how many attempts come back: default 50, maximum 200. A value\nthat is not a positive integer reads as the default.","schema":{"format":"int64","type":"integer"},"example":100},{"name":"status","in":"query","required":false,"description":"Status narrows the log to one outcome: \"ok\", \"retrying\" or \"failed\".\nEmpty returns every attempt.","schema":{"type":"string"},"example":"failed"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/webhook.deliveryList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"webhook","x-public":true,"x-tool":true}},"/v1/webhook/{id}/secret":{"post":{"operationId":"post_webhook_by_id_secret","summary":"Mints a NEW HMAC signing secret for the endpoint and answers the endpoint WITH it — the only other response besides create that ever carries a secret.","description":"Mints a NEW HMAC signing secret for the endpoint and answers the\nendpoint WITH it — the only other response besides create that ever carries a\nsecret. The old secret stops working the instant this returns: every subsequent\ndelivery signs with the new one, with no overlap window. Call it when the\nsubscriber is ready to swap the value on its side, not before.","tags":["webhook"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"wh_9f8c1d2e"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/webhook.Endpoint"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"webhook","x-public":true,"x-tool":true}},"/v1/webhook/{id}/test":{"post":{"operationId":"post_webhook_by_id_test","summary":"Sends ONE signed test event to the endpoint right now and answers the outcome inline, so the console can show whether the subscriber is reachable without waiting for real traffic.","description":"Sends ONE signed test event to the endpoint right now and answers\nthe outcome inline, so the console can show whether the subscriber is reachable\nwithout waiting for real traffic. It takes the same attempt path the bus\ndispatcher takes — one attempt, 10s timeout, no retry ladder — and records the\nresult in the endpoint's delivery log. It works on a DISABLED endpoint too:\nvalidating one you have paused is the whole point.","tags":["webhook"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"wh_9f8c1d2e"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/webhook.testResult"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"webhook","x-public":true,"x-tool":true}},"/v1/websearch":{"post":{"operationId":"search_web","summary":"Search the live web","description":"Searches the live web and answers with ranked results.\n\nThis is the fleet's path to what is happening RIGHT NOW — today's weather, an\noutage, a release that postdates any model's training. `q` is the query and\n`language` narrows it to a locale. The answer is `{query, number_of_results,\nresults:[{url, title, content, engine}]}`, where `content` is the ENGINE's\nsnippet and not the page: read a page with POST /v1/crawl.\n\nIt is served in-process by a Go meta-search over the engines the platform\nenables (GET /v1/websearch/engines): Mojeek's API by default when the platform\nholds its key, otherwise the keyless engines that answer from this cluster. The\nenabled engines run concurrently and their hits are merged, deduplicated by\nnormalised URL (host and path, trailing slash and fragment dropped, query kept,\nso distinct queries stay distinct results) and capped at 30. Hits that several\nengines agree on rank first; ties keep a stable order.\n\nIt fails SOFT on the engines. One that errors, times out or is served a\nbot-challenge page contributes zero results and never fails the call, so an\nempty `results` is a real answer — nothing was found — and not an outage. The\narray is always present, never null.\n\nTwo refusals in the order they have to be asked, both in the PREAMBLE. A typed\nop is also an MCP tool, a call-plane operation, a graph field and a CLI\ncommand, and every one of those invokes it with no route and therefore no\nmiddleware — so what admits a caller here is asked where every caller reaches\nit rather than in a middleware only one of them passes through.\n\nA VALIDATED PRINCIPAL IS REQUIRED, and there is no tenant beyond that: the\nresults are public web pages, identical for every caller, so nothing here is\nscoped and nothing here can leak across orgs.\n\nTHEN THE ANTI-FORGERY TOKEN, immediately before the money, because that is\nwhat it is about. This search is the SAME bought meta-search the compat\nendpoint runs — the engines cost, and account.Shared/meter.go bills the\ncaller's ledger for the answer — so a page the caller never visited must not\nbe able to spend for them by sending their browser here with a cookie they\nalready hold. Nothing leaks; the answer is unreadable cross-origin. What\nmoves is money.\n\nIt is account's control, the one every operation in this estate asks, and it\nis a no-op the moment a caller PRESENTS a credential (Bearer, gateway, API\nkey) — which is every service and console caller here — so it costs a CLI, an\nagent and an API client nothing. Only the ambient-cookie path is asked for the\nechoed token. The raw /v1/websearch/search route asks the same control on its\ngroup (see Mount), so the two addresses of one search are admitted alike.","tags":["websearch"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/websearch.webSearchQuery"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/websearch.webSearchResults"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"websearch","x-public":true,"x-tool":true}},"/v1/websearch/engines":{"get":{"operationId":"list_search_engines","summary":"Lists every engine web search can run and how the platform runs it.","description":"Lists every engine web search can run and how the platform runs it.\n\nFor each engine: whether it is enabled and its place in the run order, whether\nit takes an API key and whether it needs one, whether the platform holds that\nkey (`keyed` — the key itself is never returned), whether it answers from this\ncluster as things stand (`available`), the option values it is asked with and\nthe options it supports with their bounds. Enabled engines come first, in the\norder they run.\n\n`saved` is false when no setting is stored, and the engines shown enabled are\nthen the default: Mojeek alone when its key is held, otherwise bing, ddg and\nMojeek — Mojeek's keyless page does not answer from this cluster on its own.\n\nSuperAdmin only. 503 when the settings store or KMS cannot answer: a board\nthat guessed would show an operator a configuration nobody saved.","tags":["websearch"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/websearch.searchEngines"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"websearch","x-public":true,"x-tool":true},"put":{"operationId":"set_search_engines","summary":"Replaces the platform's web search engine setting and answers the result.","description":"Replaces the platform's web search engine setting and answers the result.\n\n`enabled` lists the engines searches run, in order — at least one, each a\nregistered engine named once, and at least one that is available (needs no key\nhere, or its key is held). `options` gives each engine's values by name; an\nengine or a field left out takes its default, because the setting replaces the\nstored one whole. A count must lie within the engine's bounds, a language is a\ntag like `en` or `en-US`, a region a two-letter country code, and an option the\nengine does not support is refused.\n\nSuperAdmin only. 400 names every problem with the setting at once; 503 when\nthe settings store or KMS cannot answer. The answer is the engine list as it\nnow stands, so the caller sees the effect without a second read.","tags":["websearch"],"requestBody":{"content":{"application/json":{"example":{"enabled":["mojeek"],"options":{"mojeek":{"count":30,"language":"en","region":"GB"}}},"schema":{"$ref":"#/components/schemas/websearch.searchEnginesSet"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/websearch.searchEngines"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"websearch","x-public":true,"x-tool":true}},"/v1/websearch/engines/{name}/key":{"delete":{"operationId":"delete_search_engine_key","summary":"Removes an engine's API key from KMS.","description":"Removes an engine's API key from KMS.\n\nSearches stop using the key at once. Removing a key that is not held answers\nthe same as removing one that is. 409 when the saved setting would be left with\nno engine that can answer — enable bing or ddg first.\n\nSuperAdmin only. 404 for an engine that does not exist, 400 for one that takes\nno key, 503 when the settings store or KMS cannot answer.","tags":["websearch"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the engine, from the path.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/websearch.searchEngineKeyed"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"websearch","x-public":true,"x-tool":true},"put":{"operationId":"set_search_engine_key","summary":"Seals an engine's API key in KMS, replacing any key held.","description":"Seals an engine's API key in KMS, replacing any key held.\n\nThe key is the platform's: it lives in KMS under the platform org admin at\n/websearch/\u003cENGINE\u003e_KEY (env prod), every search reads it from there at the\nmoment it runs, and no\noperation returns, logs or echoes it — the answer says only that a key is now\nheld. Only an engine that takes a key accepts one (mojeek, brave).\n\nSuperAdmin only. 404 for an engine that does not exist, 400 for one that takes\nno key or a key that is empty, longer than 4096 bytes or holds whitespace or\ncontrol characters, 503 when KMS cannot take it.","tags":["websearch"],"parameters":[{"name":"name","in":"path","required":true,"description":"Name is the engine, from the path.","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/websearch.searchEngineKey"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/websearch.searchEngineKeyed"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"websearch","x-public":true,"x-tool":true}},"/v1/websearch/scrape":{"post":{"operationId":"post_websearch_scrape","summary":"Fetch one page and get its extracted markdown, in the firecrawl envelope.","description":"Takes {url} and answers {success, data:{markdown, metadata}} — the exact contract a firecrawl client decodes. The fetch, extraction and optional browser render run in-process; there is no crawler pod to be down.\n\nThe shared service key is required as an Authorization Bearer, compared in constant time: unset on the deployment is 503, missing or wrong is 401. Unlike search, a validated principal does NOT substitute for it — this is the service-to-service endpoint.\n\nA page is archived under the caller's own org and project, taken from the verified principal when there is one, so a scrape lands in the same corpus /v1/crawl fills and a URL already read under that scope is answered from the archive without touching the network. A service caller carrying no principal shares the unscoped prefix.\n\nThe URL is caller-supplied and fetched from INSIDE the cluster, which makes this a request-forgery primitive by construction: in-namespace service DNS and a cloud metadata endpoint that hands credentials to anyone who asks are both a resolution away. Only http and https are accepted, and every address actually dialled must be public unicast — loopback, link-local, private and multicast are refused. The check lives in the DIALER rather than on the hostname, because resolving a name to validate it and then letting the transport resolve it again is a gap DNS rebinding walks straight through; redirects re-enter the same dialer, so a public URL that bounces to the metadata address is refused at the hop that matters.\n\nThe one thing to get right: FAILURE IS 200. A missing or unparseable url, a body over the 1 MiB read cap, and a fetch that could not be completed all answer HTTP 200 with success:false and a reason — a firecrawl client reads data.success, not the status line. Only the two auth refusals use a status code, so a caller that branches on HTTP status alone will read every failed scrape as a success.","tags":["websearch"],"x-app":"websearch","x-public":true}},"/v1/websearch/search":{"delete":{"operationId":"delete_websearch_search","summary":"Web meta-search, in the SearXNG JSON envelope.","description":"Answers {query, number_of_results, results:[{url, title, content, engine}]} — the exact /search?format=json contract a SearXNG client decodes, so an agent tool configured against SearXNG reaches this with no change. `q` is the query and `language` narrows it; both are read from the QUERY STRING.\n\nServed in-process by a Go meta-search over the engines the platform enables (GET /v1/websearch/engines). The enabled engines run concurrently and their hits are merged, deduplicated by normalised URL (host and path, trailing slash and fragment dropped, query kept — distinct queries are distinct results) and capped at 30. Hits several engines agree on rank first.\n\nTWO WAYS IN, one-way equivalent, and no third: a validated principal — the same gate the whole data plane uses — passes straight through, and a caller without one must present the shared service key as X-API-Key, compared in constant time. A deployment with no key configured answers 503 rather than opening the surface to everyone, and a missing or wrong key is 401. It is never an open proxy. There is no tenant scoping beyond that gate, and there is nothing to scope: the results are public web pages, identical for every caller.\n\nIt fails SOFT on the engines and closed only on the gate. An engine that errors or is served a bot-challenge page contributes zero results and never fails the request, so an empty `results` is a real answer — nothing was found — and not an outage. The array is always present, never null.\n\nThe one thing to get right: every method answers identically. This is one handler registered for all of them, and it reads only the query string, so a body sent on the write verbs is ignored rather than refused.","tags":["websearch"],"x-app":"websearch","x-public":true},"get":{"operationId":"get_websearch_search","summary":"Web meta-search, in the SearXNG JSON envelope.","description":"Answers {query, number_of_results, results:[{url, title, content, engine}]} — the exact /search?format=json contract a SearXNG client decodes, so an agent tool configured against SearXNG reaches this with no change. `q` is the query and `language` narrows it; both are read from the QUERY STRING.\n\nServed in-process by a Go meta-search over the engines the platform enables (GET /v1/websearch/engines). The enabled engines run concurrently and their hits are merged, deduplicated by normalised URL (host and path, trailing slash and fragment dropped, query kept — distinct queries are distinct results) and capped at 30. Hits several engines agree on rank first.\n\nTWO WAYS IN, one-way equivalent, and no third: a validated principal — the same gate the whole data plane uses — passes straight through, and a caller without one must present the shared service key as X-API-Key, compared in constant time. A deployment with no key configured answers 503 rather than opening the surface to everyone, and a missing or wrong key is 401. It is never an open proxy. There is no tenant scoping beyond that gate, and there is nothing to scope: the results are public web pages, identical for every caller.\n\nIt fails SOFT on the engines and closed only on the gate. An engine that errors or is served a bot-challenge page contributes zero results and never fails the request, so an empty `results` is a real answer — nothing was found — and not an outage. The array is always present, never null.\n\nThe one thing to get right: every method answers identically. This is one handler registered for all of them, and it reads only the query string, so a body sent on the write verbs is ignored rather than refused.","tags":["websearch"],"x-app":"websearch","x-public":true},"patch":{"operationId":"patch_websearch_search","summary":"Web meta-search, in the SearXNG JSON envelope.","description":"Answers {query, number_of_results, results:[{url, title, content, engine}]} — the exact /search?format=json contract a SearXNG client decodes, so an agent tool configured against SearXNG reaches this with no change. `q` is the query and `language` narrows it; both are read from the QUERY STRING.\n\nServed in-process by a Go meta-search over the engines the platform enables (GET /v1/websearch/engines). The enabled engines run concurrently and their hits are merged, deduplicated by normalised URL (host and path, trailing slash and fragment dropped, query kept — distinct queries are distinct results) and capped at 30. Hits several engines agree on rank first.\n\nTWO WAYS IN, one-way equivalent, and no third: a validated principal — the same gate the whole data plane uses — passes straight through, and a caller without one must present the shared service key as X-API-Key, compared in constant time. A deployment with no key configured answers 503 rather than opening the surface to everyone, and a missing or wrong key is 401. It is never an open proxy. There is no tenant scoping beyond that gate, and there is nothing to scope: the results are public web pages, identical for every caller.\n\nIt fails SOFT on the engines and closed only on the gate. An engine that errors or is served a bot-challenge page contributes zero results and never fails the request, so an empty `results` is a real answer — nothing was found — and not an outage. The array is always present, never null.\n\nThe one thing to get right: every method answers identically. This is one handler registered for all of them, and it reads only the query string, so a body sent on the write verbs is ignored rather than refused.","tags":["websearch"],"x-app":"websearch","x-public":true},"post":{"operationId":"post_websearch_search","summary":"Web meta-search, in the SearXNG JSON envelope.","description":"Answers {query, number_of_results, results:[{url, title, content, engine}]} — the exact /search?format=json contract a SearXNG client decodes, so an agent tool configured against SearXNG reaches this with no change. `q` is the query and `language` narrows it; both are read from the QUERY STRING.\n\nServed in-process by a Go meta-search over the engines the platform enables (GET /v1/websearch/engines). The enabled engines run concurrently and their hits are merged, deduplicated by normalised URL (host and path, trailing slash and fragment dropped, query kept — distinct queries are distinct results) and capped at 30. Hits several engines agree on rank first.\n\nTWO WAYS IN, one-way equivalent, and no third: a validated principal — the same gate the whole data plane uses — passes straight through, and a caller without one must present the shared service key as X-API-Key, compared in constant time. A deployment with no key configured answers 503 rather than opening the surface to everyone, and a missing or wrong key is 401. It is never an open proxy. There is no tenant scoping beyond that gate, and there is nothing to scope: the results are public web pages, identical for every caller.\n\nIt fails SOFT on the engines and closed only on the gate. An engine that errors or is served a bot-challenge page contributes zero results and never fails the request, so an empty `results` is a real answer — nothing was found — and not an outage. The array is always present, never null.\n\nThe one thing to get right: every method answers identically. This is one handler registered for all of them, and it reads only the query string, so a body sent on the write verbs is ignored rather than refused.","tags":["websearch"],"x-app":"websearch","x-public":true},"put":{"operationId":"put_websearch_search","summary":"Web meta-search, in the SearXNG JSON envelope.","description":"Answers {query, number_of_results, results:[{url, title, content, engine}]} — the exact /search?format=json contract a SearXNG client decodes, so an agent tool configured against SearXNG reaches this with no change. `q` is the query and `language` narrows it; both are read from the QUERY STRING.\n\nServed in-process by a Go meta-search over the engines the platform enables (GET /v1/websearch/engines). The enabled engines run concurrently and their hits are merged, deduplicated by normalised URL (host and path, trailing slash and fragment dropped, query kept — distinct queries are distinct results) and capped at 30. Hits several engines agree on rank first.\n\nTWO WAYS IN, one-way equivalent, and no third: a validated principal — the same gate the whole data plane uses — passes straight through, and a caller without one must present the shared service key as X-API-Key, compared in constant time. A deployment with no key configured answers 503 rather than opening the surface to everyone, and a missing or wrong key is 401. It is never an open proxy. There is no tenant scoping beyond that gate, and there is nothing to scope: the results are public web pages, identical for every caller.\n\nIt fails SOFT on the engines and closed only on the gate. An engine that errors or is served a bot-challenge page contributes zero results and never fails the request, so an empty `results` is a real answer — nothing was found — and not an outage. The array is always present, never null.\n\nThe one thing to get right: every method answers identically. This is one handler registered for all of them, and it reads only the query string, so a body sent on the write verbs is ignored rather than refused.","tags":["websearch"],"x-app":"websearch","x-public":true}},"/v1/workflow":{"delete":{"operationId":"delete_workflow","summary":"Redirect to the workflow API root","description":"Answers 307 with Location /v1/workflow/ — this address serves nothing itself. The status and the Location are the same on every method; a GET additionally carries the short HTML body a browser falls back to when it does not follow the redirect itself.\n\nA 307 preserves both the method and the body, so a client that follows redirects re-sends the request unchanged to /v1/workflow/ and nothing is lost. A client that does NOT follow redirects sees only the 307 and performs no work — address /v1/workflow/ directly and the hop disappears.","tags":["workflow"],"x-app":"workflow","x-public":true},"get":{"operationId":"get_workflow","summary":"Redirect to the workflow API root","description":"Answers 307 with Location /v1/workflow/ — this address serves nothing itself. The status and the Location are the same on every method; a GET additionally carries the short HTML body a browser falls back to when it does not follow the redirect itself.\n\nA 307 preserves both the method and the body, so a client that follows redirects re-sends the request unchanged to /v1/workflow/ and nothing is lost. A client that does NOT follow redirects sees only the 307 and performs no work — address /v1/workflow/ directly and the hop disappears.","tags":["workflow"],"x-app":"workflow","x-public":true},"patch":{"operationId":"patch_workflow","summary":"Redirect to the workflow API root","description":"Answers 307 with Location /v1/workflow/ — this address serves nothing itself. The status and the Location are the same on every method; a GET additionally carries the short HTML body a browser falls back to when it does not follow the redirect itself.\n\nA 307 preserves both the method and the body, so a client that follows redirects re-sends the request unchanged to /v1/workflow/ and nothing is lost. A client that does NOT follow redirects sees only the 307 and performs no work — address /v1/workflow/ directly and the hop disappears.","tags":["workflow"],"x-app":"workflow","x-public":true},"post":{"operationId":"post_workflow","summary":"Redirect to the workflow API root","description":"Answers 307 with Location /v1/workflow/ — this address serves nothing itself. The status and the Location are the same on every method; a GET additionally carries the short HTML body a browser falls back to when it does not follow the redirect itself.\n\nA 307 preserves both the method and the body, so a client that follows redirects re-sends the request unchanged to /v1/workflow/ and nothing is lost. A client that does NOT follow redirects sees only the 307 and performs no work — address /v1/workflow/ directly and the hop disappears.","tags":["workflow"],"x-app":"workflow","x-public":true},"put":{"operationId":"put_workflow","summary":"Redirect to the workflow API root","description":"Answers 307 with Location /v1/workflow/ — this address serves nothing itself. The status and the Location are the same on every method; a GET additionally carries the short HTML body a browser falls back to when it does not follow the redirect itself.\n\nA 307 preserves both the method and the body, so a client that follows redirects re-sends the request unchanged to /v1/workflow/ and nothing is lost. A client that does NOT follow redirects sees only the 307 and performs no work — address /v1/workflow/ directly and the hop disappears.","tags":["workflow"],"x-app":"workflow","x-public":true}},"/v1/world":{"get":{"operationId":"get_world","summary":"Answers GET /v1/world — the product's public endpoint, naming every wire this surface answers on.","description":"Answers GET /v1/world — the product's public endpoint, naming every wire\nthis surface answers on.\n\nIt exists because two of those wires are INVISIBLE to the generated document.\n/v1/world/mcp and /v1/world/zap are carved off the cloud catch-all by the\ningress and answered by world-gw, so the cloud router never serves them — and\nopenapi.Describe renders prose only for a route the router actually serves,\nwhich is the very property that keeps the document from being able to claim an\noperation nothing answers. Both addresses are real and public, so without this\nop the only way to learn they exist is to read the ingress config. This is\nwhere that fact lives, in the product's own surface.\n\nPublic on purpose: discovery precedes credentials. It reports addresses and\nprotocols only — never feed data, and never the caller's plan, which\nGET /v1/world/limits owns — so there is nothing here to leak.","tags":["world"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/world.worldIndex"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"world","x-public":true,"x-tool":true}},"/v1/world/limits":{"get":{"operationId":"get_world_limits","summary":"Echoes a World plan's rate limits, alert quota and model-API grant, read straight from the live @hanzo/plans catalog, so agents and dashboards configure themselves against the catalog instead of hardcoding tier numbers.","description":"Echoes a World plan's rate limits, alert quota and model-API grant, read\nstraight from the live @hanzo/plans catalog, so agents and dashboards configure\nthemselves against the catalog instead of hardcoding tier numbers.\n\nAn empty or unknown plan resolves world-free, and a catalog failure serves that\nsame free floor rather than erroring — so this always answers 200, and it can only\never under-grant. It reports the contract; it does not enforce it.","tags":["world"],"parameters":[{"name":"plan","in":"query","required":false,"description":"Plan is a World plan id from the live @hanzo/plans catalog, e.g. world-pro.\nEmpty means world-free, and so does an id the catalog does not know — this\nnever fails on an unknown plan.","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/world.limitsView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"world","x-public":true,"x-tool":true}},"/v1/world/news":{"get":{"operationId":"get_world_news","summary":"Returns the caller's merged world-news feed: every source their project's pipeline names — GDELT once per keyword, plus each allowlisted RSS or Atom feed — fetched concurrently, narrowed by the pipeline's keyword/region/source filters, deduplicated by link and sorted freshest first, capped at 50 items.","description":"Returns the caller's merged world-news feed: every source their project's\npipeline names — GDELT once per keyword, plus each allowlisted RSS or Atom feed —\nfetched concurrently, narrowed by the pipeline's keyword/region/source filters,\ndeduplicated by link and sorted freshest first, capped at 50 items.\n\nA project with no stored pipeline gets a sensible default set of world feeds\nrather than an empty answer. A source that fails or times out is SKIPPED: the feed\ndegrades to honest partial results and never 5xxs because one outlet was down.\nReading also publishes the result to the /v1/world/stream subscribers of the same\n(org, project), so a dashboard's own refresh updates every open tab.","tags":["world"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/world.newsResponse"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"world","x-public":true,"x-tool":true}},"/v1/world/pipeline":{"get":{"operationId":"get_world_pipeline","summary":"Returns the caller project's news pipeline: which feeds it reads and how the merged result is filtered.","description":"Returns the caller project's news pipeline: which feeds it reads and how\nthe merged result is filtered. A project that has never written one is answered\nwith the built-in world feeds and `default: true`, so a fresh project sees the\nsame feed /v1/world/news would actually serve rather than an empty configuration.","tags":["world"],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/world.pipelineView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"world","x-public":true,"x-tool":true},"put":{"operationId":"put_world_pipeline","summary":"Replaces the caller project's news pipeline and returns what was stored.","description":"Replaces the caller project's news pipeline and returns what was\nstored. It is a WHOLE replacement, not a patch: a field the request leaves out is\nstored empty, so sending only feeds clears the filters.\n\nEvery feed URL is validated HERE, at the write boundary — http(s) only, and the\nhost must be on the server's allowlist — so a stored pipeline can never name a\nhost the fetcher would later refuse, and the allowlist is one decision in one\nplace rather than a check at each fetch.","tags":["world"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/world.pipelineReq"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/world.pipelineView"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"world","x-public":true,"x-tool":true}},"/v1/world/stream":{"get":{"operationId":"get_world_stream","summary":"Live news refreshes for the caller's org and project, as Server-Sent Events.","description":"Holds the connection open as text/event-stream and pushes a `news` event — the same {items:[…]} body GET /v1/world/news answers — each time the caller's (org, project) feed refreshes, with a `: ping` heartbeat comment every 25s. Delivery is best-effort: a slow consumer is dropped on buffer overrun and reconnects, re-fetching GET /v1/world/news, which stays the source of truth. Requires a validated principal; 401 without one.","tags":["world"],"x-app":"world","x-public":true}},"/v1/x402/settlements":{"get":{"operationId":"get_x402_settlements","summary":"Lists the caller's x402 receipts, newest first: as payer, what its wallet paid; as payee, what its org was paid — each settled payment with what it bought, both parties, the exact amount and when.","description":"Lists the caller's x402 receipts, newest first: as payer, what its\nwallet paid; as payee, what its org was paid — each settled payment with what it\nbought, both parties, the exact amount and when. A payer is the caller's own\naccount, which for a SuperAdmin inspecting another org is still its own and for\na member of the signup org is their own wallet, never the org's; a payee is the\ncaller's own org. An unsettled claim is not a receipt and is never listed.","tags":["x402"],"parameters":[{"name":"role","in":"query","required":false,"description":"Role is payer — what the caller's org paid — or payee — what it was paid.\nPayer when empty.","schema":{"type":"string"},"example":"payee"},{"name":"year","in":"query","required":false,"description":"Year keeps the calendar year (UTC) the payments settled in. Zero keeps\nevery year.","schema":{"format":"int64","type":"integer"},"example":2026}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/x402.settlementList"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"x402","x-public":true,"x-tool":true}},"/v1/x402/settlements/{id}":{"get":{"operationId":"get_x402_settlements_by_id","summary":"Reads one x402 payment receipt by id.","description":"Reads one x402 payment receipt by id.\n\nIt is scoped to the caller's own account — the wallet that was drawn, in the\nbooks that hold it — so one tenant can never read another's settlement, nor one\nmember of the signup org another's, and an id that exists but belongs to\nsomebody else is a 404 exactly like one that does not exist. A caller with no\nbillable identity is refused outright.","tags":["x402"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID is the settlement id from the URL — the deterministic keccak(from|nonce)\nkey an x402 receipt is issued under (the `id` field of a Receipt, and the\n`transaction` of the SettlementResponse on the PAYMENT-RESPONSE header a paid\nrequest answers with).","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/x402.Receipt"}}},"description":"ok"},"default":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/problem-details"}}},"description":"refused"}},"x-app":"x402","x-public":true,"x-tool":true}},"/v1/{name}":{"get":{"operationId":"get_capability","summary":"One capability's operations, with the address and method to call each","description":"What the capability named in the path answers: every published operation, its operationId, its method and its address, and the sentence lifted from the handler that serves it — plus the way back to /v1.\n\nIt answers where the capability serves nothing at its own root. Where it does, that operation is the answer and is described at its own address; a client following the root index reaches the capability either way.\n\nUnauthenticated, and scoped to the same customer surface the root is. A name that is not a published capability is answered exactly as any other unrouted address, so this cannot be asked whether something exists that it would not have listed.","tags":["openapi"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"2XX":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Index"}}}}},"security":[],"x-app":"openapi","x-public":true}}},"components":{"schemas":{"Activity":{"properties":{"FieldCount":{"additionalProperties":{"type":"integer"},"type":"object"},"date":{"type":"string"}},"type":"object"},"App":{"properties":{"basicConfigOptions":{"items":{"$ref":"#/components/schemas/ApplicationConfigOption"},"type":"array"},"createdTime":{"type":"string"},"description":{"type":"string"},"details":{"$ref":"#/components/schemas/ApplicationView"},"displayName":{"type":"string"},"manifest":{"type":"string"},"name":{"type":"string"},"namespace":{"type":"string"},"owner":{"type":"string"},"parameters":{"type":"string"},"status":{"type":"string"},"template":{"type":"string"},"updatedTime":{"type":"string"},"url":{"type":"string"}},"type":"object"},"ApplicationConfigOption":{"properties":{"parameter":{"type":"string"},"setting":{"type":"string"}},"type":"object"},"ApplicationEvent":{"properties":{"count":{"type":"integer"},"firstTime":{"type":"string"},"involvedObject":{"type":"string"},"lastTime":{"type":"string"},"message":{"type":"string"},"name":{"type":"string"},"reason":{"type":"string"},"source":{"type":"string"},"type":{"type":"string"}},"type":"object"},"ApplicationView":{"properties":{"createdTime":{"type":"string"},"credentials":{"items":{"$ref":"#/components/schemas/EnvVariable"},"type":"array"},"deployments":{"items":{"$ref":"#/components/schemas/DeploymentDetail"},"type":"array"},"events":{"items":{"$ref":"#/components/schemas/ApplicationEvent"},"type":"array"},"metrics":{"$ref":"#/components/schemas/ResourceMetrics"},"namespace":{"type":"string"},"services":{"items":{"$ref":"#/components/schemas/ServiceDetail"},"type":"array"},"status":{"type":"string"}},"type":"object"},"Approval":{"properties":{"clause":{"description":"Clause names the clause of the rule that asked for sign-off.","type":"string"},"reason":{"description":"Reason is what a person reads before answering.","type":"string"},"status":{"description":"Status is always held: the op stopped for sign-off and did not run.","type":"string"}},"type":"object"},"Article":{"properties":{"content":{"items":{"$ref":"#/components/schemas/Block"},"type":"array"},"createdTime":{"type":"string"},"displayName":{"type":"string"},"glossary":{"items":{"type":"string"},"type":"array"},"name":{"type":"string"},"owner":{"type":"string"},"text":{"type":"string"},"type":{"type":"string"},"workflow":{"type":"string"}},"type":"object"},"Asset":{"properties":{"createdTime":{"type":"string"},"displayName":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"password":{"type":"string"},"properties":{"type":"string"},"provider":{"type":"string"},"region":{"type":"string"},"state":{"type":"string"},"tag":{"type":"string"},"type":{"type":"string"},"updatedTime":{"type":"string"},"username":{"type":"string"},"zone":{"type":"string"}},"type":"object"},"Audit":{"properties":{"action":{"type":"string"},"block":{"type":"string"},"block2":{"type":"string"},"blockHash":{"type":"string"},"blockHash2":{"type":"string"},"city":{"type":"string"},"clientIp":{"type":"string"},"count":{"type":"integer"},"createdTime":{"type":"string"},"errorText":{"type":"string"},"id":{"type":"integer"},"isTriggered":{"type":"boolean"},"language":{"type":"string"},"method":{"type":"string"},"name":{"type":"string"},"needCommit":{"type":"boolean"},"object":{"type":"string"},"organization":{"type":"string"},"owner":{"type":"string"},"provider":{"type":"string"},"provider2":{"type":"string"},"query":{"type":"string"},"region":{"type":"string"},"requestUri":{"type":"string"},"response":{"type":"string"},"section":{"type":"string"},"transaction":{"type":"string"},"transaction2":{"type":"string"},"unit":{"type":"string"},"user":{"type":"string"},"userAgent":{"type":"string"}},"type":"object"},"BankTally":{"properties":{"ingested":{"type":"integer"},"posted":{"type":"integer"},"questions":{"type":"integer"},"reconciled":{"type":"integer"},"skipped":{"type":"integer"},"transfers":{"type":"integer"}},"type":"object"},"Block":{"properties":{"prompt":{"type":"string"},"state":{"type":"string"},"text":{"type":"string"},"textEn":{"type":"string"},"type":{"type":"string"}},"type":"object"},"Brief":{"properties":{"batch":{"items":{"type":"string"},"type":"array"},"format":{"type":"string"},"glossary":{"additionalProperties":{"type":"string"},"type":"object"},"model":{"type":"string"},"source":{"type":"string"},"target":{"type":"string"},"text":{"type":"string"},"tier":{"type":"string"}},"required":["target"],"type":"object"},"Candidate":{"properties":{"isHit":{"type":"boolean"},"text":{"type":"string"}},"type":"object"},"Capability":{"type":"object","properties":{"description":{"type":"string"},"href":{"type":"string"},"name":{"type":"string"},"stage":{"type":"string"}}},"CaptureBatch":{"properties":{"batch":{"items":{"$ref":"#/components/schemas/CaptureEvent"},"type":"array"},"events":{"items":{"$ref":"#/components/schemas/CaptureEvent"},"type":"array"}},"type":"object"},"CaptureEvent":{"properties":{"anonymousId":{"type":"string"},"channel":{"type":"string"},"clip":{"$ref":"#/components/schemas/ClipBody"},"currency":{"type":"string"},"distinctId":{"type":"string"},"environment":{"type":"string"},"error":{"$ref":"#/components/schemas/Exception"},"event":{"type":"string"},"groupId":{"type":"string"},"groupType":{"type":"string"},"kind":{"type":"string"},"lastUtm":{"$ref":"#/components/schemas/UTM"},"level":{"type":"string"},"library":{"type":"string"},"libraryVersion":{"type":"string"},"log":{"$ref":"#/components/schemas/LogBody"},"messageId":{"type":"string"},"metric":{"$ref":"#/components/schemas/MetricBody"},"path":{"type":"string"},"personId":{"type":"string"},"product":{"type":"string"},"productId":{"type":"string"},"properties":{"additionalProperties":{},"type":"object"},"quantity":{"type":"integer"},"refCode":{"type":"string"},"referrer":{"type":"string"},"release":{"type":"string"},"resource":{"type":"string"},"revenue":{"type":"number"},"service":{"type":"string"},"sessionId":{"type":"string"},"signupWeek":{"type":"string"},"site":{"type":"string"},"span":{"$ref":"#/components/schemas/SpanBody"},"spanId":{"type":"string"},"timestamp":{"type":"string"},"traceId":{"type":"string"},"type":{"type":"string"},"url":{"type":"string"},"utm":{"$ref":"#/components/schemas/UTM"}},"type":"object"},"CaptureResult":{"properties":{"accepted":{"type":"integer"},"dropped":{"type":"integer"},"withheld":{"type":"integer"}},"type":"object"},"Captured":{"properties":{"answered":{"description":"Answered is the label the caller was answered: the org's capability's when\none answered, else Kai's own.","type":"string"},"key":{"type":"string"},"labels":{"items":{"type":"string"},"type":"array"},"type":{"type":"string"}},"type":"object"},"Cart":{"properties":{"createdAt":{"description":"CreatedAt is when the cart was opened, RFC3339.","type":"string"},"currency":{"description":"Currency is the ISO 4217 code every amount below is denominated in.","type":"string"},"discountCents":{"description":"DiscountCents is what coupons and promotions took off, in whole cents.","format":"int64","type":"integer"},"email":{"description":"Email is the shopper's address, when the cart carries one.","type":"string"},"id":{"description":"ID is the cart's id — what every other cart op addresses it by, and what a\nstorefront persists against the browser session.","type":"string"},"items":{"description":"Items are the cart's lines, in the order they were added.","items":{"$ref":"#/components/schemas/CartItem"},"type":"array"},"lineTotalCents":{"description":"LineTotalCents is the sum of the lines before any discount, in whole cents.","format":"int64","type":"integer"},"order":{"description":"Order is the order this cart became, once checkout completed it. Empty\nuntil then, and its presence is what makes a cart final.","type":"string"},"shippingCents":{"description":"ShippingCents is the shipping charge, in whole cents. It stays zero until a\nshipping option is priced at checkout.","format":"int64","type":"integer"},"status":{"description":"Status is \"active\" for a cart still being filled, \"ordered\" once checkout\nturned it into an order, and \"discarded\" when the shopper abandoned it.","type":"string"},"store":{"description":"Store is the storefront the cart is being filled on.","type":"string"},"subtotalCents":{"description":"SubtotalCents is LineTotalCents less DiscountCents, in whole cents.","format":"int64","type":"integer"},"taxCents":{"description":"TaxCents is the sales tax, in whole cents. It stays zero until checkout\nresolves the shopper's tax region.","format":"int64","type":"integer"},"totalCents":{"description":"TotalCents is what the shopper pays: subtotal plus shipping plus tax, in\nwhole cents.","format":"int64","type":"integer"},"updatedAt":{"description":"UpdatedAt is when the cart was last amended, RFC3339.","type":"string"},"user":{"description":"User is the signed-in shopper this cart belongs to, empty for a guest cart.","type":"string"}},"type":"object"},"CartItem":{"properties":{"free":{"description":"Free reports a line that costs nothing because a coupon or a promotion made\nit so, rather than because its price is zero.","type":"boolean"},"id":{"description":"ID is the line's identity — the variant id when the line is a variant,\notherwise the product id. It is what a subsequent set call addresses.","type":"string"},"kind":{"description":"Kind is \"variant\" when this line is a specific sellable variant and\n\"product\" when it is the product itself.","type":"string"},"name":{"description":"Name is the item's display name, cached onto the line when it was added so\na cart renders without a second read.","type":"string"},"priceCents":{"description":"PriceCents is the unit price in whole cents, cached at the moment the line\nwas added. The line's contribution to the cart is this times Quantity.","format":"int64","type":"integer"},"quantity":{"description":"Quantity is how many units of this item the cart holds.","format":"int64","type":"integer"},"sku":{"description":"SKU is the line's stock-keeping unit — the variant's when it has one,\notherwise the product's. Empty when neither carries one.","type":"string"}},"type":"object"},"CartItemSet":{"properties":{"id":{"description":"ID is the cart to amend, from the path.","type":"string"},"product":{"description":"Product names the catalog product to set, by its id or its URL slug. Give\nthis or Variant, never both; a request naming neither is refused.","type":"string"},"quantity":{"description":"Quantity is how many of that item the cart should hold AFTER this call — it\nis the resulting count, not a delta, so sending 3 twice leaves 3 and not 6.\nZERO REMOVES the line, which is the only way to take an item out.","format":"int64","type":"integer"},"variant":{"description":"Variant names the specific sellable variant to set, by its id or its SKU.\nPrefer it over Product for anything sold in sizes, colours or tiers — the\nprice and the stock are the variant's, not the product's.","type":"string"}},"type":"object"},"CartOpen":{"properties":{"currency":{"description":"Currency is the ISO 4217 code the cart is priced in, lower-cased. Empty\nmeans usd.","type":"string"},"email":{"description":"Email is the shopper's address, for a cart that belongs to someone who has\nnot signed in. It is what a guest checkout and an abandoned-cart follow-up\nkey on. Empty is fine.","type":"string"},"store":{"description":"Store is the storefront this cart is being filled on. Empty uses the org's\ndefault store, which is what a single-storefront merchant always wants.","type":"string"},"user":{"description":"User is the id of the signed-in shopper this cart belongs to, when there is\none. Empty means a guest cart identified only by its own id.","type":"string"}},"type":"object"},"Chat":{"properties":{"category":{"type":"string"},"clientIp":{"type":"string"},"clientIpDesc":{"type":"string"},"createdTime":{"type":"string"},"currency":{"type":"string"},"displayName":{"type":"string"},"isDeleted":{"type":"boolean"},"isHidden":{"type":"boolean"},"messageCount":{"type":"integer"},"modelProvider":{"type":"string"},"name":{"type":"string"},"needTitle":{"type":"boolean"},"organization":{"type":"string"},"owner":{"type":"string"},"price":{"type":"number"},"store":{"type":"string"},"tokenCount":{"type":"integer"},"type":{"type":"string"},"updatedTime":{"type":"string"},"user":{"type":"string"},"user1":{"type":"string"},"user2":{"type":"string"},"userAgent":{"type":"string"},"userAgentDesc":{"type":"string"},"users":{"items":{"type":"string"},"type":"array"}},"type":"object"},"ChatTurn":{"properties":{"assets":{"items":{"type":"string"},"type":"array"},"brand":{"type":"string"},"message":{"type":"string"},"model":{"type":"string"},"thread":{"type":"string"}},"type":"object"},"ClipBody":{"properties":{"bytes":{"type":"integer"},"duration":{"type":"integer"},"object":{"type":"string"}},"type":"object"},"Connection":{"properties":{"clientIp":{"type":"string"},"clientIpDesc":{"type":"string"},"code":{"type":"integer"},"commandCount":{"type":"integer"},"connectionId":{"type":"string"},"createdTime":{"type":"string"},"creator":{"type":"string"},"endTime":{"type":"string"},"height":{"type":"integer"},"message":{"type":"string"},"mode":{"type":"string"},"name":{"type":"string"},"node":{"type":"string"},"operations":{"items":{"type":"string"},"type":"array"},"owner":{"type":"string"},"protocol":{"type":"string"},"recording":{"type":"string"},"reviewed":{"type":"boolean"},"startTime":{"type":"string"},"status":{"type":"string"},"userAgent":{"type":"string"},"userAgentDesc":{"type":"string"},"width":{"type":"integer"}},"type":"object"},"ContainerDetail":{"properties":{"image":{"type":"string"},"name":{"type":"string"},"resources":{"$ref":"#/components/schemas/ResourceRequests"}},"type":"object"},"CorrectIn":{"properties":{"answer":{"description":"Answer is the right option label; a score's level may be named by its\nindex.","type":"string"},"cohort":{"description":"Cohort groups corrections the org files together.","type":"string"},"decision":{"description":"Decision is the decision's id.","type":"string"},"note":{"description":"Note says why, for the person reading it later.","type":"string"},"question":{"description":"Question is the question's key.","type":"string"}},"type":"object"},"Correction":{"properties":{"answer":{"description":"Answer is the right answer; Base what Kai answered.","type":"string"},"at":{"format":"int64","type":"integer"},"base":{"type":"string"},"by":{"type":"string"},"cohort":{"type":"string"},"decision":{"type":"string"},"id":{"type":"string"},"labels":{"items":{"type":"string"},"type":"array"},"note":{"type":"string"},"question":{"type":"string"},"state":{"description":"State is captured when the decision's state is held and the correction can\nteach, missing when the decision was made with capture off.","type":"string"},"type":{"type":"string"}},"type":"object"},"Corrections":{"properties":{"data":{"items":{"$ref":"#/components/schemas/Correction"},"type":"array"},"questions":{"description":"Questions are the decision's captured questions, by key; none when it was\nmade with capture off.","items":{"$ref":"#/components/schemas/Captured"},"type":"array"}},"type":"object"},"Count":{"properties":{"chatCount":{"type":"integer"},"currency":{"type":"string"},"date":{"type":"string"},"messageCount":{"type":"integer"},"price":{"type":"number"},"tokenCount":{"type":"integer"},"userCount":{"type":"integer"}},"type":"object"},"Decision":{"properties":{"defaults":{"$ref":"#/components/schemas/Grants"},"floor":{"type":"integer"},"mode":{"type":"string"},"refused":{"type":"boolean"},"region":{"type":"string"},"version":{"type":"integer"}},"type":"object"},"Declaration":{"properties":{"application":{"type":"string"},"automated":{"type":"boolean"},"component":{"type":"string"},"digest":{"type":"string"},"env":{"items":{"$ref":"#/components/schemas/declareEnv"},"type":"array"},"hosts":{"items":{"type":"string"},"type":"array"},"name":{"type":"string"},"org":{"type":"string"},"partOf":{"type":"string"},"path":{"type":"string"},"project":{"type":"string"},"replicas":{"type":"integer"},"repository":{"type":"string"},"secrets":{"items":{"$ref":"#/components/schemas/SecretRef"},"type":"array"},"tag":{"type":"string"}},"type":"object"},"Delivery":{"properties":{"detected_source":{"type":"string"},"model":{"type":"string"},"tier":{"type":"string"},"translations":{"items":{"$ref":"#/components/schemas/Translation"},"type":"array"},"usage":{"$ref":"#/components/schemas/Tally"}},"type":"object"},"DeploymentDetail":{"properties":{"containers":{"items":{"$ref":"#/components/schemas/ContainerDetail"},"type":"array"},"createdTime":{"type":"string"},"name":{"type":"string"},"readyReplicas":{"type":"integer"},"replicas":{"type":"integer"},"status":{"type":"string"}},"type":"object"},"DestinationField":{"properties":{"example":{"type":"string"},"key":{"type":"string"},"label":{"type":"string"},"required":{"type":"boolean"}},"type":"object"},"DestinationStatus":{"properties":{"account":{"type":"string"},"category":{"type":"string"},"config":{"additionalProperties":{"type":"string"},"type":"object"},"connected":{"type":"boolean"},"enabled":{"type":"boolean"},"fields":{"items":{"$ref":"#/components/schemas/DestinationField"},"type":"array"},"live":{"type":"boolean"},"name":{"type":"string"},"pixel":{"type":"boolean"},"platform":{"type":"string"},"secrets":{"items":{"type":"string"},"type":"array"}},"type":"object"},"DocSearchResult":{"properties":{"breadcrumbs":{"items":{"type":"string"},"type":"array"},"content":{"type":"string"},"file_id":{"type":"string"},"id":{"type":"string"},"title":{"type":"string"},"type":{"type":"string"},"url":{"type":"string"}},"type":"object"},"EnvVariable":{"properties":{"name":{"type":"string"},"value":{"type":"string"}},"type":"object"},"Envelope":{"description":"The resource surface's response. `status` is the verdict, not the HTTP code: a handled failure is still 200.","properties":{"data":{"description":"The operation's own result."},"data2":{"description":"A second result the operation defines, when it has one."},"msg":{"description":"Empty on success, the reason on failure.","type":"string"},"status":{"enum":["ok","error"],"type":"string"}},"required":["status","msg"],"type":"object"},"ExampleQuestion":{"properties":{"image":{"type":"string"},"text":{"type":"string"},"title":{"type":"string"}},"type":"object"},"Exception":{"properties":{"frames":{"items":{"$ref":"#/components/schemas/Frame"},"type":"array"},"handled":{"type":"boolean"},"message":{"type":"string"},"stack":{"type":"string"},"type":{"type":"string"}},"type":"object"},"Extracted":{"properties":{"category":{"type":"string"},"currency":{"type":"string"},"issuedAt":{"type":"string"},"lineItems":{"items":{"$ref":"#/components/schemas/LineItem"},"type":"array"},"merchant":{"type":"string"},"note":{"type":"string"},"taxCents":{"type":"integer"},"totalCents":{"type":"integer"}},"type":"object"},"File":{"properties":{"createdTime":{"type":"string"},"errorText":{"type":"string"},"filename":{"type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"size":{"type":"integer"},"status":{"type":"string"},"storageProvider":{"type":"string"},"store":{"type":"string"},"tokenCount":{"type":"integer"},"url":{"type":"string"}},"type":"object"},"FinetuneJob":{"properties":{"baseModel":{"type":"string"},"costCents":{"type":"integer"},"crName":{"type":"string"},"createdBy":{"type":"string"},"createdTime":{"type":"string"},"dataset":{"type":"string"},"deployUrl":{"type":"string"},"deployedModel":{"type":"string"},"displayName":{"type":"string"},"error":{"type":"string"},"finishedTime":{"type":"string"},"gpuCount":{"type":"integer"},"gpuSeconds":{"type":"integer"},"gpuType":{"type":"string"},"hyperparams":{"type":"string"},"message":{"type":"string"},"metered":{"type":"boolean"},"method":{"type":"string"},"name":{"type":"string"},"namespace":{"type":"string"},"numNodes":{"type":"integer"},"outputUri":{"type":"string"},"owner":{"type":"string"},"preset":{"type":"string"},"progress":{"type":"integer"},"runtime":{"type":"string"},"startedTime":{"type":"string"},"status":{"type":"string"},"task":{"type":"string"},"updatedTime":{"type":"string"}},"type":"object"},"FormItem":{"properties":{"label":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"visible":{"type":"boolean"},"width":{"type":"string"}},"type":"object"},"Frame":{"properties":{"column":{"type":"integer"},"file":{"type":"string"},"function":{"type":"string"},"line":{"type":"integer"}},"type":"object"},"Grants":{"properties":{"ads":{"type":"boolean"},"analytics":{"type":"boolean"},"marketing":{"type":"boolean"}},"type":"object"},"Graph":{"properties":{"category":{"type":"string"},"createdTime":{"type":"string"},"density":{"type":"integer"},"displayName":{"type":"string"},"endTime":{"type":"string"},"errorText":{"type":"string"},"layout":{"type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"startTime":{"type":"string"},"store":{"type":"string"},"text":{"type":"string"}},"type":"object"},"HfDataset":{"properties":{"downloads":{"type":"integer"},"gated":{},"id":{"type":"string"},"lastModified":{"type":"string"},"likes":{"type":"integer"},"private":{"type":"boolean"},"tags":{"items":{"type":"string"},"type":"array"}},"type":"object"},"HfModel":{"properties":{"downloads":{"type":"integer"},"gated":{},"id":{"type":"string"},"lastModified":{"type":"string"},"library_name":{"type":"string"},"likes":{"type":"integer"},"pipeline_tag":{"type":"string"},"private":{"type":"boolean"},"tags":{"items":{"type":"string"},"type":"array"}},"type":"object"},"HfRepoInfo":{"properties":{"downloads":{"type":"integer"},"gated":{},"id":{"type":"string"},"lastModified":{"type":"string"},"likes":{"type":"integer"},"pipeline_tag":{"type":"string"},"private":{"type":"boolean"},"siblings":{"items":{"$ref":"#/components/schemas/HfSibling"},"type":"array"},"tags":{"items":{"type":"string"},"type":"array"}},"type":"object"},"HfSibling":{"properties":{"rfilename":{"type":"string"},"size":{"type":"integer"}},"type":"object"},"InboxItem":{"properties":{"category":{"type":"string"},"confidence":{"type":"string"},"createdAt":{"type":"string"},"extracted":{"$ref":"#/components/schemas/Extracted"},"filename":{"type":"string"},"id":{"type":"string"},"status":{"type":"string"},"vendor":{"type":"string"}},"type":"object"},"Index":{"type":"object","properties":{"_links":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/Link"}},"description":{"type":"string"},"name":{"type":"string"},"operations":{"type":"array","items":{"$ref":"#/components/schemas/Op"}},"stage":{"type":"string"}}},"IngestStats":{"properties":{"async":{"type":"boolean"},"documentsIndexed":{"type":"integer"},"errors":{"items":{"type":"string"},"type":"array"},"filesIngested":{"type":"integer"},"filesSkipped":{"type":"integer"},"indexName":{"type":"string"},"skipped":{"items":{"type":"string"},"type":"array"},"source":{"type":"string"},"store":{"type":"string"},"workflowId":{"type":"string"}},"type":"object"},"Label":{"properties":{"endTime":{"type":"number"},"id":{"type":"string"},"speaker":{"type":"string"},"startTime":{"type":"number"},"tag1":{"type":"string"},"tag2":{"type":"string"},"tag3":{"type":"string"},"text":{"type":"string"},"type":{"type":"string"},"user":{"type":"string"}},"type":"object"},"Layout":{"properties":{"category":{"type":"string"},"createdTime":{"type":"string"},"displayName":{"type":"string"},"formItems":{"items":{"$ref":"#/components/schemas/FormItem"},"type":"array"},"name":{"type":"string"},"owner":{"type":"string"},"position":{"type":"string"},"tag":{"type":"string"},"type":{"type":"string"},"url":{"type":"string"}},"type":"object"},"Leg":{"properties":{"account":{"type":"string"},"credit":{"type":"integer"},"debit":{"type":"integer"}},"type":"object"},"LineItem":{"properties":{"amountCents":{"type":"integer"},"description":{"type":"string"}},"type":"object"},"Link":{"type":"object","properties":{"href":{"type":"string"}}},"LogBody":{"properties":{"body":{"type":"string"},"number":{"type":"integer"},"severity":{"type":"string"}},"type":"object"},"MCPError":{"type":"object","properties":{"code":{"type":"integer"},"data":{},"message":{"type":"string"}}},"MCPRequest":{"type":"object","properties":{"id":{},"jsonrpc":{"type":"string"},"method":{"type":"string"},"params":{"type":"object","additionalProperties":{}}}},"MCPResponse":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/MCPError"},"id":{},"jsonrpc":{"type":"string"},"result":{"type":"object","additionalProperties":{}}}},"Memory":{"properties":{"content":{"type":"string"},"createdTime":{"type":"string"},"dimension":{"type":"integer"},"embedding":{"items":{"type":"number"},"type":"array"},"kind":{"type":"string"},"metadata":{"additionalProperties":{"type":"string"},"type":"object"},"name":{"type":"string"},"owner":{"type":"string"},"score":{"type":"number"},"updatedTime":{"type":"string"},"userId":{"type":"string"}},"type":"object"},"Message":{"properties":{"answeredTime":{"type":"string"},"author":{"type":"string"},"chat":{"type":"string"},"claimedTime":{"type":"string"},"comment":{"type":"string"},"createdTime":{"type":"string"},"currency":{"type":"string"},"dislikeUsers":{"items":{"type":"string"},"type":"array"},"embeddingProvider":{"type":"string"},"errorText":{"type":"string"},"fileName":{"type":"string"},"isAlerted":{"type":"boolean"},"isDeleted":{"type":"boolean"},"isHidden":{"type":"boolean"},"isRegenerated":{"type":"boolean"},"likeUsers":{"items":{"type":"string"},"type":"array"},"modelProvider":{"type":"string"},"name":{"type":"string"},"needNotify":{"type":"boolean"},"organization":{"type":"string"},"owner":{"type":"string"},"price":{"type":"number"},"reasonText":{"type":"string"},"replyTo":{"type":"string"},"searchResults":{"items":{"$ref":"#/components/schemas/model.SearchResult"},"type":"array"},"store":{"type":"string"},"suggestions":{"items":{"$ref":"#/components/schemas/Candidate"},"type":"array"},"text":{"type":"string"},"textTokenCount":{"type":"integer"},"tokenCount":{"type":"integer"},"toolCalls":{"items":{"$ref":"#/components/schemas/model.ToolCall"},"type":"array"},"transactionId":{"type":"string"},"user":{"type":"string"},"vectorScores":{"items":{"$ref":"#/components/schemas/VectorScore"},"type":"array"},"webSearchEnabled":{"type":"boolean"}},"type":"object"},"MetricBody":{"properties":{"labels":{"additionalProperties":{},"type":"object"},"name":{"type":"string"},"value":{"type":"number"}},"type":"object"},"ModelAccess":{"properties":{"createdTime":{"type":"string"},"email":{"type":"string"},"model":{"type":"string"},"owner":{"type":"string"},"status":{"type":"string"},"updatedTime":{"type":"string"},"user":{"type":"string"}},"type":"object"},"ModelRoute":{"properties":{"costInPerMillion":{"type":"number"},"costOutPerMillion":{"type":"number"},"createdTime":{"type":"string"},"enabled":{"type":"boolean"},"fallback1Provider":{"type":"string"},"fallback1Upstream":{"type":"string"},"fallback2Provider":{"type":"string"},"fallback2Upstream":{"type":"string"},"hidden":{"type":"boolean"},"inputPricePerMillion":{"type":"number"},"modelName":{"type":"string"},"outputPricePerMillion":{"type":"number"},"ownedBy":{"type":"string"},"owner":{"type":"string"},"premium":{"type":"boolean"},"priced":{"type":"boolean"},"provider":{"type":"string"},"updatedTime":{"type":"string"},"upstream":{"type":"string"}},"type":"object"},"Node":{"properties":{"autoQuery":{"type":"boolean"},"category":{"type":"string"},"cpuSize":{"type":"string"},"createdTime":{"type":"string"},"description":{"type":"string"},"displayName":{"type":"string"},"enableRemoteApp":{"type":"boolean"},"isPermanent":{"type":"boolean"},"language":{"type":"string"},"machineName":{"type":"string"},"memSize":{"type":"string"},"name":{"type":"string"},"os":{"type":"string"},"owner":{"type":"string"},"patches":{"items":{"$ref":"#/components/schemas/Patch"},"type":"array"},"privateIp":{"type":"string"},"publicIp":{"type":"string"},"remoteApps":{"items":{"$ref":"#/components/schemas/RemoteApp"},"type":"array"},"remotePassword":{"type":"string"},"remotePort":{"type":"integer"},"remoteProtocol":{"type":"string"},"remoteUsername":{"type":"string"},"services":{"items":{"$ref":"#/components/schemas/Service"},"type":"array"},"size":{"type":"string"},"tag":{"type":"string"},"type":{"type":"string"},"updatedTime":{"type":"string"}},"type":"object"},"Op":{"type":"object","properties":{"href":{"type":"string"},"method":{"type":"string"},"operationId":{"type":"string"},"summary":{"type":"string"}}},"PagesDeploy":{"properties":{"branch":{"type":"string"}},"type":"object"},"Patch":{"properties":{"category":{"type":"string"},"expectedStatus":{"type":"string"},"installTime":{"type":"string"},"message":{"type":"string"},"name":{"type":"string"},"size":{"type":"string"},"status":{"type":"string"},"title":{"type":"string"},"url":{"type":"string"}},"type":"object"},"Properties":{"properties":{"collectedTime":{"type":"string"},"subject":{"type":"string"}},"type":"object"},"Provider":{"properties":{"apiVersion":{"type":"string"},"asset":{"type":"string"},"browserUrl":{"type":"string"},"category":{"type":"string"},"chain":{"type":"string"},"clientId":{"type":"string"},"clientSecret":{"type":"string"},"compatibleProvider":{"type":"string"},"configText":{"type":"string"},"contractMethod":{"type":"string"},"contractName":{"type":"string"},"createdTime":{"type":"string"},"currency":{"type":"string"},"displayName":{"type":"string"},"enableThinking":{"type":"boolean"},"errorText":{"type":"string"},"flavor":{"type":"string"},"frequencyPenalty":{"type":"number"},"inputPricePerThousandTokens":{"type":"number"},"isDefault":{"type":"boolean"},"isRemote":{"type":"boolean"},"mcpTools":{"items":{"$ref":"#/components/schemas/agent.McpTools"},"type":"array"},"name":{"type":"string"},"network":{"type":"string"},"outputPricePerThousandTokens":{"type":"number"},"owner":{"type":"string"},"presencePenalty":{"type":"number"},"providerKey":{"type":"string"},"providerUrl":{"type":"string"},"rawText":{"type":"string"},"region":{"type":"string"},"resultSummary":{"type":"string"},"runner":{"type":"string"},"signCert":{"type":"string"},"signKey":{"type":"string"},"state":{"type":"string"},"subType":{"type":"string"},"target":{"type":"string"},"targetMode":{"type":"string"},"temperature":{"type":"number"},"testContent":{"type":"string"},"text":{"type":"string"},"topK":{"type":"integer"},"topP":{"type":"number"},"type":{"type":"string"},"userCert":{"type":"string"},"userKey":{"type":"string"}},"type":"object"},"Question":{"properties":{"account":{"type":"string"},"amount":{"type":"string"},"id":{"type":"string"},"kind":{"type":"string"},"postedAt":{"type":"string"},"text":{"type":"string"}},"type":"object"},"RagEmbedResult":{"properties":{"chunks":{"type":"integer"},"file_id":{"type":"string"},"filename":{"type":"string"},"index_name":{"type":"string"},"store":{"type":"string"}},"type":"object"},"Remark":{"properties":{"isPublic":{"type":"boolean"},"score":{"type":"string"},"text":{"type":"string"},"timestamp":{"type":"string"},"user":{"type":"string"}},"type":"object"},"RemoteApp":{"properties":{"no":{"type":"integer"},"remoteAppArgs":{"type":"string"},"remoteAppDir":{"type":"string"},"remoteAppName":{"type":"string"}},"type":"object"},"ResourceMetrics":{"properties":{"cpuPercentage":{"type":"number"},"cpuUsage":{"type":"string"},"memoryPercentage":{"type":"number"},"memoryUsage":{"type":"string"},"podCount":{"type":"integer"}},"type":"object"},"ResourceRequests":{"properties":{"cpu":{"type":"string"},"memory":{"type":"string"}},"type":"object"},"Root":{"type":"object","properties":{"_links":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/Link"}},"capabilities":{"type":"array","items":{"$ref":"#/components/schemas/Capability"}}}},"RoutingVersion":{"properties":{"actor":{"type":"string"},"base":{"type":"integer"},"boot":{"type":"string"},"catalog":{"type":"string"},"createdTime":{"type":"string"},"diff":{"type":"string"},"family":{"type":"string"},"id":{"type":"integer"},"note":{"type":"string"},"sum":{"type":"string"}},"type":"object"},"Scale":{"properties":{"createdTime":{"type":"string"},"displayName":{"type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"state":{"type":"string"},"text":{"type":"string"}},"type":"object"},"ScanDraft":{"properties":{"balanced":{"type":"boolean"},"category":{"type":"string"},"confidence":{"type":"string"},"extracted":{"$ref":"#/components/schemas/Extracted"},"questions":{"items":{"$ref":"#/components/schemas/Question"},"type":"array"},"scanId":{"type":"string"},"vendor":{"type":"string"},"voucher":{"$ref":"#/components/schemas/Voucher"}},"type":"object"},"SecretRef":{"properties":{"env":{"type":"string"},"keys":{"items":{"type":"string"},"type":"array"},"path":{"type":"string"},"project":{"type":"string"}},"type":"object"},"Service":{"properties":{"expectedStatus":{"type":"string"},"message":{"type":"string"},"name":{"type":"string"},"no":{"type":"integer"},"path":{"type":"string"},"port":{"type":"integer"},"processId":{"type":"integer"},"status":{"type":"string"},"subStatus":{"type":"string"}},"type":"object"},"ServiceDetail":{"properties":{"clusterIP":{"type":"string"},"createdTime":{"type":"string"},"externalHost":{"type":"string"},"externalIP":{"type":"string"},"internalHost":{"type":"string"},"name":{"type":"string"},"ports":{"items":{"$ref":"#/components/schemas/ServicePort"},"type":"array"},"type":{"type":"string"}},"type":"object"},"ServicePort":{"properties":{"name":{"type":"string"},"nodePort":{"type":"integer"},"port":{"type":"integer"},"protocol":{"type":"string"},"url":{"type":"string"}},"type":"object"},"Session":{"properties":{"createdTime":{"type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"sessionId":{"items":{"type":"string"},"type":"array"}},"type":"object"},"SpanBody":{"properties":{"duration":{"type":"integer"},"id":{"type":"string"},"kind":{"type":"string"},"parent":{"type":"string"},"status":{"type":"string"},"trace":{"type":"string"}},"type":"object"},"Store":{"properties":{"agentProvider":{"type":"string"},"avatar":{"type":"string"},"builtinTools":{"items":{"type":"string"},"type":"array"},"chatCount":{"type":"integer"},"childModelProviders":{"items":{"type":"string"},"type":"array"},"childStores":{"items":{"type":"string"},"type":"array"},"createdTime":{"type":"string"},"disableFileUpload":{"type":"boolean"},"displayName":{"type":"string"},"embeddingProvider":{"type":"string"},"enableTtsStreaming":{"type":"boolean"},"exampleQuestions":{"items":{"$ref":"#/components/schemas/ExampleQuestion"},"type":"array"},"faviconUrl":{"type":"string"},"fileTree":{"$ref":"#/components/schemas/TreeFile"},"footerHtml":{"type":"string"},"forbiddenWords":{"items":{"type":"string"},"type":"array"},"frequency":{"type":"integer"},"hideThinking":{"type":"boolean"},"htmlTitle":{"type":"string"},"imageProvider":{"type":"string"},"isDefault":{"type":"boolean"},"knowledgeCount":{"type":"integer"},"limitMinutes":{"type":"integer"},"logoUrl":{"type":"string"},"memoryLimit":{"type":"integer"},"messageCount":{"type":"integer"},"modelProvider":{"type":"string"},"name":{"type":"string"},"navItems":{"items":{"type":"string"},"type":"array"},"owner":{"type":"string"},"prompt":{"type":"string"},"propertiesMap":{"additionalProperties":{"$ref":"#/components/schemas/Properties"},"type":"object"},"searchProvider":{"type":"string"},"showAutoRead":{"type":"boolean"},"speechToTextProvider":{"type":"string"},"splitProvider":{"type":"string"},"state":{"type":"string"},"storageProvider":{"type":"string"},"storageSubpath":{"type":"string"},"suggestionCount":{"type":"integer"},"textToSpeechProvider":{"type":"string"},"themeColor":{"type":"string"},"title":{"type":"string"},"vectorStoreId":{"type":"string"},"vectorStores":{"items":{"type":"string"},"type":"array"},"welcome":{"type":"string"},"welcomeText":{"type":"string"},"welcomeTitle":{"type":"string"}},"type":"object"},"Sweep":{"properties":{"asset":{"type":"string"},"command":{"type":"string"},"createdTime":{"type":"string"},"displayName":{"type":"string"},"errorText":{"type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"provider":{"type":"string"},"rawResult":{"type":"string"},"result":{"type":"string"},"resultSummary":{"type":"string"},"runner":{"type":"string"},"state":{"type":"string"},"target":{"type":"string"},"targetMode":{"type":"string"},"updatedTime":{"type":"string"}},"type":"object"},"Tally":{"properties":{"cached":{"type":"integer"},"characters":{"type":"integer"},"failed":{"type":"integer"},"strings":{"type":"integer"},"translated":{"type":"integer"}},"type":"object"},"Task":{"properties":{"activity":{"type":"string"},"createdTime":{"type":"string"},"displayName":{"type":"string"},"documentText":{"type":"string"},"documentUrl":{"type":"string"},"example":{"type":"string"},"grade":{"type":"string"},"labels":{"items":{"type":"string"},"type":"array"},"log":{"type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"path":{"type":"string"},"provider":{"type":"string"},"result":{"type":"string"},"scale":{"type":"string"},"score":{"type":"number"},"subject":{"type":"string"},"topic":{"type":"string"},"type":{"type":"string"}},"type":"object"},"Template":{"properties":{"basicConfigOptions":{"items":{"$ref":"#/components/schemas/TemplateConfigOption"},"type":"array"},"createdTime":{"type":"string"},"description":{"type":"string"},"displayName":{"type":"string"},"enableBasicConfig":{"type":"boolean"},"icon":{"type":"string"},"manifest":{"type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"readme":{"type":"string"},"updatedTime":{"type":"string"},"version":{"type":"string"}},"type":"object"},"TemplateConfigOption":{"properties":{"default":{"type":"string"},"description":{"type":"string"},"options":{"items":{"type":"string"},"type":"array"},"parameter":{"type":"string"},"required":{"type":"boolean"},"type":{"type":"string"}},"type":"object"},"TrafficCountryCount":{"properties":{"count":{"type":"integer"},"country":{"type":"string"}},"type":"object"},"TrafficGlobe":{"properties":{"points":{"items":{"$ref":"#/components/schemas/TrafficPoint"},"type":"array"},"totals":{"$ref":"#/components/schemas/TrafficTotals"},"window":{"$ref":"#/components/schemas/TrafficWindow"}},"type":"object"},"TrafficPoint":{"properties":{"byService":{"additionalProperties":{"type":"integer"},"type":"object"},"byTask":{"additionalProperties":{"type":"integer"},"type":"object"},"count":{"type":"integer"},"country":{"type":"string"},"lat":{"type":"number"},"lon":{"type":"number"},"region":{"type":"string"}},"type":"object"},"TrafficTotals":{"properties":{"rpm_60m":{"type":"number"},"rps_1m":{"type":"number"},"top_countries":{"items":{"$ref":"#/components/schemas/TrafficCountryCount"},"type":"array"}},"type":"object"},"TrafficWindow":{"properties":{"minutes":{"type":"integer"},"since":{"type":"string"},"until":{"type":"string"}},"type":"object"},"Translation":{"properties":{"cached":{"type":"boolean"},"error":{"type":"string"},"source":{"type":"string"},"state":{"type":"string"},"text":{"type":"string"}},"type":"object"},"TreeFile":{"properties":{"children":{"items":{"$ref":"#/components/schemas/TreeFile"},"type":"array"},"createdTime":{"type":"string"},"isLeaf":{"type":"boolean"},"key":{"type":"string"},"size":{"type":"integer"},"title":{"type":"string"},"url":{"type":"string"}},"type":"object"},"UTM":{"properties":{"campaign":{"type":"string"},"content":{"type":"string"},"medium":{"type":"string"},"source":{"type":"string"},"term":{"type":"string"}},"type":"object"},"Vector":{"properties":{"createdTime":{"type":"string"},"currency":{"type":"string"},"data":{"items":{"type":"number"},"type":"array"},"dimension":{"type":"integer"},"displayName":{"type":"string"},"file":{"type":"string"},"index":{"type":"integer"},"name":{"type":"string"},"owner":{"type":"string"},"price":{"type":"number"},"provider":{"type":"string"},"score":{"type":"number"},"store":{"type":"string"},"text":{"type":"string"},"tokenCount":{"type":"integer"}},"type":"object"},"VectorScore":{"properties":{"score":{"type":"number"},"vector":{"type":"string"}},"type":"object"},"Video":{"properties":{"audioUrl":{"type":"string"},"class":{"type":"string"},"coverUrl":{"type":"string"},"createdTime":{"type":"string"},"dataUrl":{"type":"string"},"dataUrls":{"items":{"type":"string"},"type":"array"},"description":{"type":"string"},"displayName":{"type":"string"},"downloadUrl":{"type":"string"},"editMode":{"type":"string"},"excellentCount":{"type":"integer"},"grade":{"type":"string"},"grade2":{"type":"string"},"isPublic":{"type":"boolean"},"keywords":{"items":{"type":"string"},"type":"array"},"labelCount":{"type":"integer"},"labels":{"items":{"$ref":"#/components/schemas/Label"},"type":"array"},"lesson":{"type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"playAuth":{"type":"string"},"remarks":{"items":{"$ref":"#/components/schemas/Remark"},"type":"array"},"remarks2":{"items":{"$ref":"#/components/schemas/Remark"},"type":"array"},"reviewState":{"type":"string"},"school":{"type":"string"},"segmentCount":{"type":"integer"},"segments":{"items":{"$ref":"#/components/schemas/Label"},"type":"array"},"stage":{"type":"string"},"state":{"type":"string"},"subject":{"type":"string"},"tag":{"type":"string"},"tagOnPause":{"type":"boolean"},"task1":{"type":"string"},"task2":{"type":"string"},"task3":{"type":"string"},"template":{"type":"string"},"topic":{"type":"string"},"type":{"type":"string"},"unit":{"type":"string"},"videoId":{"type":"string"},"videoLength":{"type":"string"},"wordCountMap":{"additionalProperties":{"type":"integer"},"type":"object"}},"type":"object"},"Voucher":{"properties":{"description":{"type":"string"},"legs":{"items":{"$ref":"#/components/schemas/Leg"},"type":"array"},"postingAt":{"type":"string"},"sourceId":{"type":"string"},"sourceKind":{"type":"string"}},"type":"object"},"Workflow":{"properties":{"createdTime":{"type":"string"},"displayName":{"type":"string"},"message":{"type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"questionTemplate":{"type":"string"},"text":{"type":"string"},"text2":{"type":"string"}},"type":"object"},"account.apiKey":{"properties":{"budget":{"$ref":"#/components/schemas/account.keyBudget","description":"Budget is what the key may spend on models, in cents. Absent means no cap."},"created":{"description":"Created is when the key was minted (RFC 3339).","type":"string"},"creator":{"description":"Creator is the person the key speaks for, `\u003corg\u003e/\u003cuser\u003e`: who created it.","type":"string"},"expires":{"description":"Expires is when the key stops working (RFC 3339). Absent means never.","type":"string"},"id":{"description":"ID addresses this key in PATCH and DELETE /v1/account/keys/{id}.","type":"string"},"key":{"description":"Key is the full credential. A publishable key always carries it; a secret\nkey carries it once, in the answer to the POST that created it.","type":"string"},"limit":{"description":"Limit is what this key may reach, as `kind:name` entries — `model:zen5`,\n`project:acme`, `product:train` (read and write), `read:billing` (read only),\n`read:*` (a read-only key). Absent means the key reaches whatever its holder\ndoes.","items":{"type":"string"},"type":"array"},"name":{"description":"Name is the key's label, chosen by the person who made it.","type":"string"},"prefix":{"description":"Prefix is the head of the credential this key's holder presents — the sk- of\na secret key — enough to tell which string a row is, never enough to use.\nAbsent on a key minted before prefixes were recorded.","type":"string"},"rate":{"description":"Rate is how many requests a minute the key may make. Absent means no limit\nof its own.","format":"int64","type":"integer"},"revoked":{"type":"string"},"revoker":{"description":"Revoker is who revoked the key, `\u003corg\u003e/\u003cuser\u003e`, and Revoked when.","type":"string"},"spend":{"$ref":"#/components/schemas/account.keyBudget","description":"Spend is what the key has spent on models, in cents rounded up. Absent when\nit could not be read just now."},"status":{"description":"Status is active, expired, revoked, or disabled (switched off in IAM).","type":"string"},"type":{"description":"Type is the key class: secret (sk-) or publishable (pk-).","type":"string"},"used":{"description":"Used is when the key was last used (RFC 3339). Absent means never.","type":"string"}},"type":"object"},"account.apiKeyList":{"properties":{"keys":{"description":"Keys is every key the caller may see, newest first: their own, or every key\nof the org when the caller administers it. Revoked keys stay listed.","items":{"$ref":"#/components/schemas/account.apiKey"},"type":"array"}},"type":"object"},"account.appearance":{"properties":{"accent":{"description":"Accent is the one hue — a CSS colour token (a hex, or a bounded functional\ncolour like rgb()/oklch()). Anything else is dropped rather than stored.","type":"string"},"density":{"description":"Density is the spacing step: \"compact\", \"default\" or \"comfortable\".","type":"string"},"type":{"description":"Type is the text-size multiplier, clamped to the ramp window [0.85, 1.4].\nAbsent (0) leaves the published default.","format":"double","type":"number"}},"type":"object"},"account.csrfResp":{"properties":{"csrfToken":{"description":"Token is the value to send back in the X-CSRF-Token header. It is bound to the\ncaller's identity, so it authorizes changes as them and as nobody else.","type":"string"},"expiresIn":{"description":"ExpiresIn is the token's lifetime in seconds. Fetch a new one when it lapses;\na change with an expired token is refused.","format":"int64","type":"integer"}},"type":"object"},"account.embedStatusResp":{"properties":{"app":{"description":"App is the app this verdict is about.","type":"string"},"embedUrl":{"description":"EmbedURL is the in-app landing URL to frame. Empty when the caller is not\nentitled — a non-entitled caller never receives it.","type":"string"},"entitled":{"description":"Entitled is whether the caller's org may frame this brand-owned app.","type":"boolean"},"origin":{"description":"Origin is the app's origin on this deployment's own brand domain.","type":"string"},"phase":{"description":"Phase is the verdict in one word: not-entitled, not-provisioned or ready.","type":"string"},"reachable":{"description":"Reachable is whether the app answered the liveness probe.","type":"boolean"}},"type":"object"},"account.keyBudget":{"properties":{"month":{"description":"Month is per calendar month, UTC.","format":"int64","type":"integer"},"total":{"description":"Total is over the key's whole life.","format":"int64","type":"integer"}},"type":"object"},"account.keyEdit":{"properties":{"budget":{"$ref":"#/components/schemas/account.keyBudget","description":"Budget replaces the key's spend caps, in cents; a zero drops that cap."},"expires":{"description":"Expires replaces when the key stops working, RFC 3339. An empty string means\nnever.","type":"string"},"id":{"description":"ID is the key to edit, from the path.","type":"string"},"limit":{"description":"Limit replaces what the key may reach. An empty list makes it unrestricted.","items":{"type":"string"},"type":"array"},"name":{"description":"Name relabels the key.","type":"string"},"rate":{"description":"Rate replaces the key's requests a minute; zero drops the limit.","format":"int64","type":"integer"}},"type":"object"},"account.keyIn":{"properties":{"budget":{"$ref":"#/components/schemas/account.keyBudget","description":"Budget caps what the key may spend on models, in cents, per calendar month\nand in all; a request past either is refused 402. Omitted means no cap."},"expires":{"description":"Expires is when the key stops working, RFC 3339. Omitted means never.","type":"string"},"limit":{"description":"Limit narrows what the key may reach, as `kind:name` entries: `model:zen5`,\n`project:acme`, `product:commerce`, or `model:*` for a whole kind. It only\never NARROWS — a key never reaches further than the person who made it.\nOmitted makes an unrestricted key.\n\nExample: {\"name\": \"ci\", \"limit\": [\"model:zen5\", \"project:acme\"]}","items":{"type":"string"},"type":"array"},"name":{"description":"Name labels the key. Omitted names it \"key N\".","type":"string"},"rate":{"description":"Rate caps the key's requests a minute; past it a request is refused 429.\nOmitted means no limit of its own.","format":"int64","type":"integer"},"type":{"description":"Type is the key class: \"secret\" (sk-, session-equivalent, belongs on a\nserver) or \"publishable\" (pk-, org-identifying, safe in a browser bundle).\nOmitted means secret.","type":"string"}},"type":"object"},"account.onboardReq":{"properties":{"name":{"description":"Name is the organization's display name. Ignored when personal is true, which\nderives the name from the caller's own username instead.","type":"string"},"personal":{"description":"Personal marks the organization as the caller's own space: the name is\nderived from their username and the slug auto-suffixes to stay unique.","type":"boolean"}},"type":"object"},"account.onboardResp":{"properties":{"accessKey":{"description":"AccessKey is the publishable half of the organization's default API key,\nheld by its creator. Absent when the key could not be minted; the creator\nthen mints one from the keys page.","type":"string"},"accessSecret":{"description":"AccessSecret is that credential's confidential half, returned ONCE — on the\nresponse that mints it and never again. IAM keeps only its argon2id digest\nand blanks the plaintext, so this is the single moment it exists in a form\nits owner can read.","type":"string"},"displayName":{"description":"DisplayName is the organization's human name.","type":"string"},"org":{"description":"Org is the created organization's slug, which is what X-Org-Id carries.","type":"string"}},"type":"object"},"ad.AdCampaign":{"properties":{"account":{"description":"Account is the provider ad-account the campaign runs under, in Meta's\nact_\u003cid\u003e form. Empty until the org supplies one or a launch resolves it.","type":"string"},"budget":{"description":"Budget is the campaign's authorized spend in MINOR units (cents). Negative\nclamps to 0. It is the org's stored plan: a Meta launch creates the campaign\nobject only, and the delivering budget lives on the ad set.","format":"int64","type":"integer"},"createdAt":{"description":"CreatedAt is when the campaign was first stored, in unix seconds. It never\nchanges, including across a full-replace update.","format":"int64","type":"integer"},"externalId":{"description":"ExternalID is the ad network's own campaign id, written by a successful\nlaunch and by nothing else — an update never touches it. Empty means this\ncampaign has never reached its network.","type":"string"},"id":{"description":"ID is the campaign's server-minted handle, \"camp_\" + 32 hex. A create body\ncannot choose it, and it is the id every other route addresses.","type":"string"},"name":{"description":"Name is the campaign's display label, and the name Meta creates the campaign\nobject under at launch. Required; trimmed and bounded to 1024 bytes.","type":"string"},"objective":{"description":"Objective is the campaign goal spelled as the provider names it\n(\"conversions\", \"OUTCOME_TRAFFIC\"), passed through to the network verbatim at\nlaunch — Meta defaults an empty one to OUTCOME_TRAFFIC. Free text, bounded to\n1024 bytes; no vocabulary is enforced here.","type":"string"},"platform":{"description":"Platform is the ad network: meta, google, tiktok or x, and nothing else — a\nwrite naming another is 400. Empty stores as meta. Only meta executes today;\nlaunching any of the other three is 501.","type":"string"},"spend":{"description":"Spend is spend-to-date in MINOR units (cents), as last written through create\nor update. Negative clamps to 0. It is NOT read back from the network — that\nis a separate insights call — so 0 means nothing was recorded here, not that\nnothing was spent.","format":"int64","type":"integer"},"status":{"description":"Status is the lifecycle: draft, active, paused or completed, and nothing else\n— a write naming another is 400. Empty stores as draft; a successful launch\nsets active. It records what this deployment did, not what the ad network\ncurrently reports.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the row was last written, in unix seconds — set by create,\nupdate and launch. Listings are ordered by it, newest first.","format":"int64","type":"integer"}},"type":"object"},"ad.adSummary":{"properties":{"active":{"description":"Active is how many of those campaigns are in the active state.","format":"int64","type":"integer"},"budget":{"description":"Budget is the summed budget of every campaign in the org, in cents.","format":"int64","type":"integer"},"campaigns":{"description":"Campaigns is how many campaigns the org has, in every state.","format":"int64","type":"integer"},"spend":{"description":"Spend is the summed spend of every campaign in the org, in cents.","format":"int64","type":"integer"}},"type":"object"},"ad.campaignInput":{"properties":{"account":{"description":"Account is the provider ad-account this campaign runs on (Meta act_\u003cid\u003e). Optional.","type":"string"},"budget":{"description":"Budget is the campaign budget in MINOR units (cents). Negative values clamp to 0.","format":"int64","type":"integer"},"name":{"description":"Name is the campaign's display label. Required; trimmed and bounded to 1024 bytes.","type":"string"},"objective":{"description":"Objective is the campaign goal as the provider names it. Optional, bounded to 1024 bytes.","type":"string"},"platform":{"description":"Platform is the ad network: meta, google, tiktok or x. Empty defaults to meta.","type":"string"},"spend":{"description":"Spend is the amount spent so far in MINOR units (cents). Negative values clamp to 0.","format":"int64","type":"integer"},"status":{"description":"Status is the lifecycle state: draft, active, paused or completed. Empty defaults to draft.","type":"string"}},"type":"object"},"ad.campaignList":{"properties":{"data":{"description":"Data is the matching campaigns, newest-updated first.","items":{"$ref":"#/components/schemas/ad.AdCampaign"},"type":"array"}},"type":"object"},"ad.updateCampaignIn":{"properties":{"account":{"description":"Account is the provider ad-account this campaign runs on (Meta act_\u003cid\u003e). Optional.","type":"string"},"budget":{"description":"Budget is the campaign budget in MINOR units (cents). Negative values clamp to 0.","format":"int64","type":"integer"},"name":{"description":"Name is the campaign's display label. Required; trimmed and bounded to 1024 bytes.","type":"string"},"objective":{"description":"Objective is the campaign goal as the provider names it. Optional, bounded to 1024 bytes.","type":"string"},"platform":{"description":"Platform is the ad network: meta, google, tiktok or x. Empty defaults to meta.","type":"string"},"spend":{"description":"Spend is the amount spent so far in MINOR units (cents). Negative values clamp to 0.","format":"int64","type":"integer"},"status":{"description":"Status is the lifecycle state: draft, active, paused or completed. Empty defaults to draft.","type":"string"}},"type":"object"},"affiliate.affiliateBoard":{"properties":{"leaders":{"description":"Leaders are the top opt-in affiliates, by handle and aggregate figures only.","items":{"$ref":"#/components/schemas/affiliate.leaderboardRow"},"type":"array"},"total":{"description":"Total is the approved population where it is known; omitted where the top\npage truncated and the caller has no rank to derive it from.","format":"int64","type":"integer"},"you":{"$ref":"#/components/schemas/affiliate.leaderboardRow","description":"You is the caller's own row with its exact global rank; only an approved\naffiliate has one."}},"type":"object"},"affiliate.affiliateEarnings":{"properties":{"accruedCents":{"description":"AccruedCents is lifetime commission accrued, in cents.","format":"int64","type":"integer"},"byPeriod":{"description":"ByPeriod is the per-period ledger: the margin earned against and the\ncommission taken from it.","items":{"$ref":"#/components/schemas/affiliate.periodEarningView"},"type":"array"},"byReferredOrg":{"description":"ByReferredOrg is each referral's aggregate contribution — the affiliate's\nOWN share, never the referred org's spend.","items":{"$ref":"#/components/schemas/affiliate.orgEarningView"},"type":"array"},"isAffiliate":{"description":"IsAffiliate says whether the caller org has an affiliate record. On false it\nis the ONLY field present — there is no ledger to report, and the zeros you\nmight expect are absent rather than reported as earnings of nothing.","type":"boolean"},"marginBps":{"description":"MarginBps is the platform gross-margin fraction commission is a rate OF.","format":"int64","type":"integer"},"paidCents":{"description":"PaidCents is lifetime commission already paid out, in cents.","format":"int64","type":"integer"},"pendingCents":{"description":"PendingCents is accrued minus paid — what the platform still owes.","format":"int64","type":"integer"}},"type":"object"},"affiliate.affiliateLinks":{"properties":{"isAffiliate":{"description":"IsAffiliate says whether the caller org has an affiliate record. On false only\nmaxLinks comes back — there are no links, and there is no link to mint until\nthe org applies and is approved.","type":"boolean"},"links":{"description":"Links is the caller's share links, each with its URL and funnel.","items":{"$ref":"#/components/schemas/affiliate.codeView"},"type":"array"},"maxLinks":{"description":"MaxLinks is how many share links one affiliate may hold.","format":"int64","type":"integer"},"status":{"description":"Status is the caller's affiliate status: \"applied\", \"approved\" or\n\"suspended\"; absent for a non-affiliate. Minting a link requires \"approved\",\nbecause a link that cannot accrue quietly loses the referral.","type":"string"}},"type":"object"},"affiliate.affiliateSelf":{"properties":{"accruedCents":{"description":"AccruedCents is lifetime commission accrued, in cents. It only grows — a\npayout is recorded against paidCents and never reduces this.","format":"int64","type":"integer"},"code":{"description":"Code is the minted referral code, the slug the ?aff link carries. Absent until\nstaff approve; codes live in ONE global namespace across all affiliates.","type":"string"},"defaultRateBps":{"description":"DefaultRateBps is the direct rate a new affiliate starts at, in basis points\nof margin (2000 = 20%). Answered ONLY to a caller that has not applied, as the\nquote beside `schedule`.","format":"int64","type":"integer"},"downlineTotal":{"description":"DownlineTotal counts every org in the caller's downline across the levels.","format":"int64","type":"integer"},"handle":{"description":"Handle is the opt-in public leaderboard name. Empty means opted out: the\ncaller keeps its rank and still sees its own row, it is just not listed.","type":"string"},"id":{"description":"ID is the affiliate's server-minted handle, \"aff_\"-prefixed. Absent until the\norg applies.","type":"string"},"isAffiliate":{"description":"IsAffiliate says whether the caller org has an affiliate record. On false the\nanswer carries the rate SCHEDULE and the default rate instead of a downline,\nso the console can show what the caller would earn.","type":"boolean"},"levels":{"description":"Levels is the caller's downline per upline level, with the rate paid there.","items":{"$ref":"#/components/schemas/affiliate.levelView"},"type":"array"},"link":{"description":"Link is the shareable ?aff URL built from the code. Empty until a code is\nminted, since there is nothing to share before approval.","type":"string"},"marginBps":{"description":"MarginBps is the platform gross-margin fraction, in basis points, that every\nrate here is a rate OF. Read live per request, so it is the value in force\nnow, not the one that applied to commission already accrued.","format":"int64","type":"integer"},"paidCents":{"description":"PaidCents is lifetime commission already paid out, in cents — credits grants\nand record-only cash disbursements alike.","format":"int64","type":"integer"},"payouts":{"description":"Payouts is the payout history, newest first, bounded to the last 100 rows.","items":{"$ref":"#/components/schemas/affiliate.remittance"},"type":"array"},"pendingCents":{"description":"PendingCents is accrued minus paid, in cents — what the platform still owes\nand the ceiling on the next payout. Never negative.","format":"int64","type":"integer"},"rateBps":{"description":"RateBps is the caller's OWN direct (level 1) commission rate, in basis points\nof margin. Levels 2 and 3 are platform-wide and appear in `levels`.","format":"int64","type":"integer"},"schedule":{"description":"Schedule is the rate schedule quoted to a caller that has not applied.","items":{"$ref":"#/components/schemas/affiliate.levelView"},"type":"array"},"status":{"description":"Status is \"applied\", \"approved\" or \"suspended\"; absent for a caller that never\napplied. Only \"approved\" mints links and accrues.","type":"string"}},"type":"object"},"affiliate.affiliateStanding":{"properties":{"accruedCents":{"description":"AccruedCents is lifetime commission accrued, in cents.","format":"int64","type":"integer"},"code":{"description":"Code is the minted referral code; empty until staff approve.","type":"string"},"defaultRateBps":{"description":"DefaultRateBps is the direct rate a new affiliate would get, answered only\nto a caller that has not applied.","format":"int64","type":"integer"},"handle":{"description":"Handle is the opt-in public leaderboard name; empty means opted out.","type":"string"},"id":{"description":"ID is the affiliate's server-minted handle, \"aff_\"-prefixed — what staff\napprove, suspend, re-rate and pay against. Absent until the org applies.","type":"string"},"isAffiliate":{"description":"IsAffiliate says whether the caller org has an affiliate record at all. It is\nthe ONE field an org that never applied gets besides defaultRateBps: on false,\nread nothing else here — every other field is absent, not zero.","type":"boolean"},"link":{"description":"Link is the shareable ?aff URL; empty until a code is minted.","type":"string"},"marginBps":{"description":"MarginBps is the platform gross-margin fraction commission is a rate OF.","format":"int64","type":"integer"},"paidCents":{"description":"PaidCents is lifetime commission already paid out, in cents.","format":"int64","type":"integer"},"payouts":{"description":"Payouts is the payout history, newest rows bounded.","items":{"$ref":"#/components/schemas/affiliate.remittance"},"type":"array"},"pendingCents":{"description":"PendingCents is accrued minus paid — what the platform still owes.","format":"int64","type":"integer"},"rateBps":{"description":"RateBps is the affiliate's own direct commission rate, in basis points.","format":"int64","type":"integer"},"referredCount":{"description":"ReferredCount is how many orgs this affiliate has referred.","format":"int64","type":"integer"},"requestedCode":{"description":"RequestedCode is the vanity code asked for at apply time — a request, not an\nallocation. Approval mints `code`, which may be a different slug if this one\nwas already taken.","type":"string"},"status":{"description":"Status is \"applied\", \"approved\" or \"suspended\". Only an approved affiliate has\na code that resolves for attribution and accrues commission; suspended keeps\nwhat it already earned but stops earning more.","type":"string"}},"type":"object"},"affiliate.application":{"properties":{"code":{"description":"Code is the minted referral code. Empty on a first apply — applying does not\nmint a code, approval does; a re-apply echoes whatever the row already holds.","type":"string"},"created":{"description":"Created says whether THIS call made the row. false means the org had already\napplied and nothing changed — no second row, no reset of an existing approval.\nThe HTTP status states the same fact: 201 when true, 200 when false.","type":"boolean"},"id":{"description":"ID is the affiliate's server-minted handle, \"aff_\"-prefixed — the id staff\napprove, suspend, re-rate and pay against.","type":"string"},"rateBps":{"description":"RateBps is the direct (level 1) commission rate the row carries, in basis\npoints OF Hanzo's margin (2000 = 20% of margin, never of the customer's bill).","format":"int64","type":"integer"},"requestedCode":{"description":"RequestedCode echoes the vanity code asked for, normalized to lower case. It\nis a request only: approval mints a different slug if this one is taken.","type":"string"},"status":{"description":"Status is \"applied\" for a row this call created. A re-apply echoes the\nexisting row's status, which may already be \"approved\" or \"suspended\".","type":"string"}},"type":"object"},"affiliate.applyRequest":{"properties":{"requestedCode":{"description":"RequestedCode is the vanity code the applicant asks for; approval may mint\na different one if it is taken. Body-only: the URL cannot supply it.","type":"string"}},"type":"object"},"affiliate.attributeRequest":{"properties":{"code":{"description":"Code is the affiliate code the referred org arrived with. Body-only: the\nURL cannot supply it.","type":"string"}},"type":"object"},"affiliate.attribution":{"properties":{"code":{"description":"Code is the affiliate code the edge was recorded under, normalized to lower\ncase. On a re-post it is the code of the STANDING edge, which may differ from\nthe one just sent — first touch wins.","type":"string"},"created":{"description":"Created says whether THIS call made the edge. false means the caller org was\nalready attributed and nothing moved. The HTTP status says the same: 201 when\ntrue, 200 when false.","type":"boolean"},"createdAt":{"description":"CreatedAt is when the edge was FIRST recorded, Unix seconds UTC. On a re-post\nit is the original time, not now.","format":"int64","type":"integer"},"id":{"description":"ID is the attribution edge's server-minted handle, \"afr_\"-prefixed.","type":"string"}},"type":"object"},"affiliate.clickCount":{"properties":{"counted":{"description":"Counted says the in-memory buffer took the ping. It does NOT say the code\nexists — this is deliberately not a code-existence oracle, and an unknown code\nsimply no-ops at flush time. false means the buffer was full and the ping was\ndropped, which is harmless: clicks are vanity and move no money.","type":"boolean"}},"type":"object"},"affiliate.clickRequest":{"properties":{"code":{"description":"Code is the share-link code that was clicked. Body-only: the URL cannot\nsupply it.","type":"string"}},"type":"object"},"affiliate.codeView":{"properties":{"clicks":{"description":"Clicks is how many pings this code has taken. The one STORED counter here and\npure vanity: no accrual or payout reads it, pings are coalesced in memory and\nflushed in batches, and a dropped tally is accepted rather than contending\nwith the money write path. Do not reconcile it against anything.","format":"int64","type":"integer"},"code":{"description":"Code is the link's slug — 3–32 chars of a–z, 0–9 and hyphen — unique across\nthe WHOLE directory, so any affiliate's code resolves an attribution.","type":"string"},"conversions":{"description":"Conversions is how many of those signups have actually produced positive\ncommission for the caller. Also derived, from the accrual rows, so it is\n≤ signups and lags a referral until the first sweep after it spends.","format":"int64","type":"integer"},"createdAt":{"description":"CreatedAt is when the link was minted, Unix seconds UTC.","format":"int64","type":"integer"},"label":{"description":"Label is the caller's own note for the link (\"twitter\", \"newsletter\").\nCosmetic: trimmed, stripped of control characters, capped at 48 bytes, and\nnever part of the code. \"primary\" on the link mirrored at approval.","type":"string"},"signups":{"description":"Signups is how many orgs were attributed with this code — DERIVED by counting\nattribution edges, never stored, so it cannot drift from the ledger.","format":"int64","type":"integer"},"url":{"description":"URL is the full shareable link, the brand host plus ?aff=\u003ccode\u003e. The host is\nthe deployment's own brand, so a Lux or Zoo install never mints a hanzo.ai\nlink.","type":"string"}},"type":"object"},"affiliate.createLinkRequest":{"properties":{"code":{"description":"Code is an optional vanity code; it must be free across the whole\ndirectory, and omitting it mints a random one. Body-only.","type":"string"},"label":{"description":"Label is cosmetic — trimmed, stripped of control characters, capped — and\nnever part of a code. Body-only: the URL cannot supply it.","type":"string"}},"type":"object"},"affiliate.handleRequest":{"properties":{"handle":{"description":"Handle is the public leaderboard display name; empty opts out. Body-only:\nthe URL cannot supply it.","type":"string"}},"type":"object"},"affiliate.handleSet":{"properties":{"handle":{"description":"Handle is the display name as STORED, echoed back after trimming. Empty means\nthe caller opted out: it keeps its rank and still sees its own row, it is just\nno longer listed to anyone else.","type":"string"}},"type":"object"},"affiliate.leaderboardRow":{"properties":{"accruedCents":{"description":"AccruedCents is that affiliate's lifetime commission accrued, in cents, and\nwhat the board is ordered by. An aggregate: no per-customer figure is exposed.","format":"int64","type":"integer"},"handle":{"description":"Handle is the affiliate's self-chosen display name — the only identity the\nboard ever carries. The org behind it is never disclosed.","type":"string"},"isYou":{"description":"IsYou marks the caller's own row, so a client can highlight it without\nmatching on a handle. Absent on every other row.","type":"boolean"},"rank":{"description":"Rank is the position in the GLOBAL approved set ordered by lifetime accrued\ncommission, 1-based. Affiliates that set no handle still occupy their rank and\nare simply not listed, so the visible ranks have gaps and the board is not a\ncomplete roster. On the caller's own row the rank is computed over the whole\nset, so it is exact well outside the top page.","format":"int64","type":"integer"},"referredCount":{"description":"ReferredCount is how many orgs that affiliate directly referred — a count\nonly, never which orgs.","format":"int64","type":"integer"}},"type":"object"},"affiliate.levelView":{"properties":{"downlineCount":{"description":"DownlineCount is how many orgs sit exactly this many hops below the caller. It\nis 0 in the schedule quoted to a caller that has not applied, which has no\ndownline to count.","format":"int64","type":"integer"},"level":{"description":"Level is the upline distance from the org whose spend is being shared: 1 is\nthe direct referrer, 2 and 3 the referrers above it. Nothing accrues past 3.","format":"int64","type":"integer"},"rateBps":{"description":"RateBps is the commission paid at this level, in basis points OF Hanzo's\nmargin (2000 = 20% of margin, never of the customer's bill). Level 1 is the\naffiliate's own negotiated rate; 2 and 3 are platform switches read live, so\nthis is the schedule actually in force, not one compiled in.","format":"int64","type":"integer"}},"type":"object"},"affiliate.linkMint":{"properties":{"link":{"$ref":"#/components/schemas/affiliate.codeView","description":"Link is the link just minted, with its full shareable URL. Its funnel counters\nall start at zero — nothing has clicked or signed up through it yet."}},"type":"object"},"affiliate.orgEarningView":{"properties":{"commissionCents":{"description":"CommissionCents is what the caller earned from that org across ALL periods, in\ncents. Deliberately the caller's own share and nothing else: that org's spend\nand the margin on it are not restated here.","format":"int64","type":"integer"},"referredOrg":{"description":"ReferredOrg is the org slug this contribution came from — one the caller\nreferred, directly or up to three levels down.","type":"string"}},"type":"object"},"affiliate.periodEarningView":{"properties":{"commissionCents":{"description":"CommissionCents is what the caller earned that period, in cents: the sum over\neach referred org and upline level of margin × that level's rate. Always ≤\nmarginCents, by construction.","format":"int64","type":"integer"},"marginCents":{"description":"MarginCents is the margin Hanzo earned in that period on the spend of every\norg the caller referred, in cents — the base commission is a rate OF. It is\nthe aggregate base, never any one customer's bill.","format":"int64","type":"integer"},"period":{"description":"Period is the accrual bucket: the UTC year-month, \"YYYY-MM\". Commission is\nlatched at most once per referred org per period, so one row is one month.","type":"string"}},"type":"object"},"affiliate.remittance":{"properties":{"amountCents":{"description":"AmountCents is the amount disbursed, in cents. It was reserved against pending\ncommission atomically when recorded, so it never exceeds what was owed.","format":"int64","type":"integer"},"createdAt":{"description":"CreatedAt is when the payout was recorded, Unix seconds UTC — when the balance\nmoved, not necessarily when the cash landed.","format":"int64","type":"integer"},"id":{"description":"ID is the payout row's server-minted handle, \"apo_\"-prefixed.","type":"string"},"method":{"description":"Method is how it was settled. \"credits\" issued a commerce grant into the\naffiliate org's own wallet; any other value (wire, paypal, check, …) is a\nRECORD of cash a human moved out of band.","type":"string"},"reference":{"description":"Reference is the operator's settlement note — a bank id, a ledger ref. Free\ntext, absent when none was given.","type":"string"},"txn":{"description":"Txn is the commerce ledger transaction id, set ONLY where a \"credits\" payout\nactually issued the grant. Absent for cash methods, which write no ledger row.","type":"string"}},"type":"object"},"agent.Artifact":{"properties":{"kind":{"description":"Kind is file, patch, preview, pull or deploy. A file or a patch is stored,\nand its bytes are read at GET /v1/agent/coding/{session}/artifacts/{name}.","type":"string"},"name":{"description":"Name is the artifact's handle: a changed file's path in the workspace, or\n`changes.patch` for the whole change; for a link, its kind and what it names.","type":"string"},"port":{"description":"Port is a preview's port in the run's sandbox, which\nPOST /v1/sandbox/{id}/preview opens while the sandbox is kept.","format":"int64","type":"integer"},"sandbox":{"description":"Sandbox is the sandbox a preview is served from.","type":"string"},"sha256":{"description":"SHA256 is a stored artifact's digest, hex.","type":"string"},"size":{"description":"Size is a stored artifact's length in bytes.","format":"int64","type":"integer"},"url":{"description":"URL is where a link points: a preview's host, a pull request, a deployment.","type":"string"}},"type":"object"},"agent.CodingAck":{"properties":{"ok":{"description":"OK means the operation was accepted; it does not imply that an associated coding run has finished.","type":"boolean"}},"type":"object"},"agent.CodingArtifacts":{"properties":{"artifacts":{"description":"Artifacts are the run's artifacts, stored files first. Never null.","items":{"$ref":"#/components/schemas/agent.Artifact"},"type":"array"},"saved":{"description":"Saved is when the artifacts were saved, RFC 3339 in UTC; empty while the run\nhas saved none.","type":"string"},"session":{"description":"Session is the run's handle.","type":"string"}},"type":"object"},"agent.CodingBlob":{"properties":{"binary":{"description":"Binary marks content that is not text; it comes back base64.","type":"boolean"},"content":{"description":"Content is the file's bytes, empty when Truncated.","type":"string"},"encoding":{"description":"Encoding is how Content is carried: \"utf8\" verbatim, or \"base64\".","type":"string"},"path":{"description":"Path is the file's repo-relative path.","type":"string"},"size":{"description":"Size is the file's byte length in the repository, whatever was returned below.","format":"int64","type":"integer"},"truncated":{"description":"Truncated marks a file past the 1 MiB view cap. No content is sent.","type":"boolean"}},"type":"object"},"agent.CodingChanges":{"properties":{"base":{"description":"Base is the branch the run started from: the one it was given, or the\nrepository's default.","type":"string"},"commits":{"description":"Commits are the commits on head that base does not have, newest first.","items":{"$ref":"#/components/schemas/agent.CodingCommit"},"type":"array"},"files":{"description":"Files is the net change head makes against its merge base with base, one\nentry per file.","items":{"$ref":"#/components/schemas/agent.CodingFile"},"type":"array"},"head":{"description":"Head is the run's own branch. Empty for a plan or a setup, which write none.","type":"string"},"moreCommits":{"description":"MoreCommits says the branch carries more commits than the newest 250 that\nCommits lists.","type":"boolean"},"moreFiles":{"description":"MoreFiles says the change is larger than one read answers — past 8 MiB of\ndiff or 3000 files — so Files lists the files before that, and the last of\nthem is marked truncated with the counts of the part read.","type":"boolean"},"pull":{"$ref":"#/components/schemas/agent.CodingPull","description":"Pull is the run's pull request on the forge, or null while it has none —\nand for a run proposed somewhere else, a repository the forge only mirrors\nfrom GitHub."},"repo":{"description":"Repo is the run's repository on the forge, owner/name.","type":"string"}},"type":"object"},"agent.CodingCommit":{"properties":{"author":{"description":"Author is the commit author's name as git recorded it; a run's own commits\nare authored by its harness.","type":"string"},"date":{"description":"Date is the author date, RFC 3339 in UTC.","type":"string"},"message":{"description":"Message is the commit's subject — its first line only.","type":"string"},"sha":{"description":"SHA is the full commit hash.","type":"string"}},"type":"object"},"agent.CodingEntry":{"properties":{"name":{"description":"Name is the entry's own name, no directory part.","type":"string"},"path":{"description":"Path is the entry's full repo-relative path.","type":"string"},"size":{"description":"Size is a file's byte length; 0 for a directory.","format":"int64","type":"integer"},"type":{"description":"Type is \"tree\" for a directory and \"blob\" for anything else a reader opens.","type":"string"}},"type":"object"},"agent.CodingFile":{"properties":{"additions":{"description":"Additions counts the lines the change adds, over the whole file whether or\nnot all of its patch is carried.","format":"int64","type":"integer"},"deletions":{"description":"Deletions counts the lines the change removes, the same way.","format":"int64","type":"integer"},"from":{"description":"From is where a renamed file was. Omitted for every other status.","type":"string"},"patch":{"description":"Patch is the file's unified-diff hunks, from its first \"@@\". Empty for a\nbinary file and for a rename that moved no line.","type":"string"},"path":{"description":"Path is where the file is on the branch — for a deleted file, where it was.","type":"string"},"status":{"description":"Status is added, modified, deleted or renamed.","type":"string"},"truncated":{"description":"Truncated marks a patch cut short: at 64 KiB for one file, or past 1 MiB of\npatch across the change, when later files carry none. The counts are whole.","type":"boolean"}},"type":"object"},"agent.CodingMerged":{"properties":{"base":{"description":"Base is the branch it was merged into.","type":"string"},"number":{"description":"Number is the pull request's number in its repository.","format":"int64","type":"integer"},"state":{"description":"State is merged.","type":"string"},"url":{"description":"URL is where it is read.","type":"string"}},"type":"object"},"agent.CodingPull":{"properties":{"mergeable":{"description":"Mergeable is the forge's verdict that the base takes the branch without\nconflict.","type":"boolean"},"moreReviews":{"description":"MoreReviews says it has more reviews than the first 50 that Reviews lists.","type":"boolean"},"number":{"description":"Number is the pull request's number in its repository.","format":"int64","type":"integer"},"reviews":{"description":"Reviews are its reviews, oldest first: the first 50.","items":{"$ref":"#/components/schemas/agent.CodingReview"},"type":"array"},"state":{"description":"State is open, closed or merged.","type":"string"},"title":{"description":"Title is its title.","type":"string"},"url":{"description":"URL is where a person reads and merges it.","type":"string"}},"type":"object"},"agent.CodingReview":{"properties":{"at":{"description":"At is when it was submitted, RFC 3339 in UTC; empty for one that has not\nbeen.","type":"string"},"author":{"description":"Author is the reviewer's forge login.","type":"string"},"body":{"description":"Body is what the reviewer wrote; empty for a bare verdict. At most 16 KiB\nof it, and 256 KiB across the reviews listed.","type":"string"},"state":{"description":"State is the verdict: approved, request_changes, comment, pending or\nrequest_review.","type":"string"},"truncated":{"description":"Truncated marks a Body cut at either bound — or left empty past the second,\nwhere the review keeps its author, verdict and time.","type":"boolean"}},"type":"object"},"agent.CodingStartIn":{"properties":{"after":{"description":"After names a previous run's session, and starts this one from where that\none stopped instead of from the repository's default. It is how a follow-up\ninstruction — \"now add tests for it\" — builds on work already done rather\nthan beginning again on a fresh clone: the follow-up resumes the earlier\nrun's sandbox and works in its tree, files, installs and all, while that\nsandbox is kept; one reaped by then is cloned again from the earlier branch.\n\nIt sets the base and nothing else, so this run still writes its OWN branch.\nOne run, one branch: a run that wrote back onto an earlier run's branch\nwould break the rule the forge's ref policy is built on, and would leave\ntwo turns of work with one name to review.\n\nA caller who already knows the branch may pass Base directly; this exists\nbecause the branch is derived from a session id and nobody should have to\nknow how. Base wins if both are given.","type":"string"},"agentRef":{"description":"AgentRef names a configured agent to run as, which is how an org pins a\nharness, a model and a prompt to a name. Empty runs the default agent.","type":"string"},"base":{"description":"Base is the branch to start from. Empty takes the repository's default. The\nrun never writes here — it writes the agent branch it answers with.","type":"string"},"desktop":{"description":"Desktop asks for a run with a SCREEN — an image carrying an X server — for a\ntask that has to drive a browser or another windowed program. False, the\ndefault, is a headless checkout, which is what writing code needs.","type":"boolean"},"effort":{"description":"Effort is how hard that model reasons: low, medium or high. Empty takes the\nmodel's own default. Taken by the dev and codex harnesses, like Model.","type":"string"},"issue":{"description":"Issue is the number of the issue on Repo this run resolves. Its pull\nrequest says `Closes #\u003cn\u003e`, so merging the work closes the issue. Zero is a\nrun no issue asked for.","format":"int64","type":"integer"},"mode":{"description":"Mode is what the run may do to the repository: `build` edits, commits and\npushes its branch; `plan` reads the repository and answers with a plan,\nwriting nothing — its sandbox is handed a credential that can only read and\nno push step runs, and the plan arrives as the run's final status. `setup`\nis a plan put to one question: its agent explores the checkout, installs and\nchecks what it finds, and ends with the codebase's environment, which is kept\nas the proposal at /v1/environment/{repo} until someone saves it. Empty is\n`build`. A plan or a setup runs in our sandbox only: a claimed machine clones\nand pushes with its own credential, so one routed to a machine is refused.","type":"string"},"model":{"description":"Model is the model the run's agent thinks with, by the id GET /v1/models\nlists. Empty takes the platform's coding model. The dev and codex harnesses\ntake it; the others do not think with a model we name, so naming one for\nthem is refused.","type":"string"},"project":{"description":"Project scopes the run to one board's work when the org keeps more than one.\nEmpty is the org's default.","type":"string"},"prompt":{"description":"Prompt is the task, in the words you would use with a colleague who has the\ncheckout open. It is the whole instruction: there is no second field for\ncontext, and a prompt that names files and the outcome it wants gets a run\nthat does not have to guess either.","type":"string"},"reply":{"$ref":"#/components/schemas/agent.Reply","description":"Reply is WHERE THE RUN NARRATES ITSELF, when the surface that started it has\nsomewhere for it to talk. Empty means nobody is listening and the run simply\ndoes not narrate — which is the app surface's case, because /v1/agent/coding\nhands back a session id and the session stream is a better progress feed than\nany message could be.\n\nIT IS NOT A FIELD A MODEL FILLS IN. A run asked for in a conversation is\ndispatched with the address that conversation is happening at, written over\nwhatever arrived here (apps/agents/replyto.go). A model naming a channel is\na model naming a room it was not spoken to in, so the value it chose is\ndiscarded rather than argued with — which is the same rule that left the org\nand the subject off this type entirely."},"repo":{"description":"Repo is what to work on: a repository's name, `owner/name` in the caller's\nown org, or the site a repository serves (`hanzo.ai`), as the person said\nit. The engine resolves it against the org's own repositories — a name that\nmatches none is refused with the nearest ones — and finds the clone URL and\nthe push credential from the org itself, so this says WHICH repository and\nnever how to reach it.\n\nA repository on GitHub is named by GitHub's address, `github.com/owner/name`\n— or `owner/name` when the owner is not the org's own — and runs there\ndirectly: it is admitted when the caller's own connected GitHub may push to\nit, or when the caller administers the org and the org's installation holds\nit, and refused otherwise.\n\nA repository the caller can read and not push to — a public repository, or\none their GitHub reads — is cloned read-only: the run works, commits in its\nworkspace, and pushes nothing; its change is kept as the run's artifacts.\n\nEmpty runs in an empty workspace: a fresh git repository in the sandbox,\nwith nothing cloned and nothing pushed.","type":"string"},"targetId":{"description":"TargetID routes the run to a registered machine the org has claimed instead\nof to a sandbox in our cluster. Empty runs it here, which is the usual case.","type":"string"},"task":{"description":"Task is Prompt under the name a caller asking for work tends to reach for.\nThe two are one field: Prompt wins when both are given.","type":"string"},"timeoutSeconds":{"description":"TimeoutSeconds bounds the whole run. Unset takes the default budget; a run\nthat hits the bound is stopped and reports what it had done by then.","format":"int64","type":"integer"},"tool":{"description":"Tool is which harness runs the prompt — dev | claude | codex | python |\nnode — and Desktop is whether the run needs a screen. Both are empty by\ndefault, which is `dev` with no screen, and that default is what every\ncaller gets until it says otherwise.\n\nThey are two fields because they are two questions. The harness decides\nwhat argv starts; the screen decides which image carries an X server. A\ncaller may want claude WITH a browser it can see, and a single enum would\nhave made that combination unsayable.","type":"string"}},"type":"object"},"agent.CodingStarted":{"properties":{"branch":{"description":"Branch is the ref the run will push its work to, and the ONLY ref it is\npermitted to write. It exists before the work does, so it is safe to tell\nsomebody where to look while the run is still going.","type":"string"},"repo":{"description":"Repo is the repository the run was admitted against, echoed back as the\nengine resolved it.","type":"string"},"routed":{"description":"Routed says the run went to one of the org's own registered machines rather\nthan to a sandbox in our cluster. False is the ordinary case.","type":"boolean"},"sessionId":{"description":"SessionID is the run's handle: its durable record, and the root its live\nprogress streams under at /v1/agent/sessions/stream?root=\u003csessionId\u003e. Every\nlater question about this run is asked with it.","type":"string"},"targetId":{"description":"TargetID names that machine when Routed is true, and is empty otherwise.","type":"string"}},"type":"object"},"agent.CodingTree":{"properties":{"entries":{"description":"Entries are the directory's immediate children, directories first.","items":{"$ref":"#/components/schemas/agent.CodingEntry"},"type":"array"},"ref":{"description":"Ref is the branch this was read at: the run's own once the forge holds it,\nits base until then.","type":"string"}},"type":"object"},"agent.GPU":{"properties":{"memory":{"description":"VRAM bytes, 0 = unknown","format":"int64","type":"integer"},"model":{"description":"\"GB10\", \"8060S\", \"RTX 4090\"","type":"string"},"vendor":{"description":"nvidia | amd | apple | intel | ...","type":"string"}},"type":"object"},"agent.McpTools":{"properties":{"isEnabled":{"type":"boolean"},"serverName":{"type":"string"},"tools":{"type":"string"}},"type":"object"},"agent.Metrics":{"properties":{"at":{"description":"unix seconds, server-stamped","format":"int64","type":"integer"},"cpuTemp":{"description":"CPUTemp is the CPU package temperature in °C.","format":"double","type":"number"},"cpuUtil":{"description":"CPUUtil is the busy fraction of all cores over the sample window, 0..1.","format":"double","type":"number"},"decode":{"description":"Decode is generation throughput over the sample window, in tokens per second.","format":"double","type":"number"},"diskRead":{"description":"DiskRead is the block-device read rate in bytes per second.","format":"double","type":"number"},"diskTotal":{"description":"DiskTotal is the size of those filesystems, in bytes.","format":"int64","type":"integer"},"diskUsed":{"description":"DiskUsed is the space used across local block filesystems, in bytes.","format":"int64","type":"integer"},"diskWrite":{"description":"DiskWrite is the block-device write rate in bytes per second.","format":"double","type":"number"},"gpuMemTotal":{"description":"GPUMemTotal is dedicated VRAM in bytes; absent when the GPU shares system memory (unified).","format":"int64","type":"integer"},"gpuMemUsed":{"description":"GPUMemUsed is the memory held by GPU processes, in bytes.","format":"int64","type":"integer"},"gpuPower":{"description":"GPUPower is the total GPU power draw in watts.","format":"double","type":"number"},"gpuPowerLimit":{"description":"GPUPowerLimit is the total enforced GPU power limit in watts; absent when the driver reports none.","format":"double","type":"number"},"gpuTemp":{"description":"GPUTemp is the hottest GPU's temperature in °C.","format":"double","type":"number"},"gpuUtil":{"description":"0..1 aggregate utilization","format":"double","type":"number"},"kvCache":{"description":"KVCache is the KV-cache occupancy, 0..1.","format":"double","type":"number"},"load1":{"description":"Load1 is the machine's own one-minute load average — a count of runnable and\nuninterruptible tasks, NOT a percentage and NOT already divided by core\ncount, so it is read against Spec.CPUs: 8.0 is idle on 16 cores and swamped\non 4. Coerced finite and non-negative on write, so 0 means either genuinely\nidle or nothing reported.","format":"double","type":"number"},"load15":{"description":"Load15 is the same figure over fifteen. The three together are what separate\na machine that is busy right now from one that has been busy all along —\nwhich is the question a dispatcher is really asking.","format":"double","type":"number"},"load5":{"description":"Load5 is the same figure averaged over five minutes.","format":"double","type":"number"},"memFree":{"description":"bytes","format":"int64","type":"integer"},"memUsed":{"description":"bytes","format":"int64","type":"integer"},"model":{"description":"Model is the model id(s) served on this machine, comma-separated, at most 128 bytes.","type":"string"},"netRx":{"description":"NetRx is the receive rate of physical interfaces in bytes per second.","format":"double","type":"number"},"netTx":{"description":"NetTx is the transmit rate of physical interfaces in bytes per second.","format":"double","type":"number"},"prefill":{"description":"Prefill is prompt (prefill) throughput over the sample window, in tokens per second.","format":"double","type":"number"},"running":{"description":"Running is the number of requests being served now.","format":"int64","type":"integer"},"ttft":{"description":"TTFT is the mean time to first token, in seconds, of requests that started in the window.","format":"double","type":"number"},"waiting":{"description":"Waiting is the number of requests queued.","format":"int64","type":"integer"}},"type":"object"},"agent.Reply":{"properties":{"channel":{"description":"Channel is the room inside that workspace, and it is what decides whether\nthere is an address at all. Empty is the ordinary case: a caller of\n/v1/agent/coding holds a session id and reads the stream instead.","type":"string"},"provider":{"description":"Provider is the transport the conversation is on — slack, discord,\ntelegram, teams — and it is what decides who can carry the text at all. An\naddress without it names a room in no particular workspace.","type":"string"},"thread":{"description":"Thread narrows the address to one thread inside the channel — on Slack the\nparent message's ts, the same value a reply carries as thread_ts. Empty\nputs the text at the top level of the channel.","type":"string"},"turn":{"description":"Turn is the turn that renders a run started here: the session whose one\nmessage the run's progress and its outcome are shown in. A run with a Turn\nposts nothing of its own — one question, one message. The dispatcher writes\nit (apps/agents/replyto.go); a model never does.","type":"string"},"user":{"description":"User is the platform's id for the person the conversation is with — whose\nrun it is. A run's buttons name them to anyone else who presses one; it is\nnever what decides who may (that is the chat identity).","type":"string"}},"type":"object"},"agent.Spec":{"properties":{"arch":{"description":"amd64 | arm64 | ...","type":"string"},"cpus":{"description":"logical cores","format":"int64","type":"integer"},"gpus":{"description":"GPUs is every accelerator the machine advertises, one entry each, capped at\n32 on write. Empty means the probe found none — and that is the answer a\nNeed is checked against, so a machine with no entry here clears no\naccelerator floor. The list is not vendor-filtered: what satisfies a job is\ncounts and VRAM, never a brand (see Need).","items":{"$ref":"#/components/schemas/agent.GPU"},"type":"array"},"memory":{"description":"total RAM, bytes","format":"int64","type":"integer"},"os":{"description":"linux | darwin | windows","type":"string"}},"type":"object"},"agent.activityFeed":{"properties":{"activity":{"description":"Activity is the merged run/create/update events, newest first, capped at 50.","items":{"$ref":"#/components/schemas/agent.activityView"},"type":"array"}},"type":"object"},"agent.activityView":{"properties":{"agent":{"description":"agent name","type":"string"},"at":{"description":"RFC3339 UTC","type":"string"},"id":{"description":"ID identifies the event, and its shape says which kind it is: a run event\ncarries the run's own id, while an agent event is the agent id suffixed\n\":created\" or \":updated\". Unique within a feed, and not an address — there is\nnothing to fetch it by.","type":"string"},"kind":{"description":"invoked|failed|created|updated (from real events)","type":"string"},"message":{"description":"Message is the line to render, already bounded: \"Invoked \u003cmodel\u003e\" for a run\nthat worked, the run's own error truncated to 200 characters for one that did\nnot (or \"Run failed\" when it said nothing), and a fixed phrase for the two\nagent events. Nothing here is invented — every event is a row that exists.","type":"string"}},"type":"object"},"agent.agentDetail":{"properties":{"avatar":{"description":"Avatar is an image the agent is drawn as — a link to one, or the bytes\ninline as a data URL, up to 96 KiB. Emoji is the one glyph a caller picked\nwhen they had no image. At most one is ever set; neither means the agent is\ndrawn as its initial, the same way a person with no photo is. Both are\niam/pkg/schema's Mark, so a face means the same thing on an agent as it\ndoes on a person or an org.\nAvatar is the agent's picture: an image URL, or the image itself inline as a\ndata URL up to 96 KiB. Empty when the agent has no image.","type":"string"},"cap_micro_usd":{"description":"CapMicroUSD is the total this agent may spend within one Period, as an\ninteger number of micro-USD (1,000,000 = $1). It is required at creation: a\ncap of zero would mean no limit and no per-agent spend record at all.","format":"int64","type":"integer"},"computeRef":{"description":"ComputeRef is the visor machine this bot is bound to, opaque here: this\npackage stores and echoes it, and the binding's lifecycle belongs elsewhere.\nEmpty means unbound, which is what every one-shot agent is.","type":"string"},"consumed_micro_usd":{"description":"ConsumedMicroUSD is what has been spent in the current period, in micro-USD.\nIt is settled from what the gateway reported, not from the quote.","format":"int64","type":"integer"},"createdAt":{"description":"CreatedAt is when the agent was defined, RFC 3339 in UTC to the second.","type":"string"},"description":{"description":"Description is the one line another agent reads when deciding whether to call\nthis one: the tool catalogue publishes it as the description of `agent_\u003cname\u003e`,\nfalling back to \"agent \u003cname\u003e\" when it is empty. It is not part of the prompt —\nInstructions is — so writing the behaviour here reaches the caller and not the\nmodel.","type":"string"},"emoji":{"description":"Emoji is the single glyph a caller picked when they had no image. At most one\nof avatar and emoji is ever set; neither means the agent is drawn as its\ninitial, the same way a person with no photo is.","type":"string"},"executionMode":{"description":"ExecutionMode is one-shot or long-running, and it decides who may start this\nagent. one-shot runs only when something POSTs to it; long-running is\nadditionally invoked by the scheduler on Schedule, once a minute against the\ncron. An org's long-running agents are capped, so a switch INTO it can be\nrefused with 409.","type":"string"},"id":{"description":"ID is the agent's stable handle, minted here as \"agent_\" + 32 hex characters\nof crypto/rand. A caller cannot choose it, and it never changes — unlike Name,\nwhich is the other way to address the same agent.","type":"string"},"instructions":{"description":"Instructions is the agent's system prompt, verbatim, up to 32 KiB. It is the\none field the list read withholds, because it is the agent's whole behaviour\nand a page of them would be a page of prompts.","type":"string"},"lineage":{"description":"Lineage is every agent above this one, nearest first — the parent, its\nparent, and so on to the agent a person defined. All of them are in this\norg, so the principal this agent answers to is theirs.","items":{"type":"string"},"type":"array"},"max_task_micro_usd":{"description":"MaxTaskMicroUSD is the ceiling for a single run, in micro-USD. A session\ncannot exceed it even when the period cap still has room, so one runaway\ntask cannot consume a month.","format":"int64","type":"integer"},"model":{"description":"Model is the Zen model this agent runs on, and it is always OUR name for it:\nwrites normalize through cloud.ZenModel and the read normalizes again, so an\nupstream family name never leaves here even from a row written before that\nrule existed. A create that named none took the deployment's configured\ndefault, so this is where a caller learns which model it actually got.","type":"string"},"name":{"description":"Name is the agent's org-unique handle, matching\n^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$. It addresses the agent everywhere ID does,\nit is what a run row records, and it is the suffix of the `agent_\u003cname\u003e` tool\nother agents call this one by. Set once at create; no update route moves it,\nbecause moving it would orphan that history.","type":"string"},"parent":{"description":"Parent is the agent that spawned this one; absent for an agent a person\ndefined.","type":"string"},"period":{"description":"Period is the window the cap resets on: day, week or month.","type":"string"},"recentRuns":{"description":"RecentRuns is the agent's 20 most recent executions, newest first. It is a\nwindow on the history, not the history: the count beside it is `runs`.","items":{"$ref":"#/components/schemas/agent.agentRunView"},"type":"array"},"runs":{"description":"Runs is how many executions the org has recorded against this agent, counted\nat read time. The list and update reads count the WHOLE history; the detail\nread reports the size of the RecentRuns page it carries, which stops at 20 —\nso a detail row saying 20 means \"at least 20\", not \"exactly 20\".","format":"int64","type":"integer"},"schedule":{"description":"Schedule is the 5-field cron the scheduler fires a long-running agent on,\nevaluated once a minute. Required for long-running and DROPPED for one-shot —\na one-shot agent's schedule is not stored, so absence here is the mode's\nanswer rather than a value nobody set.","type":"string"},"serviceAccountId":{"description":"ServiceAccountID is the IAM agent service account (\u003corg\u003e-\u003cagent\u003e) a scheduled\nrun is billed AS. It is what makes an autonomous run attributable to a\nprincipal rather than only to the org; empty means the org itself wears the\nspend.","type":"string"},"status":{"description":"Status is the agent's readiness, and today it is \"ready\" on every row: an\nagent is a definition rather than a provisioned thing, so nothing transitions\nit. Server-set at create; no route accepts it.","type":"string"},"tools":{"description":"Tools are the tool names this agent may call, and the list IS the authority:\nan agent that declares none gets none. The single entry \"*\" means whatever the\nfleet's MCP server serves at the moment of the run, resolved per run rather\nthan frozen here, which is how the default assistant reaches subsystems that\nshipped after it was defined. Empty array, never null.","items":{"type":"string"},"type":"array"},"updatedAt":{"description":"UpdatedAt is the last time any field above was written, same format. It moves\non an update to the DEFINITION and never on a run, so a busy agent nobody has\nedited keeps an old one.","type":"string"}},"type":"object"},"agent.agentList":{"properties":{"agents":{"description":"Agents is the org's agents, each carrying its recorded run count.","items":{"$ref":"#/components/schemas/agent.agentView"},"type":"array"}},"type":"object"},"agent.agentRunView":{"properties":{"actor":{"description":"Actor is the \"org/sub\" identity the run was executed and billed AS. Empty\nmeans there was no PERSON — a schedule or a service token — which is a\ndifferent fact from \"we do not know\", and the difference is what an audit\nasks about.","type":"string"},"agent":{"description":"What an operator needs to answer \"what ran, for whom, and what did it do\" —\nand, through traceId, to leave this record for the waterfall of the very\nsame run rather than a search that hopefully lands near it.\n\nAgent is on the row because the org-wide feed lists runs across agents, and\na run that cannot name its agent is an orphan in exactly the view built to\nmake sense of many of them. Every field is omitempty: a run recorded before\nthese columns existed reports absence rather than a zero it never measured.","type":"string"},"completionTokens":{"description":"CompletionTokens is the same measurement for what the model produced, on the\nsame final completion. It is a count of TOKENS, not of turns and not of money.","format":"int64","type":"integer"},"createdAt":{"description":"CreatedAt is when the run finished, RFC 3339 in UTC to the second — the\nduration above already says how long it had been going.","type":"string"},"durationMs":{"description":"DurationMs is wall-clock milliseconds around the completion, including a\nfailover's retries. It is time SPENT, not time billed.","format":"int64","type":"integer"},"error":{"description":"Error is why an \"ok\"-less run failed, as the failing call reported it. Empty\non every successful run.","type":"string"},"id":{"description":"ID is the run's handle, minted as \"run_\" + 32 hex characters. It is the key\nthe metering ledger records this run's per-round token spend under, so it is\nhow a bill and a run are joined.","type":"string"},"input":{"description":"Input is the text the run was given, verbatim.","type":"string"},"micro_usd":{"description":"MicroUSD is what the run spent, integer micro-USD. Absent when nothing was metered.","format":"int64","type":"integer"},"model":{"description":"Model is the model that actually SERVED this run, which is not always the one\nthe agent is defined on — a failover records what answered. Normalized to our\nname on the way out; the stored row is left exactly as it happened, because a\nrun is a record and rewriting it would be worse than the name it carries.","type":"string"},"output":{"description":"Output is what the model produced. Empty on an error run, and empty is also a\nlegitimate answer from a run that succeeded with nothing to say — Status is\nwhat separates those.","type":"string"},"promptTokens":{"description":"PromptTokens is what the gateway reported for the run's FINAL completion, and\nonly that one — a tool loop's earlier rounds are the metering ledger's account,\njoined by this run's id. Reading it as the run's total spend undercounts a\nloop.","format":"int64","type":"integer"},"status":{"description":"Status is the run's outcome, and there are exactly two: \"ok\" when the model\nanswered, \"error\" when it did not. It is written when the run ends, so no row\nhere is in flight.","type":"string"},"toolCalls":{"description":"ToolCalls is how many tool dispatches the run made — a count of ACTIONS, which\nis a different measurement from the token counts above and from the turns a\nbuild reports. Zero is a run that answered straight from the model.","format":"int64","type":"integer"},"traceId":{"description":"TraceID is the trace this run IS, so the record and its spans are one thing to\nmove between: it opens the waterfall for THIS run rather than a search that\nlands near it. Empty when the process had no tracer, never a fabricated id.","type":"string"}},"type":"object"},"agent.agentView":{"properties":{"avatar":{"description":"Avatar is an image the agent is drawn as — a link to one, or the bytes\ninline as a data URL, up to 96 KiB. Emoji is the one glyph a caller picked\nwhen they had no image. At most one is ever set; neither means the agent is\ndrawn as its initial, the same way a person with no photo is. Both are\niam/pkg/schema's Mark, so a face means the same thing on an agent as it\ndoes on a person or an org.\nAvatar is the agent's picture: an image URL, or the image itself inline as a\ndata URL up to 96 KiB. Empty when the agent has no image.","type":"string"},"cap_micro_usd":{"description":"CapMicroUSD is the total this agent may spend within one Period, as an\ninteger number of micro-USD (1,000,000 = $1). It is required at creation: a\ncap of zero would mean no limit and no per-agent spend record at all.","format":"int64","type":"integer"},"computeRef":{"description":"ComputeRef is the visor machine this bot is bound to, opaque here: this\npackage stores and echoes it, and the binding's lifecycle belongs elsewhere.\nEmpty means unbound, which is what every one-shot agent is.","type":"string"},"consumed_micro_usd":{"description":"ConsumedMicroUSD is what has been spent in the current period, in micro-USD.\nIt is settled from what the gateway reported, not from the quote.","format":"int64","type":"integer"},"createdAt":{"description":"CreatedAt is when the agent was defined, RFC 3339 in UTC to the second.","type":"string"},"description":{"description":"Description is the one line another agent reads when deciding whether to call\nthis one: the tool catalogue publishes it as the description of `agent_\u003cname\u003e`,\nfalling back to \"agent \u003cname\u003e\" when it is empty. It is not part of the prompt —\nInstructions is — so writing the behaviour here reaches the caller and not the\nmodel.","type":"string"},"emoji":{"description":"Emoji is the single glyph a caller picked when they had no image. At most one\nof avatar and emoji is ever set; neither means the agent is drawn as its\ninitial, the same way a person with no photo is.","type":"string"},"executionMode":{"description":"ExecutionMode is one-shot or long-running, and it decides who may start this\nagent. one-shot runs only when something POSTs to it; long-running is\nadditionally invoked by the scheduler on Schedule, once a minute against the\ncron. An org's long-running agents are capped, so a switch INTO it can be\nrefused with 409.","type":"string"},"id":{"description":"ID is the agent's stable handle, minted here as \"agent_\" + 32 hex characters\nof crypto/rand. A caller cannot choose it, and it never changes — unlike Name,\nwhich is the other way to address the same agent.","type":"string"},"lineage":{"description":"Lineage is every agent above this one, nearest first — the parent, its\nparent, and so on to the agent a person defined. All of them are in this\norg, so the principal this agent answers to is theirs.","items":{"type":"string"},"type":"array"},"max_task_micro_usd":{"description":"MaxTaskMicroUSD is the ceiling for a single run, in micro-USD. A session\ncannot exceed it even when the period cap still has room, so one runaway\ntask cannot consume a month.","format":"int64","type":"integer"},"model":{"description":"Model is the Zen model this agent runs on, and it is always OUR name for it:\nwrites normalize through cloud.ZenModel and the read normalizes again, so an\nupstream family name never leaves here even from a row written before that\nrule existed. A create that named none took the deployment's configured\ndefault, so this is where a caller learns which model it actually got.","type":"string"},"name":{"description":"Name is the agent's org-unique handle, matching\n^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$. It addresses the agent everywhere ID does,\nit is what a run row records, and it is the suffix of the `agent_\u003cname\u003e` tool\nother agents call this one by. Set once at create; no update route moves it,\nbecause moving it would orphan that history.","type":"string"},"parent":{"description":"Parent is the agent that spawned this one; absent for an agent a person\ndefined.","type":"string"},"period":{"description":"Period is the window the cap resets on: day, week or month.","type":"string"},"runs":{"description":"Runs is how many executions the org has recorded against this agent, counted\nat read time. The list and update reads count the WHOLE history; the detail\nread reports the size of the RecentRuns page it carries, which stops at 20 —\nso a detail row saying 20 means \"at least 20\", not \"exactly 20\".","format":"int64","type":"integer"},"schedule":{"description":"Schedule is the 5-field cron the scheduler fires a long-running agent on,\nevaluated once a minute. Required for long-running and DROPPED for one-shot —\na one-shot agent's schedule is not stored, so absence here is the mode's\nanswer rather than a value nobody set.","type":"string"},"serviceAccountId":{"description":"ServiceAccountID is the IAM agent service account (\u003corg\u003e-\u003cagent\u003e) a scheduled\nrun is billed AS. It is what makes an autonomous run attributable to a\nprincipal rather than only to the org; empty means the org itself wears the\nspend.","type":"string"},"status":{"description":"Status is the agent's readiness, and today it is \"ready\" on every row: an\nagent is a definition rather than a provisioned thing, so nothing transitions\nit. Server-set at create; no route accepts it.","type":"string"},"tools":{"description":"Tools are the tool names this agent may call, and the list IS the authority:\nan agent that declares none gets none. The single entry \"*\" means whatever the\nfleet's MCP server serves at the moment of the run, resolved per run rather\nthan frozen here, which is how the default assistant reaches subsystems that\nshipped after it was defined. Empty array, never null.","items":{"type":"string"},"type":"array"},"updatedAt":{"description":"UpdatedAt is the last time any field above was written, same format. It moves\non an update to the DEFINITION and never on a run, so a busy agent nobody has\nedited keeps an old one.","type":"string"}},"type":"object"},"agent.buildList":{"properties":{"builds":{"description":"Builds is every published build, most recently updated first.","items":{"$ref":"#/components/schemas/agent.buildSummary"},"type":"array"}},"type":"object"},"agent.buildSummary":{"properties":{"agent":{"description":"Agent is the label the surface that did the work calls itself by.","type":"string"},"endedAt":{"description":"EndedAt is when it finished, same format. Empty means it is still going.","type":"string"},"org":{"description":"Org and Project are the build's public ADDRESS — the pair the full story is\nread at, and the pair a visitor sees in the URL bar. Not a tenant key: this\nindex is anonymous and lists only what authors published.","type":"string"},"project":{"description":"Project is the product's slug, the second half of that address.","type":"string"},"repo":{"description":"Repo is the repository the work was done in, as the session reported it.","type":"string"},"session":{"description":"Session is the agent session behind the build, and the value its commits name\nin their `Hanzo-Session:` trailer.","type":"string"},"startedAt":{"description":"StartedAt is when the session opened, RFC 3339 in UTC.","type":"string"},"status":{"description":"Status is the session's own: running, paused, done or error — so a card can\nshow a build still being written.","type":"string"},"title":{"description":"Title is the human line for the card. Sent even when empty, like every field\nhere, because that is what this route has always sent.","type":"string"},"turns":{"description":"Turns is HOW MANY turns the transcript holds — a COUNT, unlike the `turn` on\neach turn of the full story, which is that turn's position. The full read\nreturns at most 1000 of them; this number is not capped.","format":"int64","type":"integer"}},"type":"object"},"agent.buildTurn":{"properties":{"actor":{"description":"Actor is who took the turn. A deploy turn's actor is the literal \"deploy\",\nbecause nobody took it.","type":"string"},"at":{"description":"At is when the turn was recorded, RFC 3339 in UTC to the second.","type":"string"},"body":{"description":"Body is the readable text of the turn, taken from the stored event's `text`.\nEmpty when the event carried a payload of some other shape — this route reads\ntranscripts and does not invent prose for turns that are not one.","type":"string"},"commit":{"description":"Commit is the full sha this turn produced, empty when the turn changed\nnothing. It is ECHOED from the transcript, and the authority is the commit\nitself: it carries the `Hanzo-Session:`/`Hanzo-Turn:` trailer, or a note under\nrefs/notes/hanzo-provenance saying the same, so the claim is checkable at\nsource with the command in `verify`.","type":"string"},"kind":{"description":"Kind is what the turn was, from the log's closed six: message, tool-call,\nspawn, log, status, control. A deploy arrives as a `status` turn.","type":"string"},"subject":{"description":"Subject is that commit's subject line, from the same transcript, so a reader\nsees what the commit says without fetching the repository.","type":"string"},"turn":{"description":"Seq is this turn's POSITION in the session's log — monotonic from 1, per\nsession — and it is what a commit's `Hanzo-Turn:` trailer names. It is not a\ncount of anything: the count is `turns` on the summary beside it.","format":"int64","type":"integer"}},"type":"object"},"agent.buildView":{"properties":{"agent":{"description":"Agent is the label the surface that did the work calls itself by.","type":"string"},"endedAt":{"description":"EndedAt is when it finished, same format. Empty means it has not — the build\nis still going.","type":"string"},"model":{"description":"Model is the model that did the work, taken from the FIRST turn whose body\nnames one — a transcript states it, this route does not resolve it. Empty when\nno turn said.","type":"string"},"org":{"description":"Org is the org that published this build, echoed from the URL. It is part of\nthe build's public ADDRESS and not a tenant key — this route is anonymous, and\nthe only rows it can reach are ones an author explicitly published.","type":"string"},"project":{"description":"Project is the product's slug, the other half of that address.","type":"string"},"repo":{"description":"Repo is the repository the work was done in, as the session reported it.","type":"string"},"session":{"description":"Session is the id of the agent session this story IS — the same value a\nproduced commit carries in its `Hanzo-Session:` trailer, which is what ties\nthe repository's history to this page.","type":"string"},"startedAt":{"description":"StartedAt is when the session opened, RFC 3339 in UTC.","type":"string"},"status":{"description":"Status is the session's own: running, paused, done or error. A build can be\nread while it is still being written, so this is not always terminal — and an\n`error` build is still a readable story, not a missing page.","type":"string"},"title":{"description":"Title is the human line the session was opened or renamed with. Empty when\nnobody gave it one.","type":"string"},"turns":{"description":"Turns is the whole transcript, oldest first, capped at 1000: a published build\nis a story to read down, not an archive to page.","items":{"$ref":"#/components/schemas/agent.buildTurn"},"type":"array"},"verify":{"description":"Verify is the exact command that re-derives every commit binding below\nstraight from git, so nothing here has to be taken on trust.","type":"string"}},"type":"object"},"agent.claimKeyOut":{"properties":{"claimKey":{"description":"ClaimKey is the capability itself. It is returned ONCE and never again — only\nits SHA-256 hash is stored — so a daemon that loses it mints a new one.","type":"string"},"targetId":{"description":"TargetID is the machine the key authenticates.","type":"string"}},"type":"object"},"agent.codingInstruction":{"properties":{"session":{"description":"Session identifies the running or paused coding session from the path.","type":"string"},"text":{"description":"Text is the new instruction to carry into the follow-up run.","type":"string"}},"type":"object"},"agent.controlCommandView":{"properties":{"command":{"description":"Command is what was asked, from a closed four: pause, resume, stop, message.\nIt is an INTENT — the poller decides what to do about it, and the session's\nstatus changes only when the poller reports back that it did.","type":"string"},"message":{"description":"Message is the text that came with the command: what to say into the run for\n`message`, and the cancellation reason for `stop`. Up to 16 KiB. Empty on a\nbare pause or resume.","type":"string"},"payload":{"description":"Payload is the structured half a caller sent instead of (or beside) Message,\nembedded as JSON. Its shape is the caller's business; this surface carries it\nthrough untouched."},"seq":{"description":"Seq is this command's position in the session's log — the same monotonic\nnumber every other turn is ordered by, so a command sits in the transcript\nwhere it was issued. Send the highest one you applied back as `after` and it\nis never redelivered.","format":"int64","type":"integer"}},"type":"object"},"agent.controlDrain":{"properties":{"commands":{"description":"Commands is the session's control commands newer than the cursor, oldest first.","items":{"$ref":"#/components/schemas/agent.controlCommandView"},"type":"array"},"cursor":{"description":"Cursor is the seq to send as `after` on the next poll — the highest seq in\nthis page, or the cursor sent in when the page is empty.","format":"int64","type":"integer"}},"type":"object"},"agent.controlIn":{"properties":{"id":{"description":"ID is the session to steer, from the path.","type":"string"},"message":{"description":"Message is free text for the running agent, up to 16 KiB. On a stop it is\nrecorded as the cancellation reason.","type":"string"},"payload":{"description":"Payload is a structured argument for the command: any valid JSON up to\n64 KiB, scanned for credentials before it is stored (a hit refuses the\ncommand with 422 and the findings). A task-backed session receives it as\nthe forwarded signal's argument."}},"type":"object"},"agent.controlResult":{"properties":{"command":{"description":"Command is the verb that was recorded: pause, resume, stop or message.","type":"string"},"event":{"$ref":"#/components/schemas/agent.eventView","description":"Event is the durable control event the command became. The intent is\nrecorded whether or not it reached an engine, which is what makes a\nstream-consuming surface able to act on it."},"forwarded":{"description":"Forwarded is whether the command also reached the durable-execution engine.\nFALSE IS NOT A FAILURE: a session with no workflow link, or a deployment\nwith no tasks backend, is record-only by design. A forward that was\nattempted and failed is a 502, never a false here.","type":"boolean"},"run":{"description":"Run is the run a resume started, under the same session. Empty for every\nother command.","type":"string"}},"type":"object"},"agent.createAgentIn":{"properties":{"avatar":{"description":"Avatar and Emoji are how the agent APPEARS. An image wins when both are\ngiven — it is the thing somebody made — and both empty leaves the agent\ndrawn as its initial. Validated by iam/pkg/schema, the same rule a person's\navatar passes, so the 96 KiB bound and the accepted URL forms are stated\nonce for every subject that has a face.","type":"string"},"cap_micro_usd":{"description":"The budget, required. An agent is not creatable without one: a zero cap\nwould mean no limit and no record of its spend, which is what a budget\nexists to remove. Integer micro-USD; the CLI converts dollars before sending.","format":"int64","type":"integer"},"computeRef":{"description":"ComputeRef optionally binds this bot to a visor machine. Opaque here, bounded\nat 256 characters, and not resolved — this package stores the reference and\nthe binding's lifecycle belongs elsewhere.","type":"string"},"description":{"description":"Description is the one line published as the description of the `agent_\u003cname\u003e`\ntool, which is how another agent decides whether to call this one. Optional,\nand worth writing for exactly that reason.","type":"string"},"emoji":{"description":"Emoji is the single glyph shown when there is no image. An image WINS when\nboth are given — it is the thing somebody made — and both empty leaves the\nagent drawn as its initial.","type":"string"},"executionMode":{"description":"ExecutionMode is one-shot or long-running. Empty takes one-shot, which runs\nonly when something POSTs to it. long-running additionally requires Schedule,\nand counts against a per-org cap that answers 409 when it is full.","type":"string"},"instructions":{"description":"Instructions is the system prompt, up to 32 KiB, stored verbatim. This is what\nthe model reads; Description is what other CALLERS read.","type":"string"},"max_task_micro_usd":{"description":"MaxTaskMicroUSD is the ceiling for a single run, in micro-USD. A session\ncannot exceed it even when the period cap still has room, so one runaway\ntask cannot consume a month.","format":"int64","type":"integer"},"model":{"description":"Model names the model to run on. Omit it to take the deployment's configured\ndefault; name one and it is checked against the gateway's served catalogue\nhere, so a model this deployment cannot serve is refused now rather than at\nthe first run. Stored under our own name for it, whatever spelling arrives.","type":"string"},"name":{"description":"Name is the agent's org-unique handle and the only required field. It must\nmatch ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$, and a name already taken in this org\nis a 409 rather than an overwrite. It is permanent: no update route moves it.","type":"string"},"parent":{"description":"Parent is the agent spawning this one — its id or name, in the caller's\norg. The new agent answers to the org its parent answers to, and a parent\noutside the caller's org is not found: an agent is never spawned into a\nprincipal its creator does not answer to. Omitted for an agent a person\ndefines. Set once; no update moves it.","type":"string"},"period":{"description":"Period is the window the cap resets on: day, week or month.","type":"string"},"schedule":{"description":"Schedule is the 5-field cron a long-running agent fires on, parsed here so a\nbad expression is a 400 and not an agent that silently never runs. Required\nwith long-running; DISCARDED for one-shot rather than stored unused.","type":"string"},"serviceAccountId":{"description":"ServiceAccountID optionally names the IAM agent service account (\u003corg\u003e-\u003cagent\u003e)\na scheduled run should be billed AS, so an autonomous run is attributable to a\nprincipal rather than only to the org. Same 256-character bound, also\nunresolved here.","type":"string"},"tools":{"description":"Tools are the tool names this agent may call. Omitted or empty grants NONE —\nthat default is the agent's authority and is not widened anywhere. The single\nentry \"*\" means whatever the fleet's MCP server serves at the time of each run.","items":{"type":"string"},"type":"array"}},"type":"object"},"agent.eventIn":{"properties":{"actor":{"description":"Actor is who produced the turn. Empty takes the validated caller, which is\nwhat an agent writing its own transcript wants; naming one is for a surface\nrecording on somebody else's behalf.","type":"string"},"id":{"description":"ID is the session to append to, from the path.","type":"string"},"kind":{"description":"Kind is what this turn IS: message, tool-call, spawn, log, status, control\nor progress. Anything else is refused — the vocabulary is closed so a\nreader can branch on it.","type":"string"},"payload":{"description":"Payload is the turn's own body, any valid JSON up to 64 KiB. It is SCANNED\nfor credentials before it is stored, and a hit refuses the whole append with\n422 and the findings — this plane never redacts a secret into a transcript\nit then keeps.\n\nIts SHAPE is the writer's business for every kind but one: a `progress`\nturn is the run reporting on itself in a shape this surface publishes —\n{\"pct\":0-100 (optional), \"phase\":\"running|blocked|done\",\n\"activity\":\"≤120 chars\"} — so a malformed one is refused with 400 instead\nof being stored as prose nobody reads."}},"type":"object"},"agent.eventView":{"properties":{"actor":{"description":"Actor is who produced the turn. A write that names nobody takes the calling\nprincipal, so this is rarely empty in practice.","type":"string"},"createdAt":{"description":"CreatedAt is when the turn was recorded, RFC 3339 in UTC to the second. Seconds\nare coarse enough that two turns can share one, which is why Seq and not this\nis the order.","type":"string"},"id":{"description":"ID is the event's own handle, minted as \"evt_\" + 32 hex characters. It\nidentifies the turn; Seq is what ORDERS it.","type":"string"},"kind":{"description":"Kind is what the turn IS, from a closed six: message (a model turn),\ntool-call, spawn (a subagent started), log, status, control (a steering\ncommand the running surface consumes). Anything else is refused at the write.","type":"string"},"payload":{"description":"Payload is the turn's body, embedded as JSON rather than as a string —\nwhatever the writer sent, up to 64 KiB, checked for well-formedness and\nscanned for credentials before it was stored. Its SHAPE is the writer's\nbusiness and varies by Kind; this surface does not interpret it, except\nthat every string in it is kept as plain text: terminal escape sequences\nand control characters other than the line break and the tab are removed."},"seq":{"description":"Seq is the turn's position in this session's log: monotonic from 1, assigned\nby the store inside the insert, and unique PER SESSION rather than globally.\nIt is the cursor a reader resumes from after a reconnect — ask for everything\nafter your last-seen seq.","format":"int64","type":"integer"},"sessionId":{"description":"SessionID is the session this turn belongs to. Carried on every event so a\nstream frame stands alone — a subscriber watching a whole tree gets turns from\nseveral sessions down one connection.","type":"string"}},"type":"object"},"agent.lastEventView":{"properties":{"actor":{"description":"Actor is who produced the turn, defaulted to the calling principal when the\nwriter named nobody.","type":"string"},"at":{"description":"At is when the turn was recorded, RFC 3339 in UTC to the second.","type":"string"},"kind":{"description":"Kind is what the turn was, from the log's closed six: message, tool-call,\nspawn, log, status, control.","type":"string"},"preview":{"description":"Preview is the first 240 bytes of the event's payload, cut without regard for\nthe JSON inside it — it is a string to SHOW, never a value to parse. Read the\ndetail or the stream for the whole payload.","type":"string"},"seq":{"description":"Seq is that event's position in the session's log — monotonic from 1, per\nsession. A reader holding it can ask the detail or stream reads for\neverything after it, so this doubles as the list's resume cursor.","format":"int64","type":"integer"}},"type":"object"},"agent.metricsView":{"properties":{"range":{"description":"echoes the requested window (24H|7D|30D)","type":"string"},"resource":{"$ref":"#/components/schemas/agent.resourceUsage","description":"Resource is the Resource Usage panel's rollup, and every field of it is\ncurrently null — see resourceUsage. It is present rather than omitted so a\npanel renders \"—\" instead of guessing."},"series":{"description":"per-agent invocation histogram (real)","items":{"$ref":"#/components/schemas/agent.seriesLine"},"type":"array"}},"type":"object"},"agent.patchSessionIn":{"properties":{"cwd":{"description":"Cwd is where the session is working NOW.\n\nIt was write-once — captured at register and never again — which is right\nfor a run that starts in a directory and stays there, and wrong for a linked\nshell, which is a place a person moves around in. The console showed the\ndirectory `hanzo link` happened to be run from and kept showing it after the\nshell had walked away, so the field answered \"which work is this\" with an\nanswer that was true once. A pointer, so an unchanged path is an omitted\nfield rather than a repeated write.","type":"string"},"id":{"description":"ID is the session to update, from the path.","type":"string"},"project":{"description":"Project tags the product this session built; Published is the author's\ndecision to let anyone read the story (provenance.go). Both are pointers so\n\"absent\" and \"cleared\" are different requests.","type":"string"},"published":{"description":"Published opens the session's story to the public build route; false withdraws\nit, and withdrawing is always allowed. PUBLISHING is refused unless the\nsession names a Project — the one set in this same request, or the one already\nstored — because that route is keyed on (org, project). It widens READ access\nto what is already there and grants nothing else.","type":"boolean"},"status":{"description":"Status moves the session to running, paused, done or error. A session that has\nalready finished refuses any change with 409 — done and error are monotonic —\nand moving INTO one stamps the end time. This is the surface REPORTING what\nhappened; a control command never writes it.","type":"string"},"target":{"description":"Target re-dispatches a session to a run-target (the #48 association). \"\" detaches.","type":"string"},"terminal":{"description":"Terminal publishes (or, with \"\", withdraws) the URL this session's live\nterminal can be watched at. A pointer so \"absent\" and \"withdrawn\" are\ndifferent requests: a session that stops sharing must be able to say so.","type":"string"},"title":{"description":"Title rewrites the human line, up to 512 characters — usually because the work\nturned out to be something other than what it was opened as.","type":"string"}},"type":"object"},"agent.patchTargetIn":{"properties":{"capacity":{"description":"Capacity rewrites the human summary, up to 256 characters. \"\" clears it.","type":"string"},"host":{"description":"Host re-points the hostname sessions are matched by. Moving it moves the load:\nthe session counts follow the new name from the next read.","type":"string"},"id":{"description":"ID is the target to update, from the path.","type":"string"},"kind":{"description":"Kind re-files it under laptop | cloud | gpu | cluster | machine.","type":"string"},"label":{"description":"Label renames the machine, up to 128 characters. Empty STRING is refused — a\ntarget with no name is a row nobody can pick out of a fleet.","type":"string"},"metrics":{"$ref":"#/components/schemas/agent.Metrics","description":"Metrics replaces the live sample, and sending one IS A HEARTBEAT: the server\nstamps the time and appends the point to the fleet series. Sending an all-zero\nsample CLEARS the heartbeat — the machine goes back to having no liveness fact\nat all, and its stored status is taken at face value again."},"spec":{"$ref":"#/components/schemas/agent.Spec","description":"Spec replaces the static capability whole, sanitized and clamped the same way\na register's is."},"status":{"description":"Status sets operator INTENT: online | offline | draining. Draining is how a\nmachine is taken out of dispatch without ending what is already on it. What\ncomes back may still read offline, because the heartbeat outranks the intent.","type":"string"}},"type":"object"},"agent.registerReq":{"properties":{"account":{"description":"Account is which subscription or API account under that provider served the\nrun, up to 256 characters. It is what lets a revoke of that login stop exactly\nthe sessions it was paying for.","type":"string"},"agent":{"description":"Agent is the label the surface opening this session calls itself by\n(\"hanzo-dev\"). REQUIRED, up to 128 characters, and free text — nothing\nresolves it against a defined agent.","type":"string"},"budget_micro_usd":{"description":"BudgetMicroUSD caps what this session may spend, integer micro-USD. Zero\nmeans no cap; a cap can be raised or removed later, never added.","format":"int64","type":"integer"},"cwd":{"description":"Cwd is the directory the session starts in, up to 1024 characters. It can be\nmoved later, because a linked shell walks around.","type":"string"},"host":{"description":"Execution context — where this session runs (all optional).","type":"string"},"parentSessionId":{"description":"ParentSessionID makes this a subagent of that session: it inherits the\nparent's root, so one flow stays one tree. The parent must exist IN THE SAME\nORG — a foreign or unknown id is a 400, never a tree across tenants. Empty\nopens a root session.","type":"string"},"project":{"description":"The readable build (provenance.go): which product this session builds, and\nwhether its story may be read by the world.","type":"string"},"provider":{"description":"Account tag — the linked AI account this session ran under (login manager).","type":"string"},"published":{"description":"Published opens this session's story to the public build route. It is refused\nwithout a Project, because that route is keyed on (org, project) — a build\nwith no product is not a story anyone can open. False keeps it org-only.","type":"boolean"},"repo":{"description":"Repo is the code being worked on, up to 512 characters. A label the surface\nstates; nothing resolves it against the forge.","type":"string"},"room":{"description":"Room is the collaborative room this run was started in (HIP-0523), so a\nspace view can list the sessions of one room. It is PROVENANCE and is set\nonly here: there is deliberately no way to move a session to another room, so\nit is absent from the patch input and from UpdateSession's SET list.","type":"string"},"status":{"description":"Status opens the session in one of running, paused, done or error. Empty means\nrunning. A TERMINAL status here (done, error) records a session that has\nalready finished — its end time is stamped now — and nothing can move it\nafterwards.","type":"string"},"target":{"description":"Target names a run-target the org has registered. Unlike Host and Repo it IS\nresolved: a target that does not exist in this org is a 400, so a session can\nnever claim to run on another tenant's machine. Empty names no machine.","type":"string"},"taskRunId":{"description":"TaskRunID is that workflow's particular run, same bound. Recorded, not\nresolved: this surface does not check the workflow exists.","type":"string"},"taskWorkflowId":{"description":"TaskWorkflowID links this session to the hanzoai/tasks workflow that executes\nit, up to 256 characters. Set it and control commands are forwarded to that\nengine; leave it and the running surface polls for them instead.","type":"string"},"terminal":{"description":"Terminal is the URL this session's live terminal is published at, so the\nconsole can watch it. Optional — a session that publishes nothing is still\na session.","type":"string"},"title":{"description":"Title is the human line a card shows, up to 512 characters. Optional, and\nchangeable later.","type":"string"}},"type":"object"},"agent.reportOut":{"properties":{"delivered":{"description":"Delivered is true when a waiting durable owner received this result. False\nmeans there was none to deliver to — an unknown or already-finished run — which\nis a clean no-op, not an error.","type":"boolean"}},"type":"object"},"agent.reportRunIn":{"properties":{"branch":{"description":"Branch, CommitSha and Diffstat describe what the run produced; Error is the\nfailure when OK is false. Each is clamped, never rejected.","type":"string"},"changed":{"description":"Changed says whether the run produced any commit. It is INDEPENDENT of OK: a\nrun can succeed and change nothing (there was nothing to do), and a run can\nfail after committing some of its work. Two questions, two booleans.","type":"boolean"},"commitSha":{"description":"CommitSha is the tip the run pushed, clamped to 128 characters. Empty when it\npushed nothing, which is the same case Changed reports false for.","type":"string"},"diffstat":{"description":"Diffstat is the run's own summary of what it changed, as text, clamped to\n64 KiB. Free-form: it is shown, never parsed.","type":"string"},"error":{"description":"Error is why the run failed, clamped to 64 KiB. It is CLAMPED rather than\nrefused — a truncated reason is worth more than a rejected report, because a\nrejected report leaves the durable workflow waiting forever.","type":"string"},"id":{"description":"ID is the machine reporting, from the path.","type":"string"},"ok":{"description":"OK is whether the run succeeded; Changed whether it produced any commit.","type":"boolean"},"runId":{"description":"RunID is the routed run being completed, from the path.","type":"string"}},"type":"object"},"agent.resourceUsage":{"properties":{"costCents":{"description":"CostCents would be the window's spend in cents. Always null here — the money\na run costs is the metering ledger's, joined by the run id, and repeating it\nfrom this side would be a second number that could disagree with the bill.","format":"double","type":"number"},"cpuVcpuHours":{"description":"CPUVcpuHours would be vCPU-hours over the window. Always null: this store\nholds agent definitions and run I/O, and nothing here meters a CPU. Null is\nthe honest answer and 0 would be a claim.","format":"double","type":"number"},"memGbHours":{"description":"MemGbHours would be gigabyte-hours of memory. Always null, same reason.","format":"double","type":"number"},"storageIoBytes":{"description":"StorageIoBytes would be bytes moved to and from storage. Always null, same\nreason.","format":"double","type":"number"}},"type":"object"},"agent.routedRunOut":{"properties":{"base":{"description":"Base is the branch to start FROM. Empty means the repository's default —\nresolve it on the machine, since the machine is the one holding the clone.","type":"string"},"branch":{"description":"Branch is the ref the run must push its work to, and the ONLY one it is\npermitted to write: the forge's ref policy refuses anything else from this\nrun's credential. It is decided at dispatch and exists before the work does.","type":"string"},"cloneUrl":{"description":"CloneURL is how to fetch the repository. It carries NO credential — the\nmachine authenticates with the git identity it already holds — which is why\nthis whole shape is safe to hand to a claimed runner.","type":"string"},"effort":{"description":"Effort is how hard that model reasons: low, medium or high. Empty is the\nmodel's own default.","type":"string"},"instructions":{"description":"Instructions are the person's own instructions for their runs, as they set\nthem in their settings: the machine's harness reads them as its user's, the\nway AGENTS.md or CLAUDE.md in its home is read. Empty when they set none.","type":"string"},"model":{"description":"Model is the model the person asked the run's agent to think with, by the\nid GET /v1/models lists. Empty is the machine's own default.","type":"string"},"project":{"description":"Project is the product slug the run is filed under, so the machine can tag\nwhat it produces. Empty when the dispatch named none.","type":"string"},"prompt":{"description":"Prompt is the task, in full, as the person wrote it. There is no second field\nfor context.","type":"string"},"repo":{"description":"Repo is the repository to work in and CloneURL is how to fetch it.","type":"string"},"sessionId":{"description":"SessionID is the live session opened at dispatch; the machine streams its\nturns into it.","type":"string"},"timeoutSeconds":{"description":"TimeoutSeconds bounds the run on the machine; 0 means the machine's own default.","format":"int64","type":"integer"}},"type":"object"},"agent.runList":{"properties":{"runs":{"description":"Runs is the agent's executions, newest first.","items":{"$ref":"#/components/schemas/agent.agentRunView"},"type":"array"}},"type":"object"},"agent.seriesLine":{"properties":{"key":{"description":"agent name","type":"string"},"points":{"description":"Points is one bucket per interval across the whole window, in time order and\nnever sparse: a bucket with no runs is present with v 0, so two lines drawn\nfrom two agents share an x-axis without the client aligning anything. The\nwindow decides the count — 24 hourly for 24H, 7 daily, 30 daily.","items":{"$ref":"#/components/schemas/agent.seriesPoint"},"type":"array"}},"type":"object"},"agent.seriesPoint":{"properties":{"t":{"description":"bucket start, RFC3339 UTC","type":"string"},"v":{"description":"real invocation count in the bucket","format":"int64","type":"integer"}},"type":"object"},"agent.sessionBudgetIn":{"properties":{"budget_micro_usd":{"description":"BudgetMicroUSD is the new cap, or null to remove the cap for good.","format":"int64","type":"integer"},"id":{"description":"ID is the session, from the path.","type":"string"}},"type":"object"},"agent.sessionBudgetView":{"properties":{"budget_micro_usd":{"description":"BudgetMicroUSD is this session's own ceiling in micro-USD, beyond the agent's.\nA replacement must strictly exceed what the session has already consumed, and\nremoving it is one-way.","format":"int64","type":"integer"},"budget_removed":{"description":"BudgetRemoved says the session's own cap was taken off. It cannot be put back.","type":"boolean"},"consumed_micro_usd":{"description":"ConsumedMicroUSD is what has been spent in the current period, in micro-USD.\nIt is settled from what the gateway reported, not from the quote.","format":"int64","type":"integer"},"id":{"description":"ID names the session.","type":"string"},"status":{"description":"Status is the session's state: running, paused at its cap, or done.","type":"string"}},"type":"object"},"agent.sessionDetail":{"properties":{"account":{"description":"Account is which subscription or API account under that provider served it.\nTogether with Provider it is what a login revoke matches on to stop the\nsessions a withdrawn account was paying for.","type":"string"},"actor":{"description":"Actor is WHO this session belongs to, as \"org/sub\" — the same identity a run\nis billed under. A register that names none takes the calling principal. It is\nwhat scopes a login revoke, so a session with the wrong actor is a session the\nright person cannot stop.","type":"string"},"agent":{"description":"Agent is the label the surface running this session calls itself by\n(\"hanzo-dev\"), up to 128 characters. Required at register. It is free text,\nnot a reference: it need not name a defined agent, and nothing resolves it.","type":"string"},"base":{"description":"Base is the branch the run started from. Empty when it took the\nrepository's default and did not say which.","type":"string"},"branch":{"description":"Branch is the branch the run pushes its work to, and the only one it may\nwrite.","type":"string"},"childSessions":{"description":"Children is the session's DIRECT children, one level down, each with its own\ncounts. The promoted `children` integer beside it is how many there are; this\nis who they are. For the whole subtree, read the tree.","items":{"$ref":"#/components/schemas/agent.sessionView"},"type":"array"},"children":{"description":"Children is the DIRECT fan-out — how many sessions name this one as parent —\nand not the size of the subtree. Read the tree for that.","format":"int64","type":"integer"},"createdAt":{"description":"CreatedAt is when the row was written, same format. Every path that opens a\nsession stamps it and StartedAt from one clock reading, so the two are equal\non every session this surface has ever produced.","type":"string"},"cwd":{"description":"Cwd is the directory the session is working in NOW, not the one it started in:\na linked shell moves around, and a card showing where `hanzo link` was run\nanswers \"which work is this\" with something that was true once.","type":"string"},"endedAt":{"description":"EndedAt is when it reached done or error, same format. Empty while it is still\nrunning or paused, which is how absence reads here: not over yet.","type":"string"},"environment":{"description":"Environment is where the run executes: \"sandbox\" for a Hanzo sandbox, or the\nid of the org's machine it was routed to (the same id Target carries).","type":"string"},"events":{"description":"Events is how many turns the session's log holds, counted at read time. It is\nthe whole log, however few of them RecentEvents carries.","format":"int64","type":"integer"},"host":{"description":"Execution context (mission-control): the machine/repo/cwd a card shows and\nthe run-target a session is dispatched to. Omitted when a surface didn't report it.","type":"string"},"id":{"description":"ID is the session's handle, minted here as \"sess_\" + 32 hex characters. Every\nlater read, patch, event append and control command is addressed with it, and\na caller cannot choose it.","type":"string"},"kind":{"description":"Kind is what sort of run this session is the view of — \"coding\" for a coding\nrun. Empty for a session no run tagged.","type":"string"},"lastEvent":{"$ref":"#/components/schemas/agent.lastEventView","description":"LastEvent is the compact latest-activity line for the list projection (nil in\nregister/patch/tree responses; set by list + detail). It lets a swipe card show\na live one-line preview without fetching full detail."},"mode":{"description":"Mode is what the run may do to its repository: \"build\" edits, commits and\npushes its branch; \"plan\" reads and answers with a plan, writing nothing.\nEmpty for a session no run tagged.","type":"string"},"org":{"description":"Org is the caller's OWN tenant, echoed so a client can build the public\nbuild URL (/builds/:org/:project) without a second call or a guess. It is\nnever another tenant's — every read is org-scoped before it gets here.","type":"string"},"parentSessionId":{"description":"ParentSessionID is the session that spawned this one, making this a subagent\nof it. Empty means this session is a root — a flow of its own. A parent always\nbelongs to the same org, so a tree never crosses a tenant.","type":"string"},"pr":{"description":"PR is the address of the pull request the run proposed. Empty until it\nproposes one, and for a run that changed nothing.","type":"string"},"progress":{"$ref":"#/components/schemas/agent.sessionProgress","description":"Progress is how far along this run is — a share of its goal, a phase, and a\nline saying what it is doing. Always present, so a board never branches on\nwhether it is there; `phase` says \"unknown\" when nothing has estimated it.\nIt is a MODEL ESTIMATE wherever `estimated` is true, and the row's own word\nwhere it is false. See progress.go."},"project":{"description":"The readable build: the product this session built and whether its story\nis public (provenance.go).","type":"string"},"provider":{"description":"Provider is the linked AI account's provider (claude | codex | hanzo | …) that\nserved this run. Empty when the surface did not say.","type":"string"},"published":{"description":"Published is the author's decision to let anyone read this session's story at\nthe public build route. It only ever widens READ access to a session that\nalready exists and grants nothing else; false, an unpublished session is\ninvisible there no matter who asks. It cannot be true without a Project,\nbecause that route is keyed on (org, project).","type":"boolean"},"recentEvents":{"description":"RecentEvents is the 50 most recent turns, OLDEST of those first — a transcript\nto read down, not a feed. The promoted `events` integer says how many the log\nholds in total; page the rest from a seq.","items":{"$ref":"#/components/schemas/agent.eventView"},"type":"array"},"repo":{"description":"Repo is the code the session is working on, as the surface reported it. It is\ntruth the SURFACE states, so it is a label rather than something resolved here.","type":"string"},"room":{"description":"Room is the collaborative room this run was started in (HIP-0523), empty\nwhen it came from anywhere else — a CLI, a schedule, an API call. It is what\nlets a space view show the runs of one room beside its messages.","type":"string"},"rootSessionId":{"description":"RootSessionID is the top of this session's tree, inherited from the parent and\nshared by every node in one flow. A root session's own id, when it has no\nparent. It is the key one indexed read pulls a whole flow by, and what ?root=\nnarrows a list or a stream to.","type":"string"},"sandbox":{"description":"Sandbox is the id of the sandbox the run works in (\"m_\" and 24 hex), the\nhandle its terminal and its screen are opened with\n(/v1/sandbox/{id}/terminal, /screen). Set when the run leases it, and kept\nonce the run gives it back, when the id opens nothing. Empty for a run that\nnever leased one — a routed run, or a turn that only talked.","type":"string"},"startedAt":{"description":"StartedAt is when the session opened, RFC 3339 in UTC to the second.","type":"string"},"status":{"description":"Status is one of exactly four: running, paused, done, error. running and\npaused are LIVE; done and error are TERMINAL and monotonic — once a session\nreaches one it can never go back, because reopening a finished run would\nfabricate liveness. A control command never moves it: the surface running the\nagent reports the new status, and until it does the command is only recorded.","type":"string"},"target":{"description":"Target is the registered run-target this session is dispatched to — a machine\nthe org claimed, resolved same-org when it was set, so it can never point at\nanother tenant's computer. Empty means the session names no machine.","type":"string"},"taskRunId":{"description":"TaskRunID is that workflow's particular run. A workflow is the definition and\na run is one execution of it, which is why both are carried.","type":"string"},"taskWorkflowId":{"description":"TaskWorkflowID is the hanzoai/tasks durable workflow that actually EXECUTES\nthis session — this registry is the view, control and stream layer over it.\nSet, a control command is FORWARDED to that engine; empty, the running surface\npolls for commands instead, which is every session today.","type":"string"},"terminal":{"description":"Terminal is where this session can be WATCHED — the URL the machine\npublished for its live terminal. Omitted when it publishes none.","type":"string"},"title":{"description":"Title is the human line a card shows (\"ship the landing page\"), up to 512\ncharacters. Free text, and the one field a surface may rewrite as the work\nturns out to be something else.","type":"string"},"updatedAt":{"description":"UpdatedAt is the session's last-activity clock, same format. It moves on a\nwrite to the row — a status, a title, a re-dispatch — AND on every appended\nturn, because the append bumps it in the same transaction. The list is ordered\non CreatedAt, so this is the field that says whether a session is still saying\nanything.","type":"string"}},"type":"object"},"agent.sessionList":{"properties":{"next":{"description":"Next is the cursor for the page after this one; empty on the last page.","type":"string"},"sessions":{"description":"Sessions is the matching sessions, each with its event and child counts and\na one-line preview of its latest event.","items":{"$ref":"#/components/schemas/agent.sessionView"},"type":"array"}},"type":"object"},"agent.sessionProgress":{"properties":{"activity":{"description":"Activity is the one line saying what the run is doing right now (\"running\nthe reaper's tests\"), up to 120 characters, in the model's words. Empty\nwhen nothing has estimated it yet.","type":"string"},"at":{"description":"At is when this was determined, RFC 3339 in UTC to the second. Read it as\nthe estimate's AGE: an estimate is not refreshed while nothing has\nhappened, and a stale one beside a run that is still moving is itself worth\nseeing. Empty when nothing has estimated it yet.","type":"string"},"estimated":{"description":"Estimated says a MODEL produced this, from the run's transcript, and it may\nbe wrong. False means the session's own row said it: a finished run is 100%\nbecause it finished, not because anything guessed. Never treat a true here\nas a measurement — it is the reason to look, not the answer.","type":"boolean"},"pct":{"description":"Pct is how much of the run is done, 0 to 100. THE KEY IS ABSENT when\nprogress is indeterminate — a run nobody can estimate is not a run that has\ndone nothing, and rendering the second for the first is the mistake this\nomission exists to make impossible. Read `phase` before reaching for it.","format":"int64","type":"integer"},"phase":{"description":"Phase is what shape the run is in: running, blocked, done, error, or\nunknown when nothing has estimated it yet. blocked means the transcript\nshows the run waiting on something — an approval, a credential, an answer —\nwhich is the one state the running surface cannot report about itself.\nerror only ever comes from the session's own terminal status.","type":"string"}},"type":"object"},"agent.sessionView":{"properties":{"account":{"description":"Account is which subscription or API account under that provider served it.\nTogether with Provider it is what a login revoke matches on to stop the\nsessions a withdrawn account was paying for.","type":"string"},"actor":{"description":"Actor is WHO this session belongs to, as \"org/sub\" — the same identity a run\nis billed under. A register that names none takes the calling principal. It is\nwhat scopes a login revoke, so a session with the wrong actor is a session the\nright person cannot stop.","type":"string"},"agent":{"description":"Agent is the label the surface running this session calls itself by\n(\"hanzo-dev\"), up to 128 characters. Required at register. It is free text,\nnot a reference: it need not name a defined agent, and nothing resolves it.","type":"string"},"base":{"description":"Base is the branch the run started from. Empty when it took the\nrepository's default and did not say which.","type":"string"},"branch":{"description":"Branch is the branch the run pushes its work to, and the only one it may\nwrite.","type":"string"},"children":{"description":"Children is the DIRECT fan-out — how many sessions name this one as parent —\nand not the size of the subtree. Read the tree for that.","format":"int64","type":"integer"},"createdAt":{"description":"CreatedAt is when the row was written, same format. Every path that opens a\nsession stamps it and StartedAt from one clock reading, so the two are equal\non every session this surface has ever produced.","type":"string"},"cwd":{"description":"Cwd is the directory the session is working in NOW, not the one it started in:\na linked shell moves around, and a card showing where `hanzo link` was run\nanswers \"which work is this\" with something that was true once.","type":"string"},"endedAt":{"description":"EndedAt is when it reached done or error, same format. Empty while it is still\nrunning or paused, which is how absence reads here: not over yet.","type":"string"},"environment":{"description":"Environment is where the run executes: \"sandbox\" for a Hanzo sandbox, or the\nid of the org's machine it was routed to (the same id Target carries).","type":"string"},"events":{"description":"Events is how many turns the session's log holds, counted at read time. It is\nthe whole log, however few of them RecentEvents carries.","format":"int64","type":"integer"},"host":{"description":"Execution context (mission-control): the machine/repo/cwd a card shows and\nthe run-target a session is dispatched to. Omitted when a surface didn't report it.","type":"string"},"id":{"description":"ID is the session's handle, minted here as \"sess_\" + 32 hex characters. Every\nlater read, patch, event append and control command is addressed with it, and\na caller cannot choose it.","type":"string"},"kind":{"description":"Kind is what sort of run this session is the view of — \"coding\" for a coding\nrun. Empty for a session no run tagged.","type":"string"},"lastEvent":{"$ref":"#/components/schemas/agent.lastEventView","description":"LastEvent is the compact latest-activity line for the list projection (nil in\nregister/patch/tree responses; set by list + detail). It lets a swipe card show\na live one-line preview without fetching full detail."},"mode":{"description":"Mode is what the run may do to its repository: \"build\" edits, commits and\npushes its branch; \"plan\" reads and answers with a plan, writing nothing.\nEmpty for a session no run tagged.","type":"string"},"org":{"description":"Org is the caller's OWN tenant, echoed so a client can build the public\nbuild URL (/builds/:org/:project) without a second call or a guess. It is\nnever another tenant's — every read is org-scoped before it gets here.","type":"string"},"parentSessionId":{"description":"ParentSessionID is the session that spawned this one, making this a subagent\nof it. Empty means this session is a root — a flow of its own. A parent always\nbelongs to the same org, so a tree never crosses a tenant.","type":"string"},"pr":{"description":"PR is the address of the pull request the run proposed. Empty until it\nproposes one, and for a run that changed nothing.","type":"string"},"progress":{"$ref":"#/components/schemas/agent.sessionProgress","description":"Progress is how far along this run is — a share of its goal, a phase, and a\nline saying what it is doing. Always present, so a board never branches on\nwhether it is there; `phase` says \"unknown\" when nothing has estimated it.\nIt is a MODEL ESTIMATE wherever `estimated` is true, and the row's own word\nwhere it is false. See progress.go."},"project":{"description":"The readable build: the product this session built and whether its story\nis public (provenance.go).","type":"string"},"provider":{"description":"Provider is the linked AI account's provider (claude | codex | hanzo | …) that\nserved this run. Empty when the surface did not say.","type":"string"},"published":{"description":"Published is the author's decision to let anyone read this session's story at\nthe public build route. It only ever widens READ access to a session that\nalready exists and grants nothing else; false, an unpublished session is\ninvisible there no matter who asks. It cannot be true without a Project,\nbecause that route is keyed on (org, project).","type":"boolean"},"repo":{"description":"Repo is the code the session is working on, as the surface reported it. It is\ntruth the SURFACE states, so it is a label rather than something resolved here.","type":"string"},"room":{"description":"Room is the collaborative room this run was started in (HIP-0523), empty\nwhen it came from anywhere else — a CLI, a schedule, an API call. It is what\nlets a space view show the runs of one room beside its messages.","type":"string"},"rootSessionId":{"description":"RootSessionID is the top of this session's tree, inherited from the parent and\nshared by every node in one flow. A root session's own id, when it has no\nparent. It is the key one indexed read pulls a whole flow by, and what ?root=\nnarrows a list or a stream to.","type":"string"},"sandbox":{"description":"Sandbox is the id of the sandbox the run works in (\"m_\" and 24 hex), the\nhandle its terminal and its screen are opened with\n(/v1/sandbox/{id}/terminal, /screen). Set when the run leases it, and kept\nonce the run gives it back, when the id opens nothing. Empty for a run that\nnever leased one — a routed run, or a turn that only talked.","type":"string"},"startedAt":{"description":"StartedAt is when the session opened, RFC 3339 in UTC to the second.","type":"string"},"status":{"description":"Status is one of exactly four: running, paused, done, error. running and\npaused are LIVE; done and error are TERMINAL and monotonic — once a session\nreaches one it can never go back, because reopening a finished run would\nfabricate liveness. A control command never moves it: the surface running the\nagent reports the new status, and until it does the command is only recorded.","type":"string"},"target":{"description":"Target is the registered run-target this session is dispatched to — a machine\nthe org claimed, resolved same-org when it was set, so it can never point at\nanother tenant's computer. Empty means the session names no machine.","type":"string"},"taskRunId":{"description":"TaskRunID is that workflow's particular run. A workflow is the definition and\na run is one execution of it, which is why both are carried.","type":"string"},"taskWorkflowId":{"description":"TaskWorkflowID is the hanzoai/tasks durable workflow that actually EXECUTES\nthis session — this registry is the view, control and stream layer over it.\nSet, a control command is FORWARDED to that engine; empty, the running surface\npolls for commands instead, which is every session today.","type":"string"},"terminal":{"description":"Terminal is where this session can be WATCHED — the URL the machine\npublished for its live terminal. Omitted when it publishes none.","type":"string"},"title":{"description":"Title is the human line a card shows (\"ship the landing page\"), up to 512\ncharacters. Free text, and the one field a surface may rewrite as the work\nturns out to be something else.","type":"string"},"updatedAt":{"description":"UpdatedAt is the session's last-activity clock, same format. It moves on a\nwrite to the row — a status, a title, a re-dispatch — AND on every appended\nturn, because the append bumps it in the same transaction. The list is ordered\non CreatedAt, so this is the field that says whether a session is still saying\nanything.","type":"string"}},"type":"object"},"agent.spendView":{"properties":{"by_component":{"additionalProperties":{"format":"int64","type":"integer"},"description":"ByComponent holds only the components with spend. Absent, not zero.","type":"object"},"cap_micro_usd":{"description":"CapMicroUSD is the total this agent may spend within one Period, as an\ninteger number of micro-USD (1,000,000 = $1). It is required at creation: a\ncap of zero would mean no limit and no per-agent spend record at all.","format":"int64","type":"integer"},"consumed_micro_usd":{"description":"ConsumedMicroUSD is what has been spent in the current period, in micro-USD.\nIt is settled from what the gateway reported, not from the quote.","format":"int64","type":"integer"},"max_task_micro_usd":{"description":"MaxTaskMicroUSD is the ceiling for a single run, in micro-USD. A session\ncannot exceed it even when the period cap still has room, so one runaway\ntask cannot consume a month.","format":"int64","type":"integer"},"period":{"description":"Period is the window the cap resets on: day, week or month.","type":"string"},"period_started_at":{"description":"PeriodStartedAt is when the current period began, as a Unix second.","format":"int64","type":"integer"},"ref":{"description":"Ref names the agent this spend belongs to.","type":"string"},"remaining_micro_usd":{"description":"RemainingMicroUSD is what the cap still allows this period, in micro-USD.","format":"int64","type":"integer"}},"type":"object"},"agent.targetDeleted":{"properties":{"deleted":{"description":"Deleted is true when the target was removed.","type":"boolean"},"id":{"description":"ID is the target that was removed.","type":"string"}},"type":"object"},"agent.targetList":{"properties":{"targets":{"description":"Targets is every target registered to the caller's org; in a held org, the\ncaller's own.","items":{"$ref":"#/components/schemas/agent.targetView"},"type":"array"}},"type":"object"},"agent.targetReq":{"properties":{"capacity":{"description":"Capacity is a human summary of the machine's size, up to 256 characters. Prose\nonly; a scheduler reads Spec.","type":"string"},"host":{"description":"Host is the hostname sessions on this machine will report. It is what makes a\nre-link IDEMPOTENT: the same (org, host, owner) refreshes the existing row and\nanswers 200, while a request with no host always creates a new target and\nanswers 201. It never adopts a row owned by somebody else.","type":"string"},"kind":{"description":"Kind is laptop | cloud | gpu | cluster | machine. Empty registers a `machine`;\nanything outside the five is a 400.","type":"string"},"label":{"description":"Label is the name to show for this machine, up to 128 characters. REQUIRED —\nit is the only field here a person reads.","type":"string"},"metrics":{"$ref":"#/components/schemas/agent.Metrics","description":"Metrics is a live sample, and sending one IS A HEARTBEAT: it refreshes the row\nand starts the 90-second liveness window, and it is appended to the fleet\nseries as one point. Its own `at` is ignored — the server stamps the time, so\na client can never age or backdate its own machine. Omit it to register a\nmachine without claiming it is alive."},"spec":{"$ref":"#/components/schemas/agent.Spec","description":"Spec is the machine's static capability — os, arch, cores, RAM, accelerators.\nEvery field is bounded on write and at most 32 accelerators are accepted, so\nwhat comes back may be clamped. Omit it for a destination nothing probes."},"status":{"description":"Status is online | offline | draining. Empty registers `online`. It states\nINTENT — a heartbeat is what decides whether an online machine is actually\nreachable, so declaring online does not make it so.","type":"string"}},"type":"object"},"agent.targetView":{"properties":{"capacity":{"description":"Capacity is a human summary of what the machine has (\"8 vCPU / 32G\", \"1× GB10\"),\nup to 256 characters. Prose for a card — Spec is the same thing in a form a\nscheduler can read, and nothing derives one from the other.","type":"string"},"createdAt":{"description":"CreatedAt is when the machine was first registered, RFC 3339 in UTC. A re-link\nrefreshes the row and leaves this alone, so it dates the machine and not the\nconnection.","type":"string"},"host":{"description":"Host is the hostname sessions on this machine report, and it is a JOIN KEY, not\na label: a session naming this host counts against the load below even when it\nnames no target id, and a re-link of the same (org, host, owner) refreshes this\nrow instead of creating a second. Empty means the machine is addressable only\nby ID.","type":"string"},"id":{"description":"ID is the machine's handle, minted as \"tgt_\" + 32 hex characters. It is what a\nsession records to say it ran here, and what every later patch, claim or\ndelete addresses.","type":"string"},"kind":{"description":"Kind is what sort of destination this is, from a closed five: laptop | cloud |\ngpu | cluster | machine. A register that named none is a `machine`.","type":"string"},"label":{"description":"Label is the name a person gave the machine (\"workshop\"), up to 128\ncharacters. Required at register, free text, and the only field here meant for\nreading rather than matching.","type":"string"},"metrics":{"$ref":"#/components/schemas/agent.Metrics","description":"Metrics is what the machine was DOING at its last heartbeat — loadavg, memory,\naccelerator utilization. Absent when it has never beaten. It is a SNAPSHOT:\nthe series over time lives in the fleet samples, not here."},"metricsAt":{"description":"MetricsAt is when that heartbeat was recorded, RFC 3339 in UTC, and the SERVER\nstamps it — a client cannot backdate or forge the staleness clock. Absent means\nnever beaten, which is exactly the case where Status is taken at its word.","type":"string"},"running":{"description":"Running is how many of those are in `running` right now — the number a\ndispatcher weighs against Capacity. paused sessions are in Sessions and not\nhere.","format":"int64","type":"integer"},"serving":{"description":"Serving says whether a run the caller sends here now would be taken: the\nmachine is the caller's (or the caller is an org admin), and it is online\nwith a runner that polled for work within the last 90 seconds — the online\nand runner half is what dispatch checks (TargetDispatchable). A heartbeat\nalone keeps a machine online, not serving, and a colleague's machine never\nserves the caller.","type":"boolean"},"sessions":{"description":"Sessions is how many of the org's sessions are mapped to this machine, by\ntarget id OR by matching Host. All of them, whatever their status.","format":"int64","type":"integer"},"spec":{"$ref":"#/components/schemas/agent.Spec","description":"Spec is what the machine IS — os, arch, cores, RAM, accelerators — the static\nhalf, changed only when something reports it again. Absent when nothing has\never been reported, and a scheduler reads absence as \"cannot satisfy a floor\"\nrather than as \"no limits\"."},"status":{"description":"Status is the EFFECTIVE liveness — online | offline | draining — not the\nstored one. offline and draining are operator INTENT and are reported as they\nstand; `online` is checked against the heartbeat, and a machine that has beaten\nbefore but not in the last 90 seconds reports offline whatever its row says. A\ntarget that has NEVER beaten keeps its stored status, because a hand-registered\ndestination has no fact to check.","type":"string"},"updatedAt":{"description":"UpdatedAt is the last write to the row, same format — which for a beating\nmachine is its last heartbeat, since a heartbeat IS a write.","type":"string"}},"type":"object"},"agent.treeNode":{"properties":{"children":{"description":"Children is this node's direct children, each a whole node, so the array nests\nto the depth of the flow. A leaf carries null rather than an empty array. The\nsubtree is materialised in full, up to 10000 nodes, out of one indexed read of\nthe root; nothing is walked node by node.","items":{"$ref":"#/components/schemas/agent.treeNode"},"type":"array"},"session":{"$ref":"#/components/schemas/agent.sessionView","description":"Session is this node's own session, carrying its event count and its direct\nfan-out. It is the same shape the list and detail reads answer with, minus the\nlast-event preview, which the tree does not fetch."}},"type":"object"},"agent.updateAgentIn":{"properties":{"avatar":{"description":"Avatar and Emoji re-draw the agent. Sending either replaces the pair, so\nsetting an image clears a glyph and \"\" for both goes back to the initial —\nthere is no state where a row holds two answers.","type":"string"},"cap_micro_usd":{"description":"The budget, any part of it. Changing the period opens a new window.","format":"int64","type":"integer"},"computeRef":{"description":"ComputeRef re-binds (or, with \"\", unbinds) the visor machine. Opaque here.","type":"string"},"description":{"description":"Description replaces the line other agents read in the tool catalogue.","type":"string"},"emoji":{"description":"Emoji re-draws the agent as a glyph. Sending either of the pair replaces\nBOTH, so setting a glyph clears an image and \"\" for both goes back to the\ninitial — there is no state where a row holds two answers.","type":"string"},"executionMode":{"description":"ExecutionMode switches between one-shot and long-running. The RESULTING\nmode+schedule are validated together, so switching to long-running without a\nstored or supplied cron is refused rather than accepted into an agent the\nscheduler would skip forever. A switch INTO long-running counts against the\nper-org cap and can be a 409.","type":"string"},"instructions":{"description":"Instructions replaces the system prompt whole, up to 32 KiB. There is no\nappend: a prompt is one text, and sending \"\" clears it.","type":"string"},"max_task_micro_usd":{"description":"MaxTaskMicroUSD is the ceiling for a single run, in micro-USD. A session\ncannot exceed it even when the period cap still has room, so one runaway\ntask cannot consume a month.","format":"int64","type":"integer"},"model":{"description":"Model re-points the agent at another model, checked against the gateway's\nserved catalogue exactly as create checks it. Empty STRING is refused — say\nnothing to keep the current one. Past runs keep the model that served them.","type":"string"},"period":{"description":"Period is the window the cap resets on: day, week or month.","type":"string"},"ref":{"description":"Ref is the agent to update — its public id or org-unique name, from the path.","type":"string"},"schedule":{"description":"Schedule replaces the cron. It is validated against the mode this update\nleaves behind, and dropped if that mode is one-shot.","type":"string"},"serviceAccountId":{"description":"ServiceAccountID re-points (or, with \"\", clears) the IAM service account a\nscheduled run is billed as. Clearing it puts that spend back on the org.","type":"string"},"tools":{"description":"Tools replaces the whole allow-list, it does not add to it. Sending [] takes\nevery tool away, which is the only way to say that.","items":{"type":"string"},"type":"array"}},"type":"object"},"ai.AiConnResponse":{"properties":{"account_label":{"type":"string"},"connected":{"type":"boolean"},"provider":{"type":"string"},"updated_at":{"type":"string"}},"type":"object"},"ai.AnthropicContentBlock":{"properties":{"text":{"type":"string"},"type":{"type":"string"}},"type":"object"},"ai.AnthropicMessage":{"properties":{"content":{},"role":{"type":"string"}},"type":"object"},"ai.AnthropicRequest":{"properties":{"max_tokens":{"type":"integer"},"messages":{"items":{"$ref":"#/components/schemas/ai.AnthropicMessage"},"type":"array"},"model":{"type":"string"},"stream":{"type":"boolean"},"system":{},"temperature":{"type":"number"},"thinking":{},"tool_choice":{},"tools":{"items":{"$ref":"#/components/schemas/ai.AnthropicTool"},"type":"array"}},"type":"object"},"ai.AnthropicResponse":{"properties":{"content":{"items":{"$ref":"#/components/schemas/ai.AnthropicContentBlock"},"type":"array"},"id":{"type":"string"},"model":{"type":"string"},"role":{"type":"string"},"stop_reason":{"type":"string"},"type":{"type":"string"},"usage":{"$ref":"#/components/schemas/ai.AnthropicUsage"}},"type":"object"},"ai.AnthropicTool":{"properties":{"description":{"type":"string"},"input_schema":{},"name":{"type":"string"}},"type":"object"},"ai.AnthropicUsage":{"properties":{"cache_creation":{"$ref":"#/components/schemas/ai.CacheWrites"},"cache_creation_input_tokens":{"type":"integer"},"cache_read_input_tokens":{"type":"integer"},"input_tokens":{"type":"integer"},"iterations":{"items":{"$ref":"#/components/schemas/ai.AnthropicUsage"},"type":"array"},"output_tokens":{"type":"integer"}},"type":"object"},"ai.CacheWrites":{"properties":{"ephemeral_1h_input_tokens":{"type":"integer"},"ephemeral_5m_input_tokens":{"type":"integer"}},"type":"object"},"ai.CostStats":{"properties":{"baseline_model":{"type":"string"},"counterfactual_index":{"type":"number"},"cumulative_saved_index":{"type":"number"},"priced_events":{"type":"integer"},"routed_index":{"type":"number"},"saved_pct":{"type":"number"}},"type":"object"},"ai.DecisionSides":{"properties":{"false":{"description":"A string, an object or an array, kept as written."},"true":{"description":"A string, an object or an array, kept as written."}},"type":"object"},"ai.DecisionsAction":{"properties":{"act_probability":{"type":"number"}},"type":"object"},"ai.DecisionsAnswer":{"properties":{"action":{"$ref":"#/components/schemas/ai.DecisionsAction"},"answer_confidence":{"type":"number"},"choice":{"type":"string"},"confidence":{"type":"number"},"legend":{"additionalProperties":{"description":"A string, an object or an array, kept as written."},"type":"object"},"noul":{"type":"number"},"probabilities":{"additionalProperties":{"type":"number"},"type":"object"},"probability":{"type":"number"},"score":{"type":"number"},"type":{"enum":["boolean","noul","choice","score"],"type":"string"}},"required":["type"],"type":"object"},"ai.DecisionsBoolean":{"properties":{"criteria":{"$ref":"#/components/schemas/ai.DecisionSides"},"instructions":{"description":"A string, an object or an array, kept as written."},"labels":{"additionalProperties":{"type":"string"},"type":"object"},"type":{"enum":["boolean"],"type":"string"}},"required":["type"],"type":"object"},"ai.DecisionsChoice":{"properties":{"criteria":{"description":"At least two labels: an object mapping each label to what it means (a string, an object, an array, or null), or an array of labels that need no description."},"instructions":{"description":"A string, an object or an array, kept as written."},"type":{"enum":["choice"],"type":"string"}},"required":["type","criteria"],"type":"object"},"ai.DecisionsNoul":{"properties":{"criteria":{"$ref":"#/components/schemas/ai.DecisionSides"},"instructions":{"description":"A string, an object or an array, kept as written."},"labels":{"additionalProperties":{"type":"string"},"type":"object"},"type":{"enum":["noul"],"type":"string"}},"required":["type"],"type":"object"},"ai.DecisionsQuestion":{"discriminator":{"mapping":{"boolean":"#/components/schemas/ai.DecisionsBoolean","choice":"#/components/schemas/ai.DecisionsChoice","noul":"#/components/schemas/ai.DecisionsNoul","score":"#/components/schemas/ai.DecisionsScore"},"propertyName":"type"},"oneOf":[{"$ref":"#/components/schemas/ai.DecisionsBoolean"},{"$ref":"#/components/schemas/ai.DecisionsNoul"},{"$ref":"#/components/schemas/ai.DecisionsChoice"},{"$ref":"#/components/schemas/ai.DecisionsScore"}]},"ai.DecisionsReason":{"properties":{"code":{"anyOf":[{"type":"integer"},{"type":"string"}]},"message":{"type":"string"}},"required":["code","message"],"type":"object"},"ai.DecisionsRefused":{"properties":{"error":{"$ref":"#/components/schemas/ai.DecisionsReason"}},"required":["error"],"type":"object"},"ai.DecisionsRequest":{"properties":{"handle":{"type":"string"},"model":{"type":"string"},"observe":{"type":"string"},"provider":{},"questions":{"additionalProperties":{"$ref":"#/components/schemas/ai.DecisionsQuestion"},"maxProperties":100,"minProperties":1,"type":"object"},"session_id":{"type":"string"},"state":{"description":"A string, an object or an array, kept as written."},"trace":{},"user":{"type":"string"}},"required":["model"],"type":"object"},"ai.DecisionsResponse":{"properties":{"answers":{"additionalProperties":{"$ref":"#/components/schemas/ai.DecisionsAnswer"},"type":"object"},"id":{"type":"string"},"latency_ms":{"type":"number"},"model":{"type":"string"},"provider":{"type":"string"},"routing":{"$ref":"#/components/schemas/ai.DecisionsRouting"},"state_hash":{"type":"string"},"usage":{"$ref":"#/components/schemas/ai.DecisionsUsage"}},"required":["id","model","provider","answers","usage","routing","state_hash","latency_ms"],"type":"object"},"ai.DecisionsRouting":{"properties":{"backend":{"type":"string"},"calibration":{"type":"string"},"checkpoint":{"type":"string"},"device":{"type":"string"},"reason":{"type":"string"},"revision":{"type":"string"},"sha256":{"type":"string"},"upstream":{"type":"string"}},"type":"object"},"ai.DecisionsScore":{"properties":{"criteria":{"items":{"description":"A string, an object or an array, kept as written."},"minItems":1,"type":"array"},"instructions":{"description":"A string, an object or an array, kept as written."},"type":{"enum":["score"],"type":"string"}},"required":["type","criteria"],"type":"object"},"ai.DecisionsUsage":{"properties":{"cost":{"type":"number"},"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"}},"required":["input_tokens","output_tokens"],"type":"object"},"ai.HistoryDay":{"properties":{"by_task":{"additionalProperties":{"type":"integer"},"type":"object"},"cost_saved_index":{"type":"number"},"cumulative_cost_saved":{"type":"number"},"date":{"type":"string"},"events":{"type":"integer"},"learned_share":{"type":"number"},"reward_rate":{"type":"number"},"rewarded_events":{"type":"integer"}},"type":"object"},"ai.HistoryRetrain":{"properties":{"date":{"type":"string"},"events":{"type":"integer"},"gate_base":{"type":"number"},"gate_metric":{"type":"string"},"gate_pass":{"type":"boolean"},"gate_value":{"type":"number"},"holdout_accuracy":{"type":"number"},"published":{"type":"boolean"},"trained_time":{"type":"string"},"version":{"type":"string"}},"type":"object"},"ai.HistoryTotals":{"properties":{"cumulative_cost_saved":{"type":"number"},"days_active":{"type":"integer"},"events":{"type":"integer"},"reward_rate":{"type":"number"}},"type":"object"},"ai.HistoryWindow":{"properties":{"days":{"type":"integer"},"since":{"type":"string"},"until":{"type":"string"}},"type":"object"},"ai.JudgeBenchmark":{"properties":{"mfjp":{"type":"number"},"naiveMean":{"type":"number"},"singleAdversary":{"type":"number"},"singleNoisy":{"type":"number"}},"type":"object"},"ai.JudgePanelState":{"properties":{"available":{"type":"boolean"},"benchmark":{"$ref":"#/components/schemas/ai.JudgeBenchmark"},"enabled":{"type":"boolean"},"judges":{"items":{"$ref":"#/components/schemas/ai.PanelJudge"},"type":"array"},"models":{"items":{"type":"string"},"type":"array"},"sampleRate":{"type":"number"}},"type":"object"},"ai.ModelAccessInfo":{"properties":{"state":{"type":"string"}},"type":"object"},"ai.ModelInfo":{"properties":{"access":{"$ref":"#/components/schemas/ai.ModelAccessInfo"},"canonical_slug":{"type":"string"},"class":{"type":"string"},"context_window":{"type":"integer"},"created":{"type":"integer"},"description":{"type":"string"},"expires":{"type":"string"},"family":{"type":"string"},"free":{"type":"boolean"},"id":{"type":"string"},"inputs":{"items":{"type":"string"},"type":"array"},"max_output_tokens":{"type":"integer"},"name":{"type":"string"},"object":{"type":"string"},"outputs":{"items":{"type":"string"},"type":"array"},"owned_by":{"type":"string"},"premium":{"type":"boolean"},"pricing":{"$ref":"#/components/schemas/ai.ModelPricingInfo"},"provider":{"type":"string"},"supports_reasoning":{"type":"boolean"},"supports_tools":{"type":"boolean"},"supports_vision":{"type":"boolean"},"video":{"$ref":"#/components/schemas/ai.VideoSpec"},"voice":{"$ref":"#/components/schemas/ai.VoiceSpec"}},"type":"object"},"ai.ModelList":{"properties":{"data":{"items":{"$ref":"#/components/schemas/ai.ModelInfo"},"type":"array"},"models":{"items":{"$ref":"#/components/schemas/ai.ModelInfo"},"type":"array"},"object":{"type":"string"}},"type":"object"},"ai.ModelPricingInfo":{"properties":{"completion":{"type":"string"},"input_per_million":{"type":"number"},"output_per_million":{"type":"number"},"overrides":{"items":{"additionalProperties":{},"type":"object"},"type":"array"},"prompt":{"type":"string"},"rates":{"additionalProperties":{"type":"string"},"type":"object"},"variable":{"type":"boolean"}},"type":"object"},"ai.ModelProviders":{"properties":{"providers":{"items":{"type":"string"},"type":"array"}},"type":"object"},"ai.PanelJudge":{"properties":{"mean":{"type":"number"},"model":{"type":"string"},"n":{"type":"integer"},"weight":{"type":"number"}},"type":"object"},"ai.ProviderUsage":{"properties":{"available":{"type":"boolean"},"byModel":{"items":{"$ref":"#/components/schemas/ai.ProviderUsageModelSpend"},"type":"array"},"connected":{"type":"boolean"},"currency":{"type":"string"},"end":{"type":"string"},"interval":{"type":"string"},"note":{"type":"string"},"provider":{"type":"string"},"series":{"items":{"$ref":"#/components/schemas/ai.ProviderUsageSeriesPoint"},"type":"array"},"start":{"type":"string"},"totals":{"$ref":"#/components/schemas/ai.ProviderUsageTotals"}},"type":"object"},"ai.ProviderUsageModelSpend":{"properties":{"model":{"type":"string"},"requests":{"type":"integer"},"spendCents":{"type":"integer"},"tokens":{"type":"integer"}},"type":"object"},"ai.ProviderUsageSeriesPoint":{"properties":{"requests":{"type":"integer"},"spendCents":{"type":"integer"},"t":{"type":"string"},"tokens":{"type":"integer"}},"type":"object"},"ai.ProviderUsageTotals":{"properties":{"inputTokens":{"type":"integer"},"outputTokens":{"type":"integer"},"requests":{"type":"integer"},"spendCents":{"type":"integer"},"tokens":{"type":"integer"}},"type":"object"},"ai.QualityStats":{"properties":{"avg_confidence":{"type":"number"},"learned_share":{"type":"number"},"reward_rate":{"type":"number"},"rewarded_events":{"type":"integer"},"shadow_agreement":{"type":"number"}},"type":"object"},"ai.RankUsage":{"properties":{"total_tokens":{"type":"integer"}},"type":"object"},"ai.RankedDoc":{"properties":{"document":{"$ref":"#/components/schemas/ai.RankedText"},"index":{"type":"integer"},"relevance_score":{"type":"number"}},"type":"object"},"ai.RankedText":{"properties":{"text":{"type":"string"}},"type":"object"},"ai.Ranking":{"properties":{"model":{"type":"string"},"object":{"type":"string"},"results":{"items":{"$ref":"#/components/schemas/ai.RankedDoc"},"type":"array"},"usage":{"$ref":"#/components/schemas/ai.RankUsage"}},"type":"object"},"ai.Response":{"properties":{"code":{"type":"string"},"data":{},"data2":{},"msg":{"type":"string"},"status":{"type":"string"}},"type":"object"},"ai.ResponsesInputDetails":{"properties":{"cache_write_tokens":{"type":"integer"},"cached_tokens":{"type":"integer"}},"type":"object"},"ai.ResponsesOutputDetails":{"properties":{"reasoning_tokens":{"type":"integer"}},"type":"object"},"ai.ResponsesResource":{"properties":{"created_at":{"type":"integer"},"error":{},"id":{"type":"string"},"incomplete_details":{},"instructions":{"type":"string"},"max_output_tokens":{"type":"integer"},"metadata":{"additionalProperties":{"type":"string"},"type":"object"},"model":{"type":"string"},"object":{"type":"string"},"output":{"items":{},"type":"array"},"parallel_tool_calls":{"type":"boolean"},"previous_response_id":{},"reasoning":{},"status":{"type":"string"},"store":{"type":"boolean"},"temperature":{"type":"number"},"text":{},"tool_choice":{},"tools":{"items":{"$ref":"#/components/schemas/ai.ResponsesTool"},"type":"array"},"top_p":{"type":"number"},"usage":{"$ref":"#/components/schemas/ai.ResponsesUsage"}},"type":"object"},"ai.ResponsesTool":{"properties":{"description":{"type":"string"},"format":{},"name":{"type":"string"},"parameters":{},"strict":{"type":"boolean"},"tools":{"items":{"$ref":"#/components/schemas/ai.ResponsesTool"},"type":"array"},"type":{"type":"string"}},"type":"object"},"ai.ResponsesUsage":{"properties":{"input_tokens":{"type":"integer"},"input_tokens_details":{"$ref":"#/components/schemas/ai.ResponsesInputDetails"},"output_tokens":{"type":"integer"},"output_tokens_details":{"$ref":"#/components/schemas/ai.ResponsesOutputDetails"},"total_tokens":{"type":"integer"}},"type":"object"},"ai.RetrainMeta":{"properties":{"events":{"type":"integer"},"gate_base":{"type":"number"},"gate_kind":{"type":"string"},"gate_metric":{"type":"string"},"gate_passed":{"type":"boolean"},"gate_value":{"type":"number"},"note":{"type":"string"},"published":{"type":"boolean"},"trained_time":{"type":"string"},"version":{"type":"string"}},"type":"object"},"ai.RouterHistory":{"properties":{"daily":{"items":{"$ref":"#/components/schemas/ai.HistoryDay"},"type":"array"},"retrains":{"items":{"$ref":"#/components/schemas/ai.HistoryRetrain"},"type":"array"},"scope":{"type":"string"},"totals":{"$ref":"#/components/schemas/ai.HistoryTotals"},"window":{"$ref":"#/components/schemas/ai.HistoryWindow"}},"type":"object"},"ai.RouterStats":{"properties":{"by_model":{"additionalProperties":{"type":"integer"},"type":"object"},"by_source":{"additionalProperties":{"type":"integer"},"type":"object"},"by_task":{"additionalProperties":{"$ref":"#/components/schemas/ai.TaskStats"},"type":"object"},"cost":{"$ref":"#/components/schemas/ai.CostStats"},"org":{"type":"string"},"quality":{"$ref":"#/components/schemas/ai.QualityStats"},"retrain":{"$ref":"#/components/schemas/ai.RetrainMeta"},"scope":{"type":"string"},"throughput":{"$ref":"#/components/schemas/ai.ThroughputStats"},"window":{"$ref":"#/components/schemas/ai.StatsWindow"}},"type":"object"},"ai.RoutingEdit":{"properties":{"base":{"type":"integer"},"catalog":{},"family":{"type":"string"},"model":{"type":"string"},"note":{"type":"string"},"version":{"type":"integer"}},"type":"object"},"ai.RoutingProbe":{"properties":{"arm":{"type":"string"},"failover":{"type":"string"},"ms":{"type":"integer"},"reply":{"type":"string"},"sku":{"type":"string"},"status":{"type":"integer"}},"type":"object"},"ai.RoutingProposal":{"properties":{"base":{"type":"integer"},"diff":{"type":"string"},"family":{"type":"string"},"refused":{"type":"string"}},"type":"object"},"ai.RoutingRewardRequest":{"properties":{"rating":{"type":"number"},"request_id":{"type":"string"},"reward":{"type":"number"},"signal":{"enum":["up","accept","regenerate","down","switch","abandon","revert","rating","dismiss"],"type":"string"}},"required":["request_id"],"type":"object"},"ai.RoutingRewardResult":{"properties":{"recorded":{"type":"boolean"},"request_id":{"type":"string"},"reward":{"type":"number"}},"type":"object"},"ai.RoutingView":{"properties":{"catalog":{},"drift":{"type":"boolean"},"error":{"type":"string"},"family":{"type":"string"},"redeployed":{"type":"boolean"},"stats":{},"version":{"$ref":"#/components/schemas/RoutingVersion"},"versions":{"items":{"$ref":"#/components/schemas/RoutingVersion"},"type":"array"}},"type":"object"},"ai.StatsWindow":{"properties":{"events":{"type":"integer"},"since":{"type":"string"},"until":{"type":"string"}},"type":"object"},"ai.TaskStats":{"properties":{"events":{"type":"integer"},"models":{"additionalProperties":{"type":"integer"},"type":"object"}},"type":"object"},"ai.ThroughputStats":{"properties":{"per_hour":{"items":{"type":"integer"},"type":"array"},"total_window":{"type":"integer"}},"type":"object"},"ai.TokenCount":{"properties":{"input_tokens":{"type":"integer"}},"type":"object"},"ai.VideoFailure":{"properties":{"message":{"type":"string"}},"type":"object"},"ai.VideoSpec":{"properties":{"aspect_ratios":{"items":{"type":"string"},"type":"array"},"audio":{"type":"boolean"},"durations":{"items":{"type":"integer"},"type":"array"},"frame_images":{"items":{"type":"string"},"type":"array"},"resolutions":{"items":{"type":"string"},"type":"array"},"sizes":{"items":{"type":"string"},"type":"array"}},"type":"object"},"ai.VideoStatus":{"properties":{"created_at":{"type":"integer"},"error":{"$ref":"#/components/schemas/ai.VideoFailure"},"id":{"type":"string"},"model":{"type":"string"},"object":{"type":"string"},"progress":{"type":"integer"},"status":{"type":"string"}},"type":"object"},"ai.VoiceSpec":{"properties":{"voices":{"items":{"type":"string"},"type":"array"}},"type":"object"},"aiAction":{"properties":{"kind":{"type":"string"},"label":{"type":"string"},"plan":{"type":"string"},"url":{"type":"string"}},"type":"object"},"aiChat":{"properties":{"answer":{"description":"Answer is the model's reply.","type":"string"},"model":{"description":"Model is the model asked: the caller's, or the default when it named none.","type":"string"},"receipt":{"$ref":"#/components/schemas/aiReceipt","description":"Receipt says which model served the reply and who paid for it."}},"type":"object"},"aiChatIn":{"properties":{"max_tokens":{"description":"MaxTokens bounds the answer in tokens; 0 leaves it to the model.","format":"int64","type":"integer"},"model":{"description":"Model is the model to answer, by id (zen5, enso, kai, anthropic/claude-sonnet-4.5\n— aiModels lists them). Empty asks the deployment's default Hanzo model.","type":"string"},"prompt":{"description":"Prompt is what to ask.","type":"string"},"system":{"description":"System is the system message ahead of the prompt, when set.","type":"string"}},"type":"object"},"aiClass":{"properties":{"paying":{"description":"Paying is plan, prepaid, credits, or none.","type":"string"},"percent":{"format":"int64","type":"integer"},"resets_at":{"type":"string"},"state":{"description":"State is ok, near, or limited when the class is used up and nothing else pays.","type":"string"},"window":{"$ref":"#/components/schemas/aiWindow"}},"type":"object"},"aiDecideIn":{"properties":{"handle":{"description":"Handle decides over a state this org observed earlier, in place of State and\nQuestions.","type":"string"},"model":{"description":"Model is kai, Kai's versioned id kai-\u003c12 hex\u003e, or Jev by its vendor id\n(typesafe/jev-1.13, ~typesafe/jev-latest).","type":"string"},"observe":{"description":"Observe holds the state under this id (1 to 128 of A-Z a-z 0-9 . _ -), so a\nlater decision can name it as its Handle.","type":"string"},"questions":{"additionalProperties":{},"description":"Questions are 1 to 100 named questions, each {\"type\": \"choice\"|\"noul\"|\"score\",\n\"instructions\"?, \"criteria\"?}; a choice names at least 2 labels and a score at\nleast 1 level. Not sent with a Handle.","type":"object"},"state":{"description":"State is what the questions are about: a string, an object or an array, kept\nas written. Not sent with a Handle."}},"type":"object"},"aiDecision":{"properties":{"decision":{"description":"Decision is POST /v1/decisions' own answer: id, model, provider, answers,\nusage (the billed input tokens), routing, state_hash and latency_ms."},"receipt":{"$ref":"#/components/schemas/aiReceipt","description":"Receipt says which model served the decision and who paid for it."}},"type":"object"},"aiLimited":{"properties":{"classes":{"items":{"type":"string"},"type":"array"},"message":{"type":"string"},"reason":{"description":"Reason is plan_allowance_used.","type":"string"}},"type":"object"},"aiLimits":{"properties":{"actions":{"description":"Actions are the ways on: upgrade, add prepaid credit.","items":{"$ref":"#/components/schemas/aiAction"},"type":"array"},"classes":{"additionalProperties":{"$ref":"#/components/schemas/aiClass"},"description":"Classes are premium (third-party frontier models) and ours (Hanzo's), each\npresent when the plan includes it.","type":"object"},"credits_after_allowance":{"description":"CreditsAfterAllowance is the payer's choice to keep using a model on credits\nonce the plan's included usage of it is spent (PUT /v1/ai/limits sets it).","type":"boolean"},"day":{"$ref":"#/components/schemas/aiWindow"},"limited":{"$ref":"#/components/schemas/aiLimited","description":"Limited is present in limited mode."},"paused":{"description":"Paused are the models whose share of the plan is used for now: each is\nanswered by its fallback in chat until its share resets.","items":{"$ref":"#/components/schemas/aiPaused"},"type":"array"},"period_end":{"type":"string"},"period_start":{"description":"PeriodStart and PeriodEnd bound the month the plan's usage renews over\n(RFC3339): the billing period, or one month of a yearly one.","type":"string"},"plan":{"description":"Plan is the plan the caller is served as (\"dev\", \"max-5x\", \"max-20x\", \"team\",\n\"agency\", \"advisory\", \"dedicated\", ...), \"free\" when none counts.","type":"string"},"session":{"$ref":"#/components/schemas/aiWindow","description":"Session and Day are the request windows over every request the plan covers."},"state":{"description":"State is the worst class's: ok, near or limited.","type":"string"},"upgrade":{"description":"Upgrade is the plan that raises these limits, absent at the top.","type":"string"}},"type":"object"},"aiLimitsSet":{"properties":{"creditsAfterAllowance":{"description":"CreditsAfterAllowance keeps a model working once the plan's included usage of\nit is spent, paid from prepaid credit (and granted credit where the model takes\nit), when true; when false the conversation moves to a Hanzo model and other\ncalls are refused until the plan resets. Off until the payer turns it on.","type":"boolean"}},"type":"object"},"aiMCPApp":{"properties":{"name":{"description":"Name is the subsystem, as the manifest names it.","type":"string"},"served":{"description":"Served reports that THIS process mounted it, so its tools are on this\nprocess's MCP server rather than behind a sibling this process only knows the\nname of.","type":"boolean"}},"type":"object"},"aiMCPSurface":{"properties":{"apps":{"description":"Apps is one row per subsystem this deployment composes, in manifest order.","items":{"$ref":"#/components/schemas/aiMCPApp"},"type":"array"},"names":{"description":"Names are this process's own tool names, present only when the query asked\nfor them.","items":{"type":"string"},"type":"array"},"tools":{"description":"Tools is how many tools THIS PROCESS's MCP server carries: its own typed-op\nregistry, projected. It is the only number a subsystem can state honestly —\nwhat the FLEET's server carries is a question only the host can ask, and it\nasks it by asking every subsystem (POST /v1/mcp, tools/list).","format":"int64","type":"integer"}},"type":"object"},"aiModel":{"properties":{"capabilities":{"description":"Capabilities are tools, vision and reasoning, those the model supports.","items":{"type":"string"},"type":"array"},"class":{"description":"Class is premium, ours or free.","type":"string"},"context_window":{"description":"ContextWindow is the most tokens the model reads at once, absent when the\ncatalog does not say.","format":"int64","type":"integer"},"expires":{"description":"Expires is the day the model's vendor stops serving it (2006-01-02), absent\nwhen it states none.","type":"string"},"family":{"description":"Family is the Hanzo family (enso, zen, kai, zoo), absent for a third-party\nmodel.","type":"string"},"free":{"description":"Free is whether a call bills nothing.","type":"boolean"},"id":{"description":"ID is the model's id, the one a completion or a decision names.","type":"string"},"inputs":{"description":"Inputs are the modalities the model reads.","items":{"type":"string"},"type":"array"},"max_output_tokens":{"description":"MaxOutputTokens is the most one answer may hold, absent when the catalog does\nnot say.","format":"int64","type":"integer"},"name":{"description":"Name is the model's display name.","type":"string"},"outputs":{"description":"Outputs are the modalities the model writes.","items":{"type":"string"},"type":"array"},"pricing":{"$ref":"#/components/schemas/aiPrice","description":"Pricing is the model's list price."}},"type":"object"},"aiModels":{"properties":{"models":{"description":"Models are the matches, in the catalog's order.","items":{"$ref":"#/components/schemas/aiModel"},"type":"array"},"total":{"description":"Total is how many models matched, before Limit.","format":"int64","type":"integer"}},"type":"object"},"aiPaused":{"properties":{"fallback":{"description":"Fallback is the Hanzo model that answers a conversation in its place.","type":"string"},"model":{"description":"Model is the model id, or a pattern ending in `*` naming a family of them.","type":"string"},"resets_at":{"description":"ResetsAt is when its share resets (RFC3339).","type":"string"}},"type":"object"},"aiPrice":{"properties":{"completion":{"description":"Completion is the price of one output token, a decimal string.","type":"string"},"input_per_million":{"description":"InputPerMillion is the price of a million input tokens.","format":"double","type":"number"},"output_per_million":{"description":"OutputPerMillion is the price of a million output tokens.","format":"double","type":"number"},"overrides":{"description":"Overrides are the vendor's conditional rates as billed, each with its\ncondition: min_prompt_tokens, or utc_start, utc_end and utc_days.","items":{"additionalProperties":{},"type":"object"},"type":"array"},"prompt":{"description":"Prompt is the price of one input token, a decimal string.","type":"string"},"rates":{"additionalProperties":{"type":"string"},"description":"Rates is every rate a resold model's vendor states, in the vendor's names\nand units (USD per token for prompt, completion, input_cache_read,\ninput_cache_write, internal_reasoning; per request; per search for\nweb_search), as billed: the vendor's rate times our margin, exact.","type":"object"},"variable":{"description":"Variable is true for a router that bills each answer at the price of the\nmodel that gave it; the figures above are then that router's ceiling.","type":"boolean"}},"type":"object"},"aiReceipt":{"properties":{"class":{"description":"Class is the model's class as billed: premium, ours or free\n(X-Hanzo-Usage-Class).","type":"string"},"fallback":{"description":"Fallback is the model that answered in place of the one asked, in limited\nmode (X-Hanzo-Fallback).","type":"string"},"paid_by":{"description":"PaidBy is plan, credits or free (X-Hanzo-Paid-By); absent when the answer\nnamed no payer, as a free model's does.","type":"string"},"reason":{"description":"Reason is the refusal code that sent the request to the fallback\n(X-Hanzo-Usage-Reason).","type":"string"},"routed":{"description":"Routed is the model `auto` resolved to (X-Routed-Model).","type":"string"},"served":{"description":"Served is the model that answered (X-Hanzo-Served).","type":"string"},"usage":{"description":"Usage is where that class stands for the payer: ok, near or limited\n(X-Hanzo-Usage).","type":"string"}},"type":"object"},"aiWindow":{"properties":{"percent":{"description":"Percent is the share used, 0 to 100, rounded up to the next five so any use\nshows.","format":"int64","type":"integer"},"resets_at":{"description":"ResetsAt is when the window starts again (RFC3339), null for a session that is\nnot running: it starts at the next request.","type":"string"},"state":{"description":"State is ok, near (four fifths used) or limited (used up).","type":"string"}},"type":"object"},"allowance.Allowance":{"properties":{"limit":{"description":"calls the plan allows per period; 0 = unbounded","format":"int64","type":"integer"},"plan":{"description":"the tier the limit came from","type":"string"},"pool":{"$ref":"#/components/schemas/allowance.Pool","description":"Pool is that shared pool's standing, where it could be read. Absent when the\nsubject is not pooled, and when the process that holds it did not answer —\nnever a guess."},"pooled":{"description":"Pooled says the calls counted here are served from the pool every free user\nshares — the platform's vendor accounts for free models — rather than from\nthe subject's own plan. True exactly where a window bounds the subject.","type":"boolean"},"resets":{"description":"unix seconds; when THAT window starts again","format":"int64","type":"integer"},"spent":{"description":"Spent says the ceiling refuses: on a take, that THIS call was refused and\nnothing was counted; on a read, that the next call would be.","type":"boolean"},"used":{"description":"Used is how many free calls this subject has been admitted in the period\nending at Resets — the UTC calendar day. A call counts when it is admitted,\nwhatever its upstream then does; a refused call counts nothing. It stops AT\nLimit rather than climbing past it, so Limit-Used is what remains and never\ngoes negative.","format":"int64","type":"integer"},"window":{"description":"Window is which ceiling these numbers describe — \"hour\" or \"day\" — because a\ncaller is held to both and only one of them is the answer. It is the window\nthat REFUSED where one did, and otherwise the one with least left, so\nLimit-Used is always the number that will actually stop them next. Empty\nwhere no window bounds the subject at all.","type":"string"}},"type":"object"},"allowance.Pool":{"properties":{"resets":{"description":"Resets is when the pool refills, unix seconds: set when it is exhausted,\nand when it is busy for less than a minute. Absent otherwise.","format":"int64","type":"integer"},"state":{"description":"State is \"available\" (every account takes free requests), \"busy\" (some\naccount is at its vendor limit, or all are and one is back within a minute)\nor \"exhausted\" (none is until Resets).","type":"string"}},"type":"object"},"ask.Report":{"properties":{"answer":{"description":"Answer is the grounded prose, with inline markdown citations. Every link in\nit points at a page in Sources: the citation check runs on the text before\nit leaves the engine, so a cited URL is one THIS call fetched.","type":"string"},"follow_ups":{"description":"FollowUps are the questions worth asking next. Best-effort — an empty list\nis a normal outcome, not a fault.","items":{"type":"string"},"type":"array"},"mode":{"description":"Mode is the profile that ran: search, news, research or deep.","type":"string"},"model":{"description":"Model is the model that synthesized the answer.","type":"string"},"sources":{"description":"Sources are the pages the answer was written from, deduplicated and ranked.\nAlways an array, never null.","items":{"$ref":"#/components/schemas/ask.Source"},"type":"array"}},"type":"object"},"ask.Source":{"properties":{"engine":{"description":"Engine is the search backend the hit came from: bing, ddg, mojeek or brave.\nOmitted when the backend did not name itself. Results are merged across\nbackends, so two sources in one answer can carry different engines.","type":"string"},"favicon":{"description":"Favicon is a 64px icon URL derived from the host for the client to render\nbeside the citation. It is Google's s2 service, not something we host or\nfetched — an empty host yields the empty string.","type":"string"},"snippet":{"description":"Snippet is the engine's summary of the page, clipped to 600 runes. THIS IS\nWHAT THE CLIENT SHOWS. What the model reads is the fetched page, which is\nfar larger and deliberately never on the wire.","type":"string"},"title":{"description":"Title is the page title the engine reported, stripped of the bracketed\nfurniture engines staple on (\"[PDF]\", \"(Official Site)\"). It falls back to\nthe www-stripped host when the engine gave none, so it is never empty and\nis safe to use as link text.","type":"string"},"url":{"description":"URL is the page, absolute, exactly as the engine gave it. It is also the\ndedupe key — one source per URL, and at most hostCap per host — and what a\nmarkdown citation in the answer is checked against, so a link in the prose\nalways matches a URL here.","type":"string"}},"type":"object"},"ask.webQuestion":{"properties":{"language":{"description":"Language narrows the search to a locale, BCP-47-ish (\"en\", \"ja\"). Empty\nmeans no narrowing.","type":"string"},"max_sources":{"description":"MaxSources caps how many pages are read. Empty means the mode's own budget.","format":"int64","type":"integer"},"mode":{"description":"Mode is how much work to do: `search` (fast, one pass), `news` (recency\nbiased), `research` (a plan and several rounds) or `deep` (the widest\nsurvey). Empty means research.","type":"string"},"q":{"description":"Q is the question, in plain language. Required.","type":"string"},"sources":{"description":"Sources narrows where the evidence comes from: any of `web`, `news`,\n`academic`, `github`, `reddit`, `x`. Each becomes a site-scoped search, so\n`[\"x\"]` researches X/Twitter posts rather than the open web.","items":{"type":"string"},"type":"array"}},"type":"object"},"askRequest":{"properties":{"followUps":{"type":"boolean"},"language":{"type":"string"},"maxQueries":{"type":"integer"},"maxSources":{"type":"integer"},"mode":{"type":"string"},"model":{"type":"string"},"q":{"type":"string"},"question":{"type":"string"},"sources":{"items":{"type":"string"},"type":"array"},"stream":{"type":"boolean"},"system":{"type":"string"}},"type":"object"},"audit.Act":{"properties":{"name":{"description":"Name is the operator's IAM username.","type":"string"},"owner":{"description":"Owner is the org of the operator's IAM row: \"admin\" for a SuperAdmin.","type":"string"},"sub":{"description":"Sub is the operator's IAM subject.","type":"string"}},"type":"object"},"audit.Wire":{"properties":{"act":{"$ref":"#/components/schemas/audit.Act","description":"Act is present ONLY on an action taken in a support session: the platform\noperator IAM signed in AS this row's sub, while org, sub and email stay the\nperson's. A console row carrying `act` was done by the operator it names."},"action":{"description":"Action is the verb that was performed. It is the event's name, not the HTTP\nmethod — a request-sourced record carries both, and the pair is what makes a\nrow readable (\"grant.create\" at POST /v1/admin/grants).","type":"string"},"after":{"description":"After is the changed thing as the action left it, redacted the same way."},"agent":{"description":"Agent is present ONLY on an action a delegated token took: who acted for\nthis row's sub — the deployment that ran their work in a sandbox — while\norg, sub and email stay the person's, who is billed for it.","type":"string"},"authMethod":{"description":"Auth is the credential the actor presented: \"jwt\", \"api-key\", or \"none\".","type":"string"},"before":{"description":"Before is the changed thing as it stood before the action, as JSON, with every\nsecret-shaped field already redacted. Only an emit point that changed something\nsets it; a request-sourced row never does."},"email":{"description":"Email is the actor's validated address, absent when the credential carried\nnone. It comes from the verified token, never from a client header.","type":"string"},"hash":{"description":"Hash is this record's SHA-256 over its own canonical JSON with both hash\nfields cleared, folded with prevHash. Recomputing it from the row's other\nfields is what proves the row has not been edited.","type":"string"},"home":{"description":"Home is present ONLY on a cross-org action: the org the actor came FROM,\nwhile Org is the org they acted IN. A console row carrying `home` is a\nplatform-admin impersonation and should be rendered as one.","type":"string"},"isAdmin":{"description":"IsAdmin is the VALIDATED platform-SuperAdmin bit at decision time\n(owner == \"admin\", principal.Super), never the client's own claim to be one.","type":"boolean"},"method":{"description":"Method is the HTTP verb, on a record a request produced. Absent on an event\nemitted from inside the binary with no request behind it.","type":"string"},"org":{"description":"Org is the tenant the action was taken IN — the effective org, which for\neveryone but an impersonating SuperAdmin is also the actor's own. Empty on an\nunauthenticated request.","type":"string"},"path":{"description":"Path is the request's route. Any segment shaped like a credential is replaced\nbefore the record is written, so a key that rides in a path is not preserved\nhere by the very control meant to watch it.","type":"string"},"prevHash":{"description":"PrevHash is the hash of record seq-1, which is what links the rows into a\nchain: a deleted or reordered record breaks the recomputation at that point.\nThe first record of a chain carries 64 zeros rather than an empty string, so\n\"start of chain\" and \"field missing\" cannot look alike.","type":"string"},"reason":{"description":"Reason is a short explanation for a deny or an error (\"SuperAdmin required\",\n\"insufficient_balance\"). It is never a secret and never a raw upstream error\nbody; absent on a success.","type":"string"},"requestId":{"description":"RequestID ties this row to the request-line log and any downstream trace — the\nX-Request-Id the pipeline minted for that request.","type":"string"},"resource":{"description":"Resource is the KIND of thing acted upon (\"org\", \"role\", \"secret\",\n\"provider-config\", \"credit\"). Where a mutation has no finer semantics than its\nroute, this is the route family and resourceId is empty — the action and the\npath already pin the object.","type":"string"},"resourceId":{"description":"ResourceID is the specific instance, absent when the kind alone identifies it.","type":"string"},"result":{"description":"Result is how the action ended: \"success\", \"deny\" or \"error\". A deny is a\ndecision this binary made and is as much evidence as a success.","type":"string"},"seq":{"description":"Seq is the record's position in the chain, 0-based and gapless. The Recorder\nassigns it under its own lock, so it is a true total order: seq n+1 was\nwritten after seq n, and a missing number is a missing record.","format":"uint64","type":"integer"},"sourceIp":{"description":"SourceIP is the client address the edge resolved for the request, after the\nproxy chain — the address a responder would act on, not the socket peer.","type":"string"},"status":{"description":"Status is the HTTP status the caller received. It is the outcome as the client\nsaw it, so a 200 carrying a domain refusal still reads 200 here.","format":"int64","type":"integer"},"sub":{"description":"Sub is the acting user (the IAM subject). Empty for a machine principal or an\nanonymous request, which is how a service action is told from a person's.","type":"string"},"time":{"description":"Time is when the action happened, RFC3339Nano in UTC. The stored column has\nthe same precision and sorts the same way, so a client can range and order on\nthis string verbatim.","type":"string"},"userAgent":{"description":"UserAgent is the client the request announced itself as. Client-supplied, so\nit is evidence about what claimed to act, not proof of it.","type":"string"}},"type":"object"},"audit.trailPage":{"properties":{"data":{"description":"Data is one page of the org's events, newest first. Empty, never null.","items":{"$ref":"#/components/schemas/audit.Wire"},"type":"array"},"msg":{"description":"Msg is the envelope's message slot, empty on success.","type":"string"},"status":{"description":"Status is the envelope's status slot, \"ok\" on success.","type":"string"},"total":{"description":"Total is how many events match the filter, across all pages — what a pager\nneeds to size itself.","format":"int64","type":"integer"}},"type":"object"},"author.authorRepo":{"properties":{"badgeMarkdown":{"description":"BadgeMarkdown is the ready-to-paste README snippet, DERIVED for each response\nfrom this deployment's badge host and never stored: a \"Deploy on Hanzo\" image\nlinking to the one-click import of this repository. Re-hosting the builder\nchanges every badge without touching a row.","type":"string"},"createdAt":{"description":"CreatedAt is unix seconds when the claim was first recorded. It equals\nverifiedAt on the first proof and then stays put while verifiedAt moves, so the\npair reads as \"claimed since / last proven\".","format":"int64","type":"integer"},"method":{"description":"Method is HOW ownership was proven: \"oauth\" — an IAM-linked forge token showed\nadmin or push on the repository; \"file\" — a hanzo.json on the default branch\ncarried this author's verify code; or \"maintainer\" — the repository sits in a\nfirst-party namespace, where ownership is intrinsic and the treasury author\nholds it with no proof step. Omitted on a row written before the method was\nrecorded.","type":"string"},"repoUrl":{"description":"RepoURL is the claim key in canonical form — lowercased \"host/owner/name\",\nno scheme, no .git, host ∈ {github.com, gitlab.com}. A deploy's source repo is\nnormalized through the same function before attribution, so the two sides can\nnever miss on a cosmetic difference. UNIQUE across every author: first proven\nclaim wins.","type":"string"},"verified":{"description":"Verified reports that ownership was proven. Only a proven claim is ever\nwritten, so it is true on every row this surface returns; the deploy path\nre-reads it regardless, because an unverified claim attributes nothing.","type":"boolean"},"verifiedAt":{"description":"VerifiedAt is unix seconds of the most recent successful proof. Re-verifying\nrefreshes it, and the method beside it, in place.","format":"int64","type":"integer"}},"type":"object"},"author.claim":{"properties":{"created":{"description":"Created reports whether this call recorded a new claim (201) or found an\nexisting one (200).","type":"boolean"},"org":{"$ref":"#/components/schemas/author.orgView","description":"Org is the verified owner-wide claim, present when an owner was claimed. It\ncovers every repository the author publishes under that owner."},"repo":{"$ref":"#/components/schemas/author.authorRepo","description":"Repo is the verified repository claim, present when a repository was claimed."}},"type":"object"},"author.connectRequest":{"properties":{"githubLogin":{"description":"GithubLogin is the account to link. Used only when IAM holds no linked\naccount for the provider — a linked account is stronger proof and always wins.","type":"string"},"login":{"description":"Login is the provider-neutral alias for GithubLogin, preferred when both are\nsent.","type":"string"},"provider":{"description":"Provider is the forge to enrol with: github (the default) or gitlab.","type":"string"}},"type":"object"},"author.deployRecord":{"properties":{"created":{"description":"Created reports whether this call recorded a new attribution edge (201) or\nfound an existing one (200). Absent when nothing was recorded.","type":"boolean"},"createdAt":{"description":"CreatedAt is when the edge was first recorded, in unix seconds. Absent when\nnothing was recorded.","format":"int64","type":"integer"},"deployId":{"description":"DeployID is the attribution edge's handle. Absent when nothing was recorded.","type":"string"},"reason":{"description":"Reason says why nothing was attributed. Present only when recorded is false.","type":"string"},"recorded":{"description":"Recorded reports whether the deploy was attributed to an author at all. False\nis the ordinary answer for a project built from no repository, or from one no\nauthor has verified — never an error, so a deploy path can fire this\nunconditionally.","type":"boolean"},"self":{"description":"Self reports that the deploying org IS the author's org. Such a deploy is\nrecorded for provenance but excluded from accrual. Absent when nothing was\nrecorded.","type":"boolean"}},"type":"object"},"author.deployRequest":{"properties":{"project":{"description":"Project is the deployed project's id. Required.","type":"string"},"repoUrl":{"description":"RepoURL is the source repository the project was built from. Empty means a\nhand-built project with nothing to attribute — an honest no-op, not an error.","type":"string"}},"type":"object"},"author.enrolment":{"properties":{"created":{"description":"Created reports whether this call enrolled the org (201) or found an existing\nenrolment (200).","type":"boolean"},"githubLogin":{"description":"GithubLogin is the linked forge account.","type":"string"},"id":{"description":"ID is the author record's server-minted handle, \"aut_\"-prefixed.","type":"string"},"shareBps":{"description":"ShareBps is this author's royalty share in basis points of the spend their\ndeployed work generates.","format":"int64","type":"integer"},"status":{"description":"Status is connected, approved or suspended. Only an approved author earns.","type":"string"},"verified":{"description":"Verified reports whether any repository or owner claim has been proven yet.","type":"boolean"},"verifyCode":{"description":"VerifyCode is this author's stable proof token — the value a repository's\nverify file must carry.","type":"string"},"verifyFile":{"description":"VerifyFile is the repo-root file the file method reads, on the default branch.","type":"string"},"verifySnippet":{"description":"VerifySnippet is that file's exact contents, ready to commit.","type":"string"}},"type":"object"},"author.orgView":{"properties":{"badgeMarkdown":{"description":"BadgeMarkdown is the ready-to-paste README snippet, DERIVED for each response\nfrom this deployment's badge host and never stored — here it deep-links the\nOWNER's template import rather than one repository's.","type":"string"},"createdAt":{"description":"CreatedAt is unix seconds when the owner claim was first recorded — equal to\nverifiedAt on the first proof, then fixed while verifiedAt moves.","format":"int64","type":"integer"},"method":{"description":"Method is HOW the owner was proven, always against its \".github\" control\nrepository: \"oauth\" — an IAM-linked forge token showed admin or push on it; or\n\"file\" — a hanzo.json on its default branch carried this author's verify code.\nThe \"maintainer\" shortcut is a per-repository attribution and never appears\nhere. Omitted on a row written before the method was recorded.","type":"string"},"ownerUrl":{"description":"OwnerURL is the claim key in canonical form — lowercased \"host/owner\" with NO\nrepository segment, host ∈ {github.com, gitlab.com}. It covers every repository\nunder that owner, so code with no claim of its own still earns; a per-repository\nclaim outranks it. UNIQUE across every author: first proven claim wins.","type":"string"},"verified":{"description":"Verified reports that ownership of the WHOLE owner was proven — against that\nowner's \".github\" control repository, which is exactly as strong as a\nper-repository claim. Only a proven claim is written, so every row returned\nhere is true.","type":"boolean"},"verifiedAt":{"description":"VerifiedAt is unix seconds of the most recent successful proof of the owner;\nre-verifying refreshes it, and the method beside it, in place.","format":"int64","type":"integer"}},"type":"object"},"author.verifyRequest":{"properties":{"repoUrl":{"description":"RepoURL is what to claim: a repository (github.com/owner/name) or a whole\nOWNER (github.com/owner, no repository segment). gitlab.com is accepted too.","type":"string"}},"type":"object"},"auto.Automation":{"properties":{"created":{"description":"Created and Updated are RFC 3339 UTC.","type":"string"},"draft":{"description":"Draft is a flow with no step yet: it has no instructions, never runs, and\nbecomes an automation when its instructions are saved.","type":"boolean"},"enabled":{"description":"Enabled is whether its schedule is armed.","type":"boolean"},"event":{"$ref":"#/components/schemas/auto.OutcomeTrigger","description":"Event runs the automation on a committed product outcome instead of a schedule."},"id":{"description":"ID is the automation's id, which is also its flow's.","type":"string"},"instructions":{"description":"Instructions are what the agent is asked to do each run.","type":"string"},"last":{"$ref":"#/components/schemas/auto.LastRun","description":"Last is its most recent run that was not skipped; null before the first."},"model":{"description":"Model is the model the agent thinks with; null for the default.","type":"string"},"name":{"description":"Name is what it is called.","type":"string"},"next":{"description":"Next is when it runs next, RFC 3339 UTC; null when manual or disabled.","type":"string"},"notify":{"description":"Notify sends a one-line summary to the automation's person when a run ends.","type":"boolean"},"permissions":{"description":"Permissions is auto (works and uses connectors without stopping) or ask\n(changes nothing and ends with the actions it proposes; agent.go agentTask).","type":"string"},"postTo":{"description":"PostTo are the connected accounts each run's answer is posted to — x,\nlinkedin, facebook — after review when Permissions is ask (post.go). Never null.","items":{"type":"string"},"type":"array"},"project":{"description":"Project is the Dev project the run works in, by its slug; null for none.","type":"string"},"schedule":{"$ref":"#/components/schemas/auto.Schedule","description":"Schedule is when it runs."},"source":{"description":"Source is the product it was made in: chat, dev, studio or workflow.","type":"string"},"target":{"description":"Target is an optional registered execution target, such as the person's local machine.","type":"string"},"updated":{"type":"string"}},"type":"object"},"auto.AutomationRun":{"properties":{"at":{"description":"At is when it started and Finished when it ended (null while it runs), RFC\n3339 UTC.","type":"string"},"draft":{"description":"Draft is the post the agent wrote, for an automation that posts; empty\notherwise.","type":"string"},"finished":{"type":"string"},"id":{"type":"string"},"outputs":{"description":"Outputs are the Library items the run made: its answer, kept as a\ndocument. Never null.","items":{"type":"string"},"type":"array"},"posts":{"description":"Posts are where it went: one per account, its link or the platform's\nreason it did not go. Never null.","items":{"$ref":"#/components/schemas/auto.PostResult"},"type":"array"},"status":{"description":"Status is succeeded, failed, running, queued, review for a post waiting\nfor its person to post or discard it, skipped for a start that found the\nprevious run still going, or refused for a run whose person is no longer a\nmember of the org.","type":"string"},"summary":{"description":"Summary is one line on how it went.","type":"string"},"transcript":{"description":"Transcript opens the run's Dev run; null when it started none.","type":"string"}},"type":"object"},"auto.Catalog":{"properties":{"connectorCount":{"format":"int64","type":"integer"},"connectors":{"items":{"$ref":"#/components/schemas/auto.ConnectorMetadata"},"type":"array"},"runnableCount":{"description":"RunnableCount is how many of them this deployment can actually invoke. It is\nthe number that matters and it was absent: a caller read connectorCount and\nreasonably believed all of it worked.","format":"int64","type":"integer"}},"type":"object"},"auto.ConnectorAction":{"properties":{"description":{"type":"string"},"displayName":{"type":"string"},"name":{"type":"string"},"props":{"items":{"$ref":"#/components/schemas/auto.PropSpec"},"type":"array"}},"type":"object"},"auto.ConnectorAuth":{"properties":{"required":{"type":"boolean"},"type":{"type":"string"}},"type":"object"},"auto.ConnectorMetadata":{"properties":{"actions":{"items":{"$ref":"#/components/schemas/auto.ConnectorAction"},"type":"array"},"auth":{"$ref":"#/components/schemas/auto.ConnectorAuth"},"categories":{"items":{"type":"string"},"type":"array"},"description":{"type":"string"},"displayName":{"type":"string"},"logoUrl":{"type":"string"},"name":{"type":"string"},"runnable":{"description":"Runnable is whether this connector's actions run HERE, so a caller can\ninvoke what the entry lists. It is the registry's answer — an action\nregistered for the connector — never a stored flag, because a stored flag\nis a second answer to a question the registry already answers.","type":"boolean"},"triggers":{"items":{"$ref":"#/components/schemas/auto.ConnectorTrigger"},"type":"array"},"version":{"type":"string"}},"type":"object"},"auto.ConnectorTrigger":{"properties":{"description":{"type":"string"},"displayName":{"type":"string"},"name":{"type":"string"},"props":{"items":{"$ref":"#/components/schemas/auto.PropSpec"},"type":"array"},"strategy":{"type":"string"}},"type":"object"},"auto.Flow":{"properties":{"created":{"format":"int64","type":"integer"},"externalId":{"type":"string"},"folderId":{"type":"string"},"id":{"type":"string"},"metadata":{},"projectId":{"description":"projectId == org (server-derived)","type":"string"},"publishedVersionId":{"type":"string"},"status":{"type":"string"},"updated":{"format":"int64","type":"integer"}},"type":"object"},"auto.FlowAction":{"properties":{"displayName":{"type":"string"},"name":{"type":"string"},"nextAction":{"$ref":"#/components/schemas/auto.FlowAction"},"settings":{"$ref":"#/components/schemas/auto.StepSettings"},"skip":{"type":"boolean"},"type":{"description":"PIECE | CODE | ROUTER | LOOP_ON_ITEMS","type":"string"},"valid":{"type":"boolean"}},"type":"object"},"auto.FlowRun":{"properties":{"created":{"format":"int64","type":"integer"},"finishTime":{"format":"int64","type":"integer"},"flowId":{"type":"string"},"flowVersionId":{"type":"string"},"id":{"type":"string"},"startTime":{"format":"int64","type":"integer"},"status":{"type":"string"},"updated":{"format":"int64","type":"integer"}},"type":"object"},"auto.FlowTrigger":{"properties":{"displayName":{"type":"string"},"name":{"type":"string"},"nextAction":{"$ref":"#/components/schemas/auto.FlowAction"},"settings":{"$ref":"#/components/schemas/auto.StepSettings"},"strategy":{"type":"string"},"type":{"description":"PIECE_TRIGGER | EMPTY","type":"string"},"valid":{"type":"boolean"}},"type":"object"},"auto.FlowVersion":{"properties":{"created":{"format":"int64","type":"integer"},"displayName":{"type":"string"},"flowId":{"type":"string"},"id":{"type":"string"},"schemaVersion":{"type":"string"},"state":{"type":"string"},"trigger":{"$ref":"#/components/schemas/auto.FlowTrigger"},"updated":{"format":"int64","type":"integer"},"valid":{"type":"boolean"}},"type":"object"},"auto.Job":{"properties":{"automation":{"type":"string"},"cost":{"format":"int64","type":"integer"},"error":{"type":"string"},"finished":{"type":"string"},"id":{"type":"string"},"kind":{"type":"string"},"origin":{"type":"string"},"outputs":{"items":{"type":"string"},"type":"array"},"product":{"type":"string"},"progress":{"format":"double","type":"number"},"ref":{"type":"string"},"session":{"type":"string"},"started":{"type":"string"},"state":{"type":"string"},"status":{"type":"string"},"summary":{"type":"string"},"title":{"type":"string"},"updated":{"type":"string"}},"type":"object"},"auto.LastRun":{"properties":{"at":{"type":"string"},"id":{"type":"string"},"status":{"description":"Status is succeeded, failed, running or queued.","type":"string"},"summary":{"type":"string"}},"type":"object"},"auto.OutcomeTrigger":{"properties":{"name":{"description":"Name is the event, for example improvement.reviewed.","type":"string"},"source":{"description":"Source is the producing capability, for example research.","type":"string"}},"type":"object"},"auto.PostResult":{"properties":{"error":{"description":"Error is the platform's reason it did not go; absent when it did.","type":"string"},"to":{"description":"To is the account's platform: x, linkedin or facebook.","type":"string"},"url":{"description":"URL opens the post; absent when it did not go.","type":"string"}},"type":"object"},"auto.PropSpec":{"properties":{"description":{"description":"Description says what the value is.","type":"string"},"displayName":{"description":"DisplayName is what a form calls it.","type":"string"},"name":{"description":"Name is the input's key in the action's input object.","type":"string"},"required":{"description":"Required is whether the action refuses to run without it.","type":"boolean"},"type":{"description":"Type is the JSON type the value takes: string|number|boolean|object|array.","type":"string"}},"type":"object"},"auto.Schedule":{"properties":{"at":{"description":"At is the local time, HH:MM on a 24-hour clock, for daily, weekdays and\nweekly. Hourly takes its minute, and runs on the hour without one. Once\ntakes a local date and time, YYYY-MM-DDTHH:MM, and runs now without one.","type":"string"},"cron":{"description":"Cron is a five-field cron expression (minute hour day-of-month month\nday-of-week), for kind cron only, read in TZ.","type":"string"},"day":{"description":"Day is the weekday a weekly schedule runs on: mon, tue, wed, thu, fri, sat\nor sun.","type":"string"},"kind":{"description":"Kind is manual, hourly, daily, weekdays, weekly, cron or once. Manual runs\nonly when asked; once runs one time and then switches itself off.","type":"string"},"tz":{"description":"TZ is the IANA time zone every time here is read in. Empty is UTC.","type":"string"}},"type":"object"},"auto.Starter":{"properties":{"description":{"type":"string"},"icon":{"type":"string"},"instructions":{"type":"string"},"key":{"type":"string"},"name":{"type":"string"},"schedule":{"$ref":"#/components/schemas/auto.Schedule"}},"type":"object"},"auto.StepSettings":{"properties":{"actionName":{"type":"string"},"input":{"additionalProperties":{},"type":"object"},"pieceName":{"type":"string"},"pieceVersion":{"type":"string"},"triggerName":{"type":"string"}},"type":"object"},"auto.automationIn":{"properties":{"enabled":{"description":"Enabled arms its schedule. Absent is true.","type":"boolean"},"event":{"$ref":"#/components/schemas/auto.OutcomeTrigger","description":"Event arms a product-outcome trigger; it is mutually exclusive with a timed schedule."},"instructions":{"description":"Instructions are what the agent is asked to do each run. Required.","type":"string"},"model":{"description":"Model is the model id to think with. Optional; absent is the default.","type":"string"},"name":{"description":"Name is what it is called. Required.","type":"string"},"notify":{"description":"Notify sends a one-line summary when a run ends.","type":"boolean"},"permissions":{"description":"Permissions is auto (works without stopping) or ask (proposes, changes\nnothing). Absent is ask.","type":"string"},"postTo":{"description":"PostTo are the connected accounts each run's answer is posted to: x,\nlinkedin, facebook. Absent posts nothing.","items":{"type":"string"},"type":"array"},"project":{"description":"Project is a Dev project's slug to work in. Optional.","type":"string"},"schedule":{"$ref":"#/components/schemas/auto.Schedule","description":"Schedule is when it runs. Absent runs it only on demand."},"source":{"description":"Source is the product it is made in: chat, dev, studio or workflow. Absent\nis dev.","type":"string"},"target":{"description":"Target selects a registered execution target for the coding run.","type":"string"}},"type":"object"},"auto.automationPage":{"properties":{"data":{"description":"Data is the org's automations.","items":{"$ref":"#/components/schemas/auto.Automation"},"type":"array"}},"type":"object"},"auto.automationPatch":{"properties":{"enabled":{"description":"Enabled arms or disarms its schedule.","type":"boolean"},"event":{"$ref":"#/components/schemas/auto.OutcomeTrigger","description":"Event replaces the trigger with a product outcome; null clears it."},"id":{"description":"ID is the automation, from the path.","type":"string"},"instructions":{"type":"string"},"model":{"type":"string"},"name":{"type":"string"},"notify":{"type":"boolean"},"permissions":{"type":"string"},"postTo":{"items":{"type":"string"},"type":"array"},"project":{"type":"string"},"schedule":{"$ref":"#/components/schemas/auto.Schedule"},"target":{"description":"Target replaces the registered execution target; null clears it.","type":"string"}},"type":"object"},"auto.automationRunPage":{"properties":{"data":{"description":"Data is the automation's runs, newest first.","items":{"$ref":"#/components/schemas/auto.AutomationRun"},"type":"array"}},"type":"object"},"auto.createFlowReq":{"properties":{"displayName":{"description":"DisplayName names the flow's initial draft version.","type":"string"},"externalId":{"description":"ExternalID is the caller's own id for this flow. Optional.","type":"string"},"folderId":{"description":"FolderID groups the flow in the builder's tree. Optional.","type":"string"},"trigger":{"$ref":"#/components/schemas/auto.FlowTrigger","description":"Trigger is the root of the step tree — how the flow starts, and the action\nchain that follows. Optional: a flow may be created empty and edited later."}},"type":"object"},"auto.createVersionIn":{"properties":{"displayName":{"description":"DisplayName names the new version.","type":"string"},"id":{"description":"ID is the flow to add a version to, from the path.","type":"string"},"trigger":{"$ref":"#/components/schemas/auto.FlowTrigger","description":"Trigger is the root of the version's step tree. Optional: a version with no\ntrigger is created invalid, and cannot run until one is set."}},"type":"object"},"auto.flowPage":{"properties":{"data":{"description":"Data is the page of flows, newest-updated first.","items":{"$ref":"#/components/schemas/auto.Flow"},"type":"array"}},"type":"object"},"auto.jobPage":{"properties":{"data":{"description":"Data are your jobs, the most recently changed first.","items":{"$ref":"#/components/schemas/auto.Job"},"type":"array"}},"type":"object"},"auto.patchFlowIn":{"properties":{"externalId":{"description":"ExternalID sets the caller's own id for this flow.","type":"string"},"folderId":{"description":"FolderID moves the flow in the builder's tree.","type":"string"},"id":{"description":"ID is the flow to update, from the path.","type":"string"},"metadata":{"description":"Metadata replaces the caller's opaque JSON."},"publishedVersionId":{"description":"PublishedVersionID pins the version runs execute. It must name a version OF\nTHIS FLOW; empty clears the pin, so runs take the latest version again.","type":"string"}},"type":"object"},"auto.populatedFlow":{"properties":{"created":{"description":"Created and Updated are unix milliseconds.","format":"int64","type":"integer"},"externalId":{"description":"ExternalID is the caller's own id for this flow, if it set one.","type":"string"},"folderId":{"description":"FolderID groups the flow in the builder's tree.","type":"string"},"id":{"description":"ID is the flow's id.","type":"string"},"metadata":{"description":"Metadata is the caller's opaque JSON, stored and returned verbatim."},"projectId":{"description":"Org is the owning org, which this surface names projectId. Server-derived from\nthe validated principal — never read from a request.","type":"string"},"publishedVersionId":{"description":"PublishedVersionID is the version a run executes when set; empty means the\nlatest version runs.","type":"string"},"status":{"description":"Status is ENABLED or DISABLED — whether the flow's trigger is armed.","type":"string"},"updated":{"format":"int64","type":"integer"},"version":{"$ref":"#/components/schemas/auto.FlowVersion","description":"Version is the flow's latest version — its display name and step tree."}},"type":"object"},"auto.reviewIn":{"properties":{"id":{"description":"ID is the automation, and Run its run in review, from the path.","type":"string"},"post":{"description":"Post posts it when true and discards it when false.","type":"boolean"},"run":{"type":"string"}},"type":"object"},"auto.runHandle":{"properties":{"id":{"type":"string"},"status":{"type":"string"}},"type":"object"},"auto.runIn":{"properties":{"action":{"description":"Action is the name of the provider action to invoke.","type":"string"},"auth":{"description":"Auth is the caller's resolved credential for the provider, handed to the\naction verbatim. Its shape is whatever the provider's auth descriptor\ndeclares (a token string, an object), so it is opaque here."},"id":{"description":"ID is the provider to run, from the path.","type":"string"},"props":{"additionalProperties":{},"description":"Props are the action's input properties, keyed by property name.","type":"object"}},"type":"object"},"auto.runPage":{"properties":{"data":{"description":"Data is the page of runs, newest first.","items":{"$ref":"#/components/schemas/auto.FlowRun"},"type":"array"}},"type":"object"},"auto.runResp":{"properties":{"error":{"description":"Error is the provider-level failure message when not ok.","type":"string"},"ok":{"description":"Ok reports whether the action ran to completion.","type":"boolean"},"output":{"description":"Output is the action's result when ok. Its shape is the action's own."}},"type":"object"},"auto.runStarted":{"properties":{"run":{"$ref":"#/components/schemas/auto.runHandle","description":"Run is the run this started, or the skipped start when one was going."}},"type":"object"},"auto.starterPage":{"properties":{"data":{"description":"Data is the starters.","items":{"$ref":"#/components/schemas/auto.Starter"},"type":"array"}},"type":"object"},"auto.versionPage":{"properties":{"data":{"description":"Data is the page of versions, newest first.","items":{"$ref":"#/components/schemas/auto.FlowVersion"},"type":"array"}},"type":"object"},"auto.whenIn":{"properties":{"text":{"description":"Text is when it runs, as a person says it: \"every monday at 9am\".","type":"string"},"tz":{"description":"TZ is the IANA zone the words are read in. Empty is UTC.","type":"string"}},"type":"object"},"auto.whenOut":{"properties":{"next":{"description":"Next is when it would first run, RFC 3339 UTC; null when it runs only on\ndemand.","type":"string"},"says":{"description":"Says is the schedule said back in plain words.","type":"string"},"schedule":{"$ref":"#/components/schemas/auto.Schedule","description":"Schedule is the schedule, ready to send as an automation's `schedule`."}},"type":"object"},"base.baseHealth":{"properties":{"service":{"description":"Service is \"base\" — which subsystem answered.","type":"string"},"status":{"description":"Status is \"ok\" when the subsystem is serving.","type":"string"}},"type":"object"},"base.baseView":{"properties":{"bytes":{"description":"Bytes is the store's size on disk, present only once it exists. It is what\nthis Base occupies, not a quota.","format":"int64","type":"integer"},"exists":{"description":"Exists reports whether this Base's store has been provisioned. False is an\norg nobody has stored anything for yet, which is a state to name rather\nthan an error: the store is created the first time anything writes.","type":"boolean"},"org":{"description":"Org is the org this Base belongs to. It is the address every other Base\ncall is scoped by, and a Base has no name of its own.","type":"string"}},"type":"object"},"benchmark.Benchmark":{"properties":{"axis":{"description":"what capability it measures","type":"string"},"direction":{"description":"Direction is \"higher\" when a higher score is better and \"lower\" when a\nlower one is: a false-alarm rate, a share of answers that moved. The\nleaderboard orders its rows by it.","type":"string"},"id":{"description":"the id every other op on this surface takes","type":"string"},"items":{"description":"how many items it holds, when the set is fixed","format":"int64","type":"integer"},"native":{"description":"whether the standardized harness runs it today","type":"boolean"},"source":{"description":"where the items come from","type":"string"},"title":{"description":"the benchmark's published name","type":"string"}},"type":"object"},"benchmark.Claim":{"properties":{"benchmark":{"description":"Benchmark is the canonical test id the claim is about, from /catalog.","type":"string"},"evidence":{"description":"Evidence are the evidence uris the claim rests on, at most 64.","items":{"type":"string"},"type":"array"},"model":{"description":"Model is the system the score is claimed for.","type":"string"},"protocol":{"description":"Protocol records HOW it was scored — provider-reported, agentic,\nthird-party-leaderboard — so a provider card is never read as a measurement.","type":"string"},"provider":{"description":"Provider is who the claim belongs to — the lab or leaderboard whose number\nthis is.","type":"string"},"runs":{"description":"Runs are the research run ids the claim rests on, at most 64.","items":{"type":"string"},"type":"array"},"score":{"description":"Score is the reported aggregate, as a percentage.","format":"double","type":"number"},"source":{"description":"Source is the citation the row was read from. Required.","type":"string"}},"type":"object"},"benchmark.ClaimRow":{"properties":{"at":{"description":"At is when a stored row was recorded. Zero for a seed row.","format":"date-time","type":"string"},"benchmark":{"description":"Benchmark is the canonical test id the claim is about, from /catalog.","type":"string"},"by":{"description":"By is the verified user who recorded a stored row. Empty for a seed row.","type":"string"},"evidence":{"description":"Evidence are the evidence uris the claim rests on\n(GET /v1/research/evidence?uri=).","items":{"type":"string"},"type":"array"},"from":{"description":"From is the org a curator row was promoted from: the org that filed the\nclaim before a SuperAdmin published it. Empty on every other row.","type":"string"},"model":{"description":"Model is the system the score is claimed for.","type":"string"},"org":{"description":"Org is the org that made the claim. \"admin\" is the platform's own curated\nreading; any other org is that org's claim, not the platform's. Empty on an\nunattributed row.","type":"string"},"origin":{"description":"Origin is \"seed\" for a compiled row, \"stored\" for one a verified caller\nwrote through this surface, and \"unattributed\" for a stored row no verified\ncaller vouches for, which never reaches the leaderboard.","type":"string"},"protocol":{"description":"Protocol records HOW it was scored — provider-reported, agentic,\nthird-party-leaderboard — so a provider card is never read as a measurement.","type":"string"},"provider":{"description":"Provider is who the claim belongs to — the lab or leaderboard whose number\nthis is.","type":"string"},"runs":{"description":"Runs are the research run ids the claim rests on\n(GET /v1/research/runs?id=).","items":{"type":"string"},"type":"array"},"score":{"description":"Score is the reported aggregate, as a percentage.","format":"double","type":"number"},"source":{"description":"Source is the citation the row was read from.","type":"string"},"visibility":{"description":"Visibility is \"public\", readable by anyone, or \"private\", readable by Org's\nown members only. Only the curator's public claims reach the leaderboard.","type":"string"}},"type":"object"},"benchmark.LeaderRow":{"properties":{"ciHigh":{"description":"CIHigh is the upper bound of that interval. Wilson rather than the normal\napproximation because the normal one produces bounds past 100 exactly where\nbenchmark scores live — at 194/198 that is the top of the board, not a\ncorner case.","format":"double","type":"number"},"ciLow":{"description":"CILow and CIHigh are the 95% Wilson interval on Measured, in percent. They\nare what makes the score comparable: at n=198 a 98% carries roughly ±2\npoints, so most differences at the top of a board are not distinguishable\nand a bare number implies a precision it does not have. Absent when there\nis no measurement.","format":"double","type":"number"},"claims":{"description":"Claims is how many independent claims the platform holds for this model on\nthis benchmark. More than one means several sources reported it.","format":"int64","type":"integer"},"evidence":{"description":"Evidence are the evidence uris the Published claim rests on\n(GET /v1/research/evidence?uri=).","items":{"type":"string"},"type":"array"},"from":{"description":"From is the org whose claim Published was promoted from, when a SuperAdmin\npublished another org's claim rather than writing one under org admin:\n\"hanzo\" on a row Hanzo measured and the platform published.","type":"string"},"gap":{"description":"published − measured (the arena signal)","format":"double","type":"number"},"mean":{"description":"Mean is the unweighted average of every claim, which answers a different\nquestion from Published: what the field says on average, rather than what\nthe vendor says about itself. With one claim the two are equal.","format":"double","type":"number"},"measured":{"description":"hanzo-measured accuracy % (nil if unrun)","format":"double","type":"number"},"measuredAt":{"description":"MeasuredAt is when the run behind Measured was recorded.","format":"date-time","type":"string"},"model":{"description":"the model this row scores","type":"string"},"n":{"description":"coverage — NEVER compare across different n","format":"int64","type":"integer"},"protocol":{"description":"how the vendor scored their claim: single-attempt, pass@k or agentic","type":"string"},"published":{"description":"the platform's selected claim % (nil if none)","format":"double","type":"number"},"run":{"description":"Run names the measurement Measured came from, and MeasuredAt is when it\nran. A score with no date is not a fact about a model, it is a fact about\na model on a day — and models change, so the date is what makes the number\ncheckable rather than merely quoted.","type":"string"},"runs":{"description":"Runs are the research run ids the Published claim rests on\n(GET /v1/research/runs?id=).","items":{"type":"string"},"type":"array"},"spread":{"description":"Spread is the distance between the highest and lowest of them, nil when\nthere is only one. It is the disagreement AMONG sources, which a single\nPublished number cannot show — signal in the same way the\npublished-minus-measured gap is.","format":"double","type":"number"}},"type":"object"},"benchmark.ModelHistory":{"properties":{"model":{"description":"Model is the system these runs measured.","type":"string"},"points":{"description":"Points is every run, oldest first.","items":{"$ref":"#/components/schemas/benchmark.RunPoint"},"type":"array"},"trend":{"description":"Trend is the change from the first run to the last, absent when there has\nonly been one. It answers the question a list of points makes you compute.","format":"double","type":"number"}},"type":"object"},"benchmark.Preset":{"properties":{"arms":{"description":"the blend — model ids from the arena","items":{"type":"string"},"type":"array"},"at":{"description":"At is when this version was stored. Set by the server; a value sent is not\nread. Zero on the reference blend.","format":"date-time","type":"string"},"by":{"description":"By is the verified user who stored it. Set by the server; a value sent is\nnot read.","type":"string"},"name":{"description":"the part after enso-: lowercase letters, digits and inner hyphens, at most 64","type":"string"},"note":{"description":"why this blend (audit)","type":"string"},"owner":{"description":"the org the blend belongs to: the writer's verified org, never a value sent","type":"string"},"panel":{"description":"fan-out width (\u003e=1)","format":"int64","type":"integer"},"rank":{"description":"escalation order over arms","items":{"type":"string"},"type":"array"}},"type":"object"},"benchmark.RunPoint":{"properties":{"at":{"description":"At is when the run was recorded.","format":"date-time","type":"string"},"delta":{"description":"Delta is the change in score from the previous run for this model, absent\non the first. It is the number the whole surface exists to make visible.","format":"double","type":"number"},"n":{"description":"N is how many items the run covered. Two runs are only comparable at the\nsame n, which is why it travels with every point rather than being assumed.","format":"int64","type":"integer"},"run":{"description":"Run is the measurement id these attempts were recorded under.","type":"string"},"score":{"description":"Score is accuracy over the items this run covered, as a percentage.","format":"double","type":"number"}},"type":"object"},"benchmark.benchmarkCatalog":{"properties":{"data":{"description":"Data is one row per benchmark, in the catalog's own order.","items":{"$ref":"#/components/schemas/benchmark.Benchmark"},"type":"array"},"total":{"description":"Total is how many rows Data holds.","format":"int64","type":"integer"}},"type":"object"},"benchmark.claimsOut":{"properties":{"data":{"description":"Data is one row per (org, benchmark, model, SOURCE) — every independent\nclaim, not one per model. Effective values only: the row that wins after\nlayering for each key, never the superseded readings behind it.","items":{"$ref":"#/components/schemas/benchmark.ClaimRow"},"type":"array"},"total":{"description":"Total is how many rows Data holds.","format":"int64","type":"integer"}},"type":"object"},"benchmark.historyOut":{"properties":{"benchmark":{"description":"Benchmark is the catalog id these histories are about.","type":"string"},"data":{"description":"Data is one entry per model, ordered by model name.","items":{"$ref":"#/components/schemas/benchmark.ModelHistory"},"type":"array"},"total":{"description":"Total is how many models Data holds.","format":"int64","type":"integer"}},"type":"object"},"benchmark.leaderboard":{"properties":{"benchmark":{"description":"Benchmark is the catalog id these rows are about.","type":"string"},"direction":{"description":"Direction is \"higher\" or \"lower\": which way this benchmark's score\nimproves, and so which way Rows is ordered.","type":"string"},"rows":{"description":"Rows is one per model, best first in Direction: measured rows by their\nmeasurement, then claim-only rows by their published score, ties by model.","items":{"$ref":"#/components/schemas/benchmark.LeaderRow"},"type":"array"}},"type":"object"},"benchmark.measurement":{"properties":{"benchmark":{"description":"Benchmark is the catalog id this answer is about.","type":"string"},"harness":{"description":"Harness is the harness that measures this benchmark for the arena, by\nrepository. Empty when none does, and then a measurement arrives only as a\npublished run's items imported through POST /v1/benchmark/attempts.","type":"string"},"latest":{"$ref":"#/components/schemas/benchmark.RunPoint","description":"Latest is the model's latest run on this benchmark — its run id, when it\nwas recorded, its accuracy and how many items it covered — read from the\nattempts the store already holds. Null when the store holds none."},"note":{"description":"Note says in a sentence what the answer means: a held measurement served\nrather than spent again, or nothing queued and why.","type":"string"}},"type":"object"},"benchmark.measurements":{"properties":{"by":{"description":"By is the verified user who asked.","type":"string"},"data":{"description":"Data is one answer per benchmark, in the order the request named them.","items":{"$ref":"#/components/schemas/benchmark.measurement"},"type":"array"},"model":{"description":"Model is the model asked about.","type":"string"},"org":{"description":"Org is the caller's verified org.","type":"string"}},"type":"object"},"benchmark.pairing":{"properties":{"a":{"description":"A is the first model id.","type":"string"},"a_correct":{"description":"ACorrect is how many of those common items A got right.","format":"int64","type":"integer"},"b":{"description":"B is the second model id.","type":"string"},"b_correct":{"description":"BCorrect is how many of those common items B got right.","format":"int64","type":"integer"},"benchmark":{"description":"Benchmark is the catalog id the two arms were compared on.","type":"string"},"mcnemar_p":{"description":"McnemarP is the two-sided exact binomial p on the discordant pairs. It is 1\nwhen nothing is discordant, which is \"no evidence of a difference\", not an\nerror.","format":"double","type":"number"},"n_common":{"description":"NCommon is how many items BOTH arms completed. It is the denominator, and\nthe reason this comparison is valid where a raw accuracy difference is not.","format":"int64","type":"integer"},"net_a_minus_b":{"description":"NetAMinusB is the two rescue counts subtracted — A's advantage in items.","format":"int64","type":"integer"},"rescue_a_over_b":{"description":"RescueAOverB is how many items A got right and B got wrong.","format":"int64","type":"integer"},"rescue_b_over_a":{"description":"RescueBOverA is how many items B got right and A got wrong.","format":"int64","type":"integer"}},"type":"object"},"benchmark.presetList":{"properties":{"data":{"description":"Data is the reference blend, then the caller's org's stored blends by name.","items":{"$ref":"#/components/schemas/benchmark.Preset"},"type":"array"}},"type":"object"},"benchmark.presetStored":{"properties":{"note":{"description":"Note says what storing does and does not promise.","type":"string"},"preset":{"$ref":"#/components/schemas/benchmark.Preset","description":"Preset is the blend as stored: defaults filled in, Owner the caller's\nverified org, At and By the server's."},"served_as":{"description":"ServedAs is enso-\u003cname\u003e: the model id a router would resolve this blend\nunder.","type":"string"}},"type":"object"},"benchmark.putClaimsIn":{"properties":{"data":{"description":"Data is the claims to record. One row is a correction; many is an import.\nThere is no separate bulk endpoint because there is no separate operation:\nimporting a leaderboard and fixing one number are the same write.","items":{"$ref":"#/components/schemas/benchmark.Claim"},"type":"array"},"visibility":{"description":"Visibility is who may read every row in Data: \"private\", the default, keeps\nthem to the caller's org; \"public\" shows them to anyone. Restating a claim\nwith the other value moves it.","type":"string"}},"type":"object"},"benchmark.putClaimsOut":{"properties":{"org":{"description":"Org is the org the rows were recorded under: the caller's own.","type":"string"},"recorded":{"description":"Recorded is how many rows were written.","format":"int64","type":"integer"},"rejected":{"description":"Rejected names the rows that were not, and why.","items":{"type":"string"},"type":"array"},"visibility":{"description":"Visibility is who may read them.","type":"string"}},"type":"object"},"benchmark.suite":{"properties":{"benchmarks":{"description":"Benchmarks are the catalog ids to ask about. At least one is required, and\nevery id must be in the catalog.","items":{"type":"string"},"type":"array"},"model":{"description":"Model is the model to ask about, by the id its attempts are stored under.\nRequired.","type":"string"}},"required":["benchmarks"],"type":"object"},"billing.AccountsTotal":{"properties":{"accounts":{"description":"Accounts is how many linked accounts the total folds.","format":"int64","type":"integer"},"completionTokens":{"description":"CompletionTokens is the total completion-token count.","format":"int64","type":"integer"},"costCents":{"description":"CostCents is the total cost in cents.","format":"int64","type":"integer"},"promptTokens":{"description":"PromptTokens is the total prompt-token count.","format":"int64","type":"integer"},"requests":{"description":"Requests is the total request count the gateway routed.","format":"int64","type":"integer"},"totalTokens":{"description":"TotalTokens is the total token count.","format":"int64","type":"integer"}},"type":"object"},"billing.Alert":{"properties":{"createdAt":{"type":"string"},"currency":{"type":"string"},"enforce":{"type":"boolean"},"id":{"type":"string"},"over":{"type":"boolean"},"period":{"type":"string"},"periodSpentCents":{"format":"int64","type":"integer"},"project":{"type":"string"},"rateLimitRpm":{"format":"int64","type":"integer"},"resetsAt":{"type":"string"},"service":{"type":"string"},"softPct":{"format":"int64","type":"integer"},"threshold":{"format":"int64","type":"integer"},"title":{"type":"string"},"triggeredAt":{"type":"string"},"updatedAt":{"type":"string"},"userId":{"type":"string"},"warn":{"type":"boolean"}},"type":"object"},"billing.AlertPatch":{"properties":{"enforce":{"type":"boolean"},"id":{"type":"string"},"project":{"type":"string"},"rateLimitRpm":{"format":"int64","type":"integer"},"service":{"type":"string"},"softPct":{"format":"int64","type":"integer"},"subject":{"type":"string"},"threshold":{"format":"int64","type":"integer"},"title":{"type":"string"}},"type":"object"},"billing.AlertSpec":{"properties":{"currency":{"type":"string"},"enforce":{"type":"boolean"},"project":{"type":"string"},"rateLimitRpm":{"format":"int64","type":"integer"},"service":{"type":"string"},"softPct":{"format":"int64","type":"integer"},"subject":{"type":"string"},"threshold":{"format":"int64","type":"integer"},"title":{"type":"string"}},"type":"object"},"billing.AutoRecharge":{"properties":{"amountCents":{"format":"int64","type":"integer"},"currency":{"type":"string"},"enabled":{"type":"boolean"},"lastRechargedAt":{"type":"string"},"perDay":{"description":"PerDay is the most times the sweep reloads the balance in one UTC day.","format":"int64","type":"integer"},"stored":{"type":"boolean"},"subject":{"type":"string"},"thresholdCents":{"format":"int64","type":"integer"}},"type":"object"},"billing.AutoRechargeEdit":{"properties":{"amountCents":{"format":"int64","type":"integer"},"currency":{"type":"string"},"enabled":{"type":"boolean"},"thresholdCents":{"format":"int64","type":"integer"}},"type":"object"},"billing.BillingAccount":{"properties":{"createdAt":{"type":"string"},"currency":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"orgId":{"type":"string"},"orgName":{"type":"string"},"role":{"description":"Role is the caller's standing. Absent when nobody was named, so an\nanonymous read returns an account rather than an implied membership.","type":"string"}},"type":"object"},"billing.BillingInvoice":{"properties":{"amountDue":{"format":"int64","type":"integer"},"amountPaid":{"format":"int64","type":"integer"},"attemptCount":{"format":"int64","type":"integer"},"createdAt":{"type":"string"},"creditApplied":{"format":"int64","type":"integer"},"currency":{"type":"string"},"customerEmail":{"type":"string"},"discount":{"format":"int64","type":"integer"},"dueDate":{"type":"string"},"id":{"type":"string"},"lineItems":{"description":"LineItems carries no omitempty and is never allocated empty, because the\nwire it reproduces sends `null` for an invoice with no lines. An empty\narray there would be a different answer to \"were there lines\".","items":{"$ref":"#/components/schemas/billing.InvoiceLineItem"},"type":"array"},"number":{"format":"int64","type":"integer"},"numberStr":{"type":"string"},"paidAt":{"type":"string"},"paymentMethod":{"type":"string"},"paymentRef":{"type":"string"},"periodEnd":{"type":"string"},"periodStart":{"type":"string"},"status":{"type":"string"},"subscriptionId":{"type":"string"},"subtotal":{"format":"int64","type":"integer"},"tax":{"format":"int64","type":"integer"},"updatedAt":{"type":"string"},"userId":{"type":"string"},"voidedAt":{"type":"string"}},"type":"object"},"billing.CapVerdict":{"properties":{"allow":{"type":"boolean"},"capCents":{"format":"int64","type":"integer"},"reason":{"type":"string"},"spentCents":{"format":"int64","type":"integer"},"warnPct":{"format":"int64","type":"integer"}},"type":"object"},"billing.Charged":{"properties":{"balanceCents":{"description":"BalanceCents is the subject's balance AFTER the charge settled, in cents, so\na caller does not have to re-read to show the new number.","format":"int64","type":"integer"},"processorRef":{"description":"ProcessorRef is the payment processor's own reference. It is the only field\nthat proves money moved at the GATEWAY rather than merely in our ledger,\nwhich is why it is answered and not only logged. Absent where the processor\nreturned none.","type":"string"},"status":{"description":"Status is how the charge ended. Read it rather than inferring success from\nthe HTTP status: the call succeeded whenever this field is present, and what\nthe PROCESSOR did is what this says.","type":"string"},"test":{"description":"Test states which bucket was credited — sandbox money or real money — so no\nreader has to guess whether a receipt is real. Sandbox and live funds are\nphysically separate ledgers, and a reader that conflates them restates the\ncompany's revenue.","type":"boolean"},"transactionId":{"description":"TransactionID is the ledger entry this charge created. It is the handle a\nlater read or a refund names, and it is minted by the ledger rather than by\nthe caller.","type":"string"}},"type":"object"},"billing.Collected":{"properties":{"balanceUsedCents":{"description":"BalanceUsedCents is how much was covered by prepaid balance.","format":"int64","type":"integer"},"cardChargedCents":{"description":"CardChargedCents is how much was charged to the card on file.","format":"int64","type":"integer"},"creditUsedCents":{"description":"CreditUsedCents is how much was covered by credit grants.","format":"int64","type":"integer"},"invoice":{"$ref":"#/components/schemas/billing.Invoice","description":"Invoice is the invoice AFTER the attempt — its status is the authority on\nwhat happened, not this struct's other fields."},"paid":{"description":"Paid reports whether the invoice is now settled in full. A false here with\nno error is a DECLINE: the invoice stays open and may be collected again.","type":"boolean"},"processorRef":{"description":"ProcessorRef is the processor's reference for any card charge — the field\nthat proves money moved at the gateway rather than only in our ledger.","type":"string"},"reason":{"description":"Reason explains a decline or partial collection. Empty on success.","type":"string"}},"type":"object"},"billing.CreditBalance":{"properties":{"balances":{"items":{"$ref":"#/components/schemas/billing.CreditEntry"},"type":"array"},"userId":{"type":"string"}},"type":"object"},"billing.CreditEntry":{"properties":{"available":{"format":"int64","type":"integer"},"currency":{"type":"string"}},"type":"object"},"billing.CreditGrant":{"properties":{"active":{"type":"boolean"},"amountCents":{"format":"int64","type":"integer"},"createdAt":{"type":"string"},"currency":{"type":"string"},"effectiveAt":{"type":"string"},"expiresAt":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"priority":{"format":"int64","type":"integer"},"remainingCents":{"format":"int64","type":"integer"},"tags":{"type":"string"},"userId":{"type":"string"},"voided":{"type":"boolean"}},"type":"object"},"billing.CreditGrants":{"properties":{"count":{"format":"int64","type":"integer"},"grants":{"items":{"$ref":"#/components/schemas/billing.CreditGrant"},"type":"array"}},"type":"object"},"billing.CryptoDeposit":{"properties":{"addressTag":{"type":"string"},"chain":{"type":"string"},"depositAddress":{"type":"string"},"expiresAt":{"type":"string"},"id":{"type":"string"},"status":{"type":"string"},"token":{"type":"string"}},"type":"object"},"billing.CryptoOptions":{"properties":{"chains":{"items":{"type":"string"},"type":"array"},"gateway":{"items":{"type":"string"},"type":"array"},"tokens":{"items":{"type":"string"},"type":"array"}},"type":"object"},"billing.Detachment":{"properties":{"deleted":{"description":"Deleted is whether the method was actually removed. False with no error\nmeans it was already gone, which is a successful detach rather than a\nfailure — a retry must not be an error.","type":"boolean"},"id":{"description":"ID is the method that was detached, echoed so a caller batching several can\ntell the answers apart.","type":"string"}},"type":"object"},"billing.GatewayAccept":{"properties":{"asset":{"type":"string"},"decimals":{"format":"int64","type":"integer"},"domain":{"$ref":"#/components/schemas/billing.GatewayDomain"},"maxAmount":{"type":"string"},"minAmount":{"type":"string"},"minValiditySeconds":{"format":"int64","type":"integer"},"network":{"type":"string"},"symbol":{"type":"string"}},"type":"object"},"billing.GatewayAuthorization":{"properties":{"from":{"type":"string"},"nonce":{"type":"string"},"to":{"type":"string"},"validAfter":{"type":"string"},"validBefore":{"type":"string"},"value":{"type":"string"}},"type":"object"},"billing.GatewayDomain":{"properties":{"chainId":{"format":"int64","type":"integer"},"name":{"type":"string"},"verifyingContract":{"type":"string"},"version":{"type":"string"}},"type":"object"},"billing.GatewayField":{"properties":{"name":{"type":"string"},"type":{"type":"string"}},"type":"object"},"billing.GatewayPayment":{"properties":{"amountCents":{"format":"int64","type":"integer"},"createdAt":{"type":"string"},"credited":{"type":"boolean"},"deferred":{"type":"boolean"},"from":{"type":"string"},"id":{"type":"string"},"network":{"type":"string"},"payment":{"type":"string"},"reason":{"type":"string"},"status":{"type":"string"},"txHash":{"type":"string"},"updatedAt":{"type":"string"},"value":{"type":"string"}},"type":"object"},"billing.GatewayTerms":{"properties":{"accepts":{"items":{"$ref":"#/components/schemas/billing.GatewayAccept"},"type":"array"},"maxCents":{"format":"int64","type":"integer"},"maxValiditySeconds":{"format":"int64","type":"integer"},"minCents":{"format":"int64","type":"integer"},"nonce":{"type":"string"},"payTo":{"type":"string"},"primaryType":{"type":"string"},"salt":{"type":"string"},"scheme":{"type":"string"},"types":{"additionalProperties":{"items":{"$ref":"#/components/schemas/billing.GatewayField"},"type":"array"},"type":"object"},"x402Version":{"format":"int64","type":"integer"}},"type":"object"},"billing.Holder":{"properties":{"addedAt":{"type":"string"},"email":{"type":"string"},"id":{"type":"string"},"role":{"type":"string"},"userId":{"type":"string"}},"type":"object"},"billing.Invoice":{"properties":{"amountDueCents":{"description":"AmountDueCents is what remains collectible.","format":"int64","type":"integer"},"amountPaidCents":{"description":"AmountPaidCents is what has been collected so far.","format":"int64","type":"integer"},"createdAt":{"description":"CreatedAt is when the draft was raised, RFC3339.","type":"string"},"currency":{"description":"Currency is the ISO 4217 code.","type":"string"},"customerEmail":{"description":"CustomerEmail is where it is sent.","type":"string"},"id":{"description":"ID is the invoice id — what the issue, collect and void ops address.","type":"string"},"lines":{"description":"Lines are the charges on the invoice.","items":{"$ref":"#/components/schemas/billing.InvoiceLine"},"type":"array"},"number":{"description":"Number is the human-facing invoice number, e.g. \"INV-0042\". A draft has\nnone; issuing assigns it.","type":"string"},"paymentRef":{"description":"PaymentRef is the processor reference for the collection, once paid.","type":"string"},"status":{"description":"Status is draft, open, paid, void or uncollectible. A draft is not\ncollectible; issuing moves it to open.","type":"string"},"subtotalCents":{"description":"SubtotalCents is the sum of the lines.","format":"int64","type":"integer"},"userId":{"description":"UserID is the customer billed.","type":"string"}},"type":"object"},"billing.InvoiceLine":{"properties":{"amount":{"description":"Amount is the line total in whole cents (250000 is $2,500.00).","format":"int64","type":"integer"},"description":{"description":"Description is the human-readable line, e.g. \"Advisory retainer — August\".","type":"string"},"quantity":{"description":"Quantity is the number of units, when the line is metered. Optional.","format":"int64","type":"integer"},"unitPrice":{"description":"UnitPrice is the per-unit price in cents, when the line is metered. Optional.","format":"int64","type":"integer"}},"type":"object"},"billing.InvoiceLineItem":{"properties":{"amount":{"format":"int64","type":"integer"},"currency":{"type":"string"},"description":{"type":"string"},"id":{"type":"string"},"meterId":{"type":"string"},"periodEnd":{"type":"string"},"periodStart":{"description":"The billed period. Both carry omitempty and neither is ever empty, which\nlooks contradictory and is not: the shape they reproduce is a time value,\nand omitempty does nothing to a struct — so those keys render even for the\nzero instant. The adapter formats the zero instant rather than skipping it,\nwhich is what keeps the two wires the same.","type":"string"},"planId":{"type":"string"},"planName":{"type":"string"},"quantity":{"format":"int64","type":"integer"},"type":{"type":"string"},"unitPrice":{"format":"int64","type":"integer"}},"type":"object"},"billing.InvoiceRef":{"properties":{"brand":{"description":"Brand is the brand that bills (hanzo, lux, zoo, pars), whose mark and\naddress a rendered invoice carries. The edge sets it from the caller's\nissuer; empty is Hanzo.","type":"string"},"id":{"description":"ID is the invoice id.","type":"string"}},"type":"object"},"billing.Invoices":{"properties":{"count":{"format":"int64","type":"integer"},"cursor":{"type":"string"},"invoices":{"items":{"$ref":"#/components/schemas/billing.BillingInvoice"},"type":"array"}},"type":"object"},"billing.Mode":{"properties":{"live":{"type":"boolean"},"orgId":{"type":"string"},"orgName":{"type":"string"},"testMode":{"type":"boolean"}},"type":"object"},"billing.ModeIn":{"properties":{"testMode":{"type":"boolean"}},"type":"object"},"billing.Money":{"properties":{"currency":{"type":"string"},"decimal":{"type":"string"}},"required":["decimal","currency"],"type":"object"},"billing.PaymentConfig":{"properties":{"applicationId":{"type":"string"},"environment":{"type":"string"},"live":{"type":"boolean"},"locationId":{"type":"string"},"provider":{"type":"string"}},"type":"object"},"billing.Payout":{"properties":{"amount":{"format":"int64","type":"integer"},"arrivalDate":{"type":"string"},"created":{"type":"string"},"currency":{"type":"string"},"description":{"type":"string"},"destinationId":{"type":"string"},"destinationType":{"type":"string"},"failureCode":{"type":"string"},"failureMessage":{"type":"string"},"id":{"type":"string"},"metadata":{},"providerRef":{"type":"string"},"status":{"type":"string"}},"type":"object"},"billing.RaiseIn":{"properties":{"currency":{"description":"Currency is the ISO 4217 code, lower-cased. Empty means usd.","type":"string"},"customerEmail":{"description":"CustomerEmail is where the invoice is sent. Optional.","type":"string"},"lines":{"description":"Lines are the charges. The invoice subtotal and amount due are COMPUTED\nfrom these — there is no total field to send, because a total that\ndisagreed with its own lines would bill a number nobody could derive.","items":{"$ref":"#/components/schemas/billing.InvoiceLine"},"type":"array"},"userId":{"description":"UserID identifies the customer being billed, within the caller's own org.\nRequired — an invoice with no addressee is not an invoice.","type":"string"}},"type":"object"},"billing.Recharge":{"properties":{"charged":{"description":"Charged is how many of them were actually charged. It is at most Orgs, and\nthe difference is orgs whose balance was already above their threshold.","format":"int64","type":"integer"},"orgs":{"description":"Orgs is how many orgs the sweep considered — every org with auto-recharge\narmed, whether or not it needed charging.","format":"int64","type":"integer"},"results":{"description":"Results is one row per org considered, so a sweep that charged nobody is\nstill explainable. Never null.","items":{"$ref":"#/components/schemas/billing.Recharged"},"type":"array"}},"type":"object"},"billing.Recharged":{"properties":{"amountCents":{"format":"int64","type":"integer"},"balanceCents":{"format":"int64","type":"integer"},"charged":{"type":"boolean"},"error":{"type":"string"},"orgName":{"type":"string"},"transactionId":{"type":"string"},"userId":{"type":"string"}},"type":"object"},"billing.Rollup":{"properties":{"balance":{"$ref":"#/components/schemas/billing.RollupBalance"},"consumedCents":{"format":"int64","type":"integer"},"currency":{"type":"string"},"included":{"$ref":"#/components/schemas/billing.RollupAllotment"},"overageCents":{"format":"int64","type":"integer"},"period":{"type":"string"},"plan":{"type":"string"},"user":{"type":"string"}},"type":"object"},"billing.RollupAllotment":{"properties":{"consumedCents":{"format":"int64","type":"integer"},"grantedCents":{"format":"int64","type":"integer"},"monthlyCents":{"format":"int64","type":"integer"},"remainingCents":{"format":"int64","type":"integer"}},"type":"object"},"billing.RollupBalance":{"properties":{"availableCents":{"format":"int64","type":"integer"},"balanceCents":{"format":"int64","type":"integer"},"holdsCents":{"format":"int64","type":"integer"}},"type":"object"},"billing.RoutedUsage":{"properties":{"account":{"description":"Account is the provider-side account identifier.","type":"string"},"billing":{"description":"Billing is how the routed inference bills: plan or commerce.","type":"string"},"completionTokens":{"description":"CompletionTokens is the routed completion-token count.","format":"int64","type":"integer"},"costCents":{"description":"CostCents is the routed cost in cents.","format":"int64","type":"integer"},"kind":{"description":"Kind is how the account authenticates: subscription or apikey.","type":"string"},"promptTokens":{"description":"PromptTokens is the routed prompt-token count.","format":"int64","type":"integer"},"provider":{"description":"Provider is the AI provider the row's account belongs to.","type":"string"},"requests":{"description":"Requests is how many requests the gateway routed through this account.","format":"int64","type":"integer"},"totalTokens":{"description":"TotalTokens is the routed total token count.","format":"int64","type":"integer"}},"type":"object"},"billing.SaleLine":{"properties":{"planId":{"description":"PlanID is the seat type, e.g. \"team-premium\".","type":"string"},"quantity":{"description":"Quantity is the seats of it bought, at least 1.","format":"int64","type":"integer"}},"type":"object"},"billing.Subscription":{"properties":{"assigned":{"description":"Assigned is which member holds which seat type, as the org's admin set it.","items":{"$ref":"#/components/schemas/billing.SubscriptionSeat"},"type":"array"},"cancelAtPeriodEnd":{"description":"CancelAtPeriodEnd reports that the plan ends at CurrentPeriodEnd.","type":"boolean"},"canceledAt":{"description":"CanceledAt is when it was canceled; absent when it was not.","type":"string"},"chargedCents":{"description":"ChargedCents is what the period in hand was actually paid, after any discount\nand net of refunds. 0 when the period is unpaid.","format":"int64","type":"integer"},"coupon":{"description":"Coupon is the plan coupon code the first period was bought with, as commerce\nstores it (upper case); absent when none was.","type":"string"},"createdAt":{"description":"CreatedAt is when the row was written, RFC 3339.","type":"string"},"currentPeriodEnd":{"description":"CurrentPeriodEnd is when it ends, RFC 3339. The plan is paid through it.","type":"string"},"currentPeriodStart":{"description":"CurrentPeriodStart is when the period in hand began, RFC 3339.","type":"string"},"defaultPaymentMethod":{"description":"DefaultPaymentMethod is the saved method a renewal would use. Empty means\nthere is none, so nothing can charge the plan.","type":"string"},"endedAt":{"description":"EndedAt is when it ended; absent while it runs.","type":"string"},"held":{"description":"Held reports that this row is the subject's one paid plan: while it stands,\ncommerce refuses a second paid sale (409).","type":"boolean"},"id":{"description":"ID is the subscription's own id, the one cancel and reactivate take.","type":"string"},"lines":{"description":"Lines are a team's other seat types beside Plan (a team of standard and\npremium seats is Plan \"team\" and one line of \"team-premium\"), each with the\nseats of it the period in hand was paid for. Seats above counts them too.\nAfter Held, so the fields before them keep their places on the ZAP wire.","items":{"$ref":"#/components/schemas/billing.SubscriptionLine"},"type":"array"},"mrrCents":{"description":"MRRCents is what this subscription contributes per month — commerce's own\nfigure, interval-normalized and multiplied by its seats, so no reader\nre-derives it from price and interval.","format":"int64","type":"integer"},"plan":{"$ref":"#/components/schemas/billing.SubscriptionPlan","description":"Plan is the plan as this subscription snapshotted it."},"planId":{"description":"PlanID is the plan slug, e.g. \"max-20x\".","type":"string"},"providerType":{"description":"ProviderType is who collects it: a processor (\"square\"), \"credit\" for a\nplan bought with credits, \"internal\" or \"bundle\" for a row nobody paid for.","type":"string"},"quantity":{"description":"Quantity is the seat count; a flat plan holds 1.","format":"int64","type":"integer"},"seats":{"description":"Seats is the seat count the period in hand was paid for — its paid invoice's\nquantity, or the quantity recorded with an external period — never the row's\nlive Quantity, which the holder may change. 0 when the period is unpaid.","format":"int64","type":"integer"},"settled":{"description":"Settled is how the period in hand was paid: \"card\" (a card paid all of it),\n\"external:\u003cprocessor\u003e\" (a payment recorded as collected outside commerce),\n\"balance\", \"credit\" or \"mixed\" (prepaid money). Empty when unpaid or unknown.","type":"string"},"status":{"description":"Status is trialing, active, past_due, canceled or unpaid. Only active and\ntrialing confer the plan.","type":"string"},"test":{"description":"Test marks a sandbox subscription: sold while its org was in test mode, paid\nwith sandbox money. It is listed and never revenue.","type":"boolean"},"trialEnd":{"description":"TrialEnd is when that trial ends; absent when there was none.","type":"string"},"trialStart":{"description":"TrialStart is when a trial began; absent when there was none.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the row last changed, RFC 3339.","type":"string"},"userId":{"description":"UserID is the billing account that holds it: the org slug for an org's own\nplan, \"\u003corg\u003e/\u003cname\u003e\" for a member's.","type":"string"}},"type":"object"},"billing.SubscriptionLine":{"properties":{"name":{"description":"Name is the seat type's display name, e.g. \"Team Premium\".","type":"string"},"pendingQuantity":{"description":"PendingQuantity is the seats of it the next period opens at, when a change\nwaits for the renewal that charges it; absent when none does.","format":"int64","type":"integer"},"plan":{"description":"Plan is the seat type's catalog plan, e.g. \"team-premium\".","type":"string"},"price":{"description":"Price is one seat of it for the row's period, in cents.","format":"int64","type":"integer"},"quantity":{"description":"Quantity is the seats of it the row holds.","format":"int64","type":"integer"},"seats":{"description":"Seats is the seats of it the period in hand was paid for; 0 when unpaid.","format":"int64","type":"integer"}},"type":"object"},"billing.SubscriptionPlan":{"properties":{"currency":{"description":"Currency is the ISO code the price is in, lower-cased.","type":"string"},"id":{"description":"ID is the plan row the subscription was opened on.","type":"string"},"interval":{"description":"Interval is the billing period: \"month\" or \"year\".","type":"string"},"name":{"description":"Name is the plan's display name, e.g. \"Max 20x\".","type":"string"},"price":{"description":"Price is what one period costs per seat, in cents, as the subscription\nsnapshotted it: a later catalog price change does not move it.","format":"int64","type":"integer"},"slug":{"description":"Slug is the catalog plan it was opened on, e.g. \"max-20x\": what a reader\nmatches against GET /v1/billing/plans. Empty on a row that predates it.","type":"string"}},"type":"object"},"billing.SubscriptionSeat":{"properties":{"member":{"description":"Member is the IAM user who holds the seat, as the org's members list names them.","type":"string"},"plan":{"description":"Plan is the seat type held: \"team\" (standard) or \"team-premium\".","type":"string"}},"type":"object"},"billing.Subscriptions":{"properties":{"count":{"description":"Count is the row count beside the rows, which is the shape this address\nhas always answered with.","format":"int64","type":"integer"},"subscriptions":{"items":{"$ref":"#/components/schemas/billing.Subscription"},"type":"array"}},"type":"object"},"billing.Tier":{"properties":{"balance":{"$ref":"#/components/schemas/billing.TierBalance"},"plan":{"description":"Plan is the catalog rung the subject is served as (\"\" with no plan). A tier\nis a class of rungs; a bound that differs within one class keys on this.","type":"string"},"subscription":{"description":"Subscription is the id of the subscription row whose plan is the served rung,\n\"\" when the tier is not a subscription's.","type":"string"},"tier":{"$ref":"#/components/schemas/billing.TierLimits"},"user":{"type":"string"}},"type":"object"},"billing.TierBalance":{"properties":{"creditsRemaining":{"format":"int64","type":"integer"},"currency":{"type":"string"},"dailyRemaining":{"format":"int64","type":"integer"},"effectiveAvailable":{"format":"int64","type":"integer"},"prepaidAvailable":{"format":"int64","type":"integer"}},"type":"object"},"billing.TierLimits":{"properties":{"allowedModels":{"items":{"type":"string"},"type":"array"},"dailyCreditsCents":{"format":"int64","type":"integer"},"displayName":{"type":"string"},"maxAgents":{"format":"int64","type":"integer"},"name":{"type":"string"},"unlimitedAgents":{"description":"UnlimitedAgents reports that MaxAgents 0 means \"no ceiling\" rather than\n\"no agents\" — the reading a bare zero cannot carry.","type":"boolean"}},"type":"object"},"billing.Transaction":{"properties":{"amount":{"format":"int64","type":"integer"},"createdAt":{"type":"string"},"currency":{"type":"string"},"expiresAt":{"type":"string"},"id":{"type":"string"},"metadata":{},"notes":{"type":"string"},"tags":{"type":"string"},"type":{"type":"string"}},"type":"object"},"billing.Transactions":{"properties":{"count":{"format":"int64","type":"integer"},"transactions":{"items":{"$ref":"#/components/schemas/billing.Transaction"},"type":"array"},"user":{"type":"string"}},"type":"object"},"billing.WireInstructions":{"properties":{"accountName":{"type":"string"},"accountNumber":{"type":"string"},"bankAddress":{"type":"string"},"bankName":{"type":"string"},"iban":{"type":"string"},"memo":{"type":"string"},"reference":{"type":"string"},"routingNumber":{"type":"string"},"swiftCode":{"type":"string"}},"type":"object"},"billing.accounts":{"properties":{"accounts":{"description":"Accounts is one row per linked account the gateway actually routed through.","items":{"$ref":"#/components/schemas/billing.RoutedUsage"},"type":"array"},"scope":{"description":"Scope is always \"user\": the caller's own linked accounts.","type":"string"},"source":{"description":"Source is always \"routed\": the gateway's own routed ledger.","type":"string"},"total":{"$ref":"#/components/schemas/billing.AccountsTotal","description":"Total is the honest sum across the rows."}},"type":"object"},"billing.assignment":{"properties":{"assigned":{"description":"Assigned is every seat assigned: the member, and the seat type (a plan the\nsubscription holds seats of, \"team\" or \"team-premium\") they hold. It\nreplaces what was assigned; an empty list unassigns every seat.","items":{"$ref":"#/components/schemas/billing.SubscriptionSeat"},"type":"array"}},"type":"object"},"billing.cryptoAsset":{"properties":{"amountCents":{"description":"AmountCents is what the payer intends to send, for the record. Optional —\nthe credit is what actually arrives, never what was announced.","format":"int64","type":"integer"},"chain":{"description":"Chain is the network to receive on. Empty takes the rail's default.","type":"string"},"token":{"description":"Token is the asset on that chain. Empty takes the chain's native one.","type":"string"}},"type":"object"},"billing.financeLedgerEntry":{"properties":{"account":{"type":"string"},"balanceCents":{"format":"int64","type":"integer"},"cents":{"format":"int64","type":"integer"},"currency":{"type":"string"},"date":{"type":"string"},"description":{"type":"string"},"id":{"type":"string"}},"type":"object"},"billing.resize":{"properties":{"lines":{"description":"Lines are the team's other seat types and the seats of each:\n[{\"planId\":\"team-premium\",\"quantity\":2}]. A seat type of the team the\nsubscription does not hold yet is added.","items":{"$ref":"#/components/schemas/billing.SaleLine"},"type":"array"},"quantity":{"description":"Quantity is the seats of the subscription's own seat type; 0 keeps them.","format":"int64","type":"integer"}},"type":"object"},"billing.signedPayment":{"properties":{"authorization":{"$ref":"#/components/schemas/billing.GatewayAuthorization","description":"Authorization is the EIP-3009 TransferWithAuthorization as signed: every\nfield a string, addresses and nonce 0x hex, value in USDC base units."},"network":{"description":"Network is the CAIP-2 network the payment was signed for, one of the\nterms' accepts, e.g. \"eip155:8453\".","type":"string"},"salt":{"description":"Salt is the salt the terms issued with the nonce.","type":"string"},"signature":{"description":"Signature is the 65-byte EIP-712 signature, 0x hex.","type":"string"}},"type":"object"},"billing.subscriptionAct":{"properties":{"atPeriodEnd":{"description":"AtPeriodEnd cancels at the end of the paid period rather than at once. It\ndefaults TRUE, because a customer who cancels has already paid for the\nperiod they are in.","type":"boolean"},"id":{"description":"ID is the subscription, from the path.","type":"string"}},"type":"object"},"billing.topupIn":{"properties":{"amountCents":{"description":"AmountCents is how much to charge, in cents of Currency. Required.","format":"int64","type":"integer"},"currency":{"description":"Currency is the ISO-4217 code to charge in. Empty takes the deployment's\nown default.","type":"string"},"paymentMethodId":{"description":"MethodID names a card the subject already saved, for the saved-card endpoint.","type":"string"},"sourceId":{"description":"SourceID is a single-use card token from the payment form, for the token\nendpoint. It is vaulted as part of the charge, so a caller never holds card\nnumbers and this service never sees one.","type":"string"}},"type":"object"},"billing.usageReceipt":{"properties":{"account":{"description":"Account is the wallet the debit drew from, the same key GET\n/v1/billing/balance reports for this caller.","type":"string"},"amount":{"$ref":"#/components/schemas/billing.Money","description":"Amount is the debit, exactly as recorded."},"id":{"description":"ID is the act's name, echoed.","type":"string"},"org":{"description":"Org is the organization whose ledger holds the debit.","type":"string"}},"type":"object"},"billing.usageReport":{"properties":{"amount":{"$ref":"#/components/schemas/billing.Money","description":"Amount is what the act costs, as an exact decimal in USD. It must be\ngreater than zero."},"id":{"description":"ID names the act, chosen by the reporting application and stable across its\nretries: the ledger debits one act once. At most 128 printable characters,\nno whitespace. Reusing an ID for a different amount is a 409.","type":"string"},"model":{"description":"Model names the unit the amount prices (a machine size, a model id), and is\nrecorded with the debit.","type":"string"},"org":{"description":"Org is the organization this usage is billed to. It must be the org the\ntoken acts in — the application's own, or one that granted it membership and\nis selected with X-Org-Id — and any other is refused before money moves.","type":"string"},"project":{"description":"Project attributes the debit to one project of the org. Empty is the org's\ndefault project.","type":"string"},"service":{"description":"Service scopes the debit for spend caps and attributes it to a product, as\na lowercase slug. Empty takes the reporting application's name.","type":"string"}},"type":"object"},"blueprint.RateCard":{"properties":{"basis":{"description":"Basis names where the rates come from, so a published price can be\nexplained rather than merely asserted.","type":"string"},"microUsdPerGbHour":{"description":"MicroUSDPerGBHour is the price of one GiB of memory for one hour, in\nmillionths of a US dollar.","format":"int64","type":"integer"},"microUsdPerVcpuHour":{"description":"MicroUSDPerVCPUHour is the price of one vCPU for one hour, in millionths of\na US dollar.","format":"int64","type":"integer"}},"type":"object"},"blueprint.blueprintHealth":{"properties":{"blueprints":{"description":"Blueprints is how many blueprints this build has embedded and priced.","format":"int64","type":"integer"},"rateCard":{"$ref":"#/components/schemas/blueprint.RateCard","description":"RateCard is the rate card actually in force after the operator env overlay\n(CLOUD_BLUEPRINT_UCPU_HR / CLOUD_BLUEPRINT_UGB_HR), not the shipped default."},"service":{"description":"Service names the subsystem answering — always \"blueprint\".","type":"string"},"status":{"description":"Status is \"ok\"; the route answers 200 whenever the subsystem is mounted.","type":"string"}},"type":"object"},"blueprint.blueprintIndex":{"properties":{"data":{"description":"Data is one row per embedded blueprint, sorted by template id.","items":{"$ref":"#/components/schemas/blueprint.blueprintRow"},"type":"array"}},"type":"object"},"blueprint.blueprintRow":{"properties":{"estCentsPerMonth":{"description":"CentsPerMonth is the estimated compute cost of running the whole stack for\none month, in USD cents, from the rate card GET /v1/blueprint/health echoes.","format":"int64","type":"integer"},"services":{"description":"Services is how many compose services the stack runs.","format":"int64","type":"integer"},"templateId":{"description":"TemplateID is the blueprint slug — the id GET /v1/blueprint/sbom takes as\n?template= and the path under templates.hanzo.ai/blueprints/\u003cid\u003e/.","type":"string"}},"type":"object"},"books.Account":{"properties":{"name":{"description":"Name is the account's human name, for a statement's line label.","type":"string"},"number":{"description":"Number is the posting key every voucher leg, rule and report references —\nstable, and the reason the chart is a fixed value rather than a table anybody\ncan edit. It looks numeric and is a string: \"1000\" sorts and compares as text.","type":"string"},"party":{"description":"Party marks the account as carrying a SUBLEDGER — receivable is money owed to\nus, payable money we owe — so a leg posted here also writes a payment-ledger\nrow against a counterparty. Absent means no subledger: a bank, wallet, revenue\nor cost account tracks no counterparty at all.","type":"string"},"type":{"description":"Type is the account's fundamental class, which is also its NORMAL balance\nside: asset and expense are debit-normal, liability, income and equity\ncredit-normal.","type":"string"}},"type":"object"},"books.AskRequest":{"properties":{"from":{"description":"From is the RFC3339 start of the metric window. Empty means all time, treated as a\nsingle reporting period (see monthsBetween).","type":"string"},"question":{"description":"Question is the plain-language question about the org's books, e.g. \"what is my\nMRR?\". Longer than 2000 characters is truncated, never refused.","type":"string"},"to":{"description":"To is the RFC3339 end of the metric window. Empty means up to now.","type":"string"}},"type":"object"},"books.AskResponse":{"properties":{"answer":{"description":"Answer is one or two sentences answering the question, every number in it taken\nfrom Figures.","type":"string"},"figures":{"description":"Figures are the grounded numbers the answer states, each already formatted.","items":{"$ref":"#/components/schemas/books.Figure"},"type":"array"},"followups":{"description":"Followups are sharper questions to ask next, chosen from the same intent.","items":{"type":"string"},"type":"array"},"sources":{"description":"Sources name the books reports the figures were computed from — \"pnl\",\n\"position\", \"trial\".","items":{"type":"string"},"type":"array"}},"type":"object"},"books.BalanceLine":{"properties":{"account":{"description":"Account is the chart-of-accounts number this line reports on. ABSENT marks a\nDERIVED line that no account holds — retained earnings is the one such line,\ncomputed from cumulative income minus expense.","type":"string"},"amount":{"description":"Amount is the balance as of the statement date, in whole cents, in its NATURAL\nsign: positive when the account behaved normally, on all three sides. Assets\nare debit-normal and shown as stored; liabilities and equity are credit-normal\nand flipped once here for display. A negative asset is a real overdraft, not a\nsign convention.","format":"int64","type":"integer"},"name":{"description":"Name is the account's human name, or the derived line's own name.","type":"string"},"type":{"description":"Type is the account's fundamental class. Absent on a derived line, which\nbelongs to no account and therefore has none.","type":"string"}},"type":"object"},"books.BalanceSheet":{"properties":{"asOf":{"description":"AsOf is the posting time the statement is taken at, inclusive. A balance sheet\nis a snapshot, not a window, so there is no From. Absent means as of now.","type":"string"},"assets":{"description":"Assets are what the org OWNS at that instant, one line per account that has a\nbalance. Cash, receivables, funds captured but not yet settled.","items":{"$ref":"#/components/schemas/books.BalanceLine"},"type":"array"},"balanced":{"description":"Balanced is whether assets equal liabilities plus equity — the accounting\nequation, computed from the totals above rather than assumed. False means the\nledger is broken, not that the statement is.","type":"boolean"},"equity":{"description":"Equity is what is left over for the owners. It carries a DERIVED retained\nearnings line holding cumulative income minus expense, because this ledger has\nno period close that sweeps the P\u0026L into equity — without that line the\nequation would not close.","items":{"$ref":"#/components/schemas/books.BalanceLine"},"type":"array"},"liabilities":{"description":"Liabilities are what the org OWES — including customers' unspent prepaid\ncredit, which is their money until it is consumed and so is carried here\nrather than counted as revenue.","items":{"$ref":"#/components/schemas/books.BalanceLine"},"type":"array"},"totalAssets":{"description":"TotalAssets is the sum of the asset lines, in cents.","format":"int64","type":"integer"},"totalEquity":{"description":"TotalEquity is the sum of the equity lines including retained earnings, in cents.","format":"int64","type":"integer"},"totalLiabilities":{"description":"TotalLiabilities is the sum of the liability lines, in cents.","format":"int64","type":"integer"}},"type":"object"},"books.BankQuestion":{"properties":{"connector":{"description":"Connector names the feed the unplaceable line arrived on. With externalId it\nidentifies both the question and the bank line it is about, so re-syncing the\nsame deposit never asks twice.","type":"string"},"createdAt":{"description":"CreatedAt is when the question was raised.","type":"string"},"externalId":{"description":"ExternalID is the bank's own id for the line in question.","type":"string"},"prompt":{"description":"Prompt is the question put to the founder in plain language — what this money\nwas, since the books cannot place it on their own.","type":"string"},"status":{"description":"Status is whether the question is still open or has been answered.","type":"string"}},"type":"object"},"books.BankTally":{"properties":{"ingested":{"description":"transactions seen","format":"int64","type":"integer"},"posted":{"description":"vouchers newly posted (outflow + reconciled)","format":"int64","type":"integer"},"questions":{"description":"unmatched inflows that raised a question","format":"int64","type":"integer"},"reconciled":{"description":"inflows cleared against Square-clearing","format":"int64","type":"integer"},"skipped":{"description":"already-processed idempotent no-ops","format":"int64","type":"integer"},"transfers":{"description":"own-account moves recorded (no P\u0026L)","format":"int64","type":"integer"}},"type":"object"},"books.BankTxnRow":{"properties":{"amountCents":{"description":"AmountCents is the size of the movement in whole cents, always POSITIVE —\ndirection carries the sign, so a caller must read both to know which way money\nwent.","format":"int64","type":"integer"},"connector":{"description":"Connector names the feed this row arrived on — which bank or processor\nconnection it was synced from. With externalId it is the row's identity, so\nre-syncing the same statement never books a second copy.","type":"string"},"currency":{"description":"Currency is the ISO code the bank reported the line in.","type":"string"},"description":{"description":"Description is the statement memo as the bank wrote it.","type":"string"},"direction":{"description":"Direction is which way the money moved: an inflow into the account or an\noutflow from it, from the org's point of view.","type":"string"},"externalId":{"description":"ExternalID is the bank's OWN id for the line, carried verbatim. It is unique\nonly within its connector.","type":"string"},"matchedVoucher":{"description":"MatchedVoucher names the ledger voucher this line was reconciled against —\nthe bill it paid, or the settlement it cleared. Absent when nothing matched,\nwhich for an inflow is what raises a question.","type":"string"},"merchant":{"description":"Merchant is the counterparty the feed identified, where it did.","type":"string"},"postedAt":{"description":"PostedAt is the bank's posting date for the line, not when we synced it.","type":"string"},"status":{"description":"Status is where the line got to: posted (an outflow booked straight to an\nexpense), settled (an outflow that paid down a scanned bill), reconciled (an\ninflow that cleared a pending settlement), transfer (a move between the org's\nown accounts, recorded but with no effect on the books), or unmatched (an\ninflow nobody could place, which is waiting on a human answer).","type":"string"}},"type":"object"},"books.BookRequest":{"properties":{"override":{"description":"Override books this bill even when one of the SAME economic identity\n(vendor, total, issue date) already posted — the explicit human confirmation that a\nsame-looking bill is a genuine second spend, not the same receipt re-scanned.","type":"boolean"},"scanId":{"description":"ScanID is the scanned document's file hash, as GET /v1/books/inbox and the scan\ndraft report it. It is the idempotency key: re-booking the same scan writes nothing.","type":"string"},"voucher":{"$ref":"#/components/schemas/books.Voucher","description":"Voucher is the reviewed voucher to post. Its source is FORCED to (scan, scanId)\nserver-side, so it can never be booked under another source's key."}},"type":"object"},"books.BookResponse":{"properties":{"posted":{"description":"Posted is true when this call wrote the voucher, false when the same scan had\nalready booked and nothing was written.","type":"boolean"},"scanId":{"description":"ScanID echoes the scan that was booked.","type":"string"}},"type":"object"},"books.Extracted":{"properties":{"category":{"description":"Category is the expense bucket the SCANNER guessed, as a slug — a hint only.\nVendor rules override it whenever they know better, so this is the model's\nreading and not the account the entry will land on.","type":"string"},"currency":{"description":"Currency is the ISO code the document is denominated in.","type":"string"},"issuedAt":{"description":"IssuedAt is the document's OWN date as YYYY-MM-DD — when the bill was issued,\nwhich is not when it was uploaded or when it will post.","type":"string"},"lineItems":{"description":"LineItems are the individual lines read off the document, where it had any.\nThey need not sum to totalCents: a document may carry lines the scanner could\nnot read, and the total is taken from the total.","items":{"$ref":"#/components/schemas/books.LineItem"},"type":"array"},"merchant":{"description":"Merchant is the supplier as printed on the document.","type":"string"},"note":{"description":"Note is anything else worth carrying from the document that has no field of\nits own.","type":"string"},"taxCents":{"description":"TaxCents is how much of that total is tax, in cents. It is part of totalCents,\nnot additional to it.","format":"int64","type":"integer"},"totalCents":{"description":"TotalCents is the document total in whole cents, tax INCLUDED.","format":"int64","type":"integer"}},"type":"object"},"books.Figure":{"properties":{"label":{"description":"Label names the metric, e.g. \"MRR\" or \"Runway\".","type":"string"},"period":{"description":"Period is the window the figure covers, e.g. \"2026-07\" or \"all-time\".","type":"string"},"value":{"description":"Value is the figure already formatted through books' own money formatter, so a\nconsumer never re-derives it.","type":"string"}},"type":"object"},"books.FinancialPackage":{"properties":{"balanceSheet":{"$ref":"#/components/schemas/books.BalanceSheet","description":"BalanceSheet is struck as of the period END, not the start."},"from":{"description":"From opens the reporting period. Absent means from the beginning of the ledger.","type":"string"},"generatedAt":{"description":"GeneratedAt is when the bundle was assembled — the moment the statements were\nstruck, which is what makes two exports of the same period comparable.","type":"string"},"gl":{"description":"GL is the newest slice of ledger detail, as the audit trail behind the\nstatements. It is CAPPED, so on a busy ledger it is a sample rather than the\nfull support for the figures above.","items":{"$ref":"#/components/schemas/books.GLRow"},"type":"array"},"org":{"description":"Org is the organisation whose books these are — the validated caller's own,\nstamped so a downloaded bundle still says whose it is.","type":"string"},"pnl":{"$ref":"#/components/schemas/books.PnL","description":"PnL is the income statement for the period, on an accrual basis."},"to":{"description":"To closes it. Absent means up to now.","type":"string"},"trialBalance":{"$ref":"#/components/schemas/books.TrialBalance","description":"TrialBalance is the proof the ledger balances over the period."}},"type":"object"},"books.GLRow":{"properties":{"account":{"description":"Account is the chart-of-accounts number this leg posts to.","type":"string"},"against":{"description":"Against names the OTHER accounts in the same voucher — the contra side of this\nleg — so a single row reads as an entry rather than as half of one.","type":"string"},"credit":{"description":"Credit is the amount credited to that account, in whole cents.","format":"int64","type":"integer"},"debit":{"description":"Debit is the amount debited to that account, in whole cents. Exactly one of\ndebit and credit is non-zero on a leg; a negative amount is never used to mean\nthe other side.","format":"int64","type":"integer"},"id":{"description":"ID is the entry's position in the ledger. The ledger is append-only, so ids\nascend with posting order and a higher id is a later entry.","format":"int64","type":"integer"},"postingAt":{"description":"PostingAt is the accounting date this entry belongs to — what the reports\nwindow on, which need not be when the row was written.","type":"string"},"remarks":{"description":"Remarks is the memo carried onto the entry, for a human reading the ledger.","type":"string"},"sourceId":{"description":"SourceID identifies that originating record within its kind.","type":"string"},"sourceKind":{"description":"SourceKind is what caused the posting: a bank line, a scanned document, a\ncommerce sale. With sourceId it traces the entry back to the thing that\nproduced it.","type":"string"}},"type":"object"},"books.InboxItem":{"properties":{"category":{"description":"Category is the expense account the scanner proposed, as a chart number — a\nPROPOSAL, not a posting: nothing is booked until it is accepted.","type":"string"},"confidence":{"description":"Confidence is how sure the scanner is of that reading, and is the signal for\nwhether a person needs to check it before it is booked.","type":"string"},"createdAt":{"description":"CreatedAt is when the document was uploaded.","type":"string"},"extracted":{"$ref":"#/components/schemas/books.Extracted","description":"Extracted is what the scanner read off the document. Absent until it has been\nscanned, so its absence is \"not read yet\", never \"nothing on it\"."},"filename":{"description":"Filename is the name the document was uploaded under, for a person to\nrecognise it by. It is not part of the item's identity.","type":"string"},"id":{"description":"ID is the CONTENT HASH of the uploaded bytes, which is what makes the queue\nidempotent: re-uploading the same document returns this item rather than\nadding a second one. It is also the id the scan of this document carries.","type":"string"},"status":{"description":"Status is where the document is in the queue — unsorted until the scanner has\nread it, and thereafter whether it is waiting on a person or has been booked.","type":"string"},"vendor":{"description":"Vendor is the supplier the scanner identified, surfaced beside the item so a\nqueue renders without opening each document.","type":"string"}},"type":"object"},"books.Leg":{"properties":{"account":{"description":"Account is the chart-of-accounts number this side posts to, e.g. \"5300\".","type":"string"},"credit":{"description":"Credit is the leg's credit in exact cents. Set this or Debit, not both.","format":"int64","type":"integer"},"debit":{"description":"Debit is the leg's debit in exact cents. Set this or Credit, not both.","format":"int64","type":"integer"}},"type":"object"},"books.LineItem":{"properties":{"amountCents":{"description":"AmountCents is that line's amount in whole cents. The scanner is instructed to\nreturn integer cents rather than a decimal, so no float rounding can enter the\nledger through here.","format":"int64","type":"integer"},"description":{"description":"Description is the line as it appears on the document.","type":"string"}},"type":"object"},"books.MetricsResponse":{"properties":{"arr":{"description":"ARR is annualized recurring revenue in cents (MRR × 12).","format":"int64","type":"integer"},"burn":{"description":"Burn is total expense in cents over the period.","format":"int64","type":"integer"},"cash":{"description":"Cash is the bank + processor-clearing balance in cents as of To.","format":"int64","type":"integer"},"cogs":{"description":"COGS is cost of goods sold in cents over the period.","format":"int64","type":"integer"},"deferredRevenue":{"description":"DeferredRevenue is the customer-wallet liability in cents as of To.","format":"int64","type":"integer"},"figures":{"description":"Figures is the same snapshot rendered through books' one money formatter.","items":{"$ref":"#/components/schemas/books.Figure"},"type":"array"},"from":{"description":"From is the RFC3339 start of the reporting window, exclusive; absent for all time.","type":"string"},"grossMarginBps":{"description":"GrossMarginBps is GrossProfit / Revenue in basis points (7000 = 70%).","format":"int64","type":"integer"},"grossProfit":{"description":"GrossProfit is Revenue − COGS, in cents.","format":"int64","type":"integer"},"monthlyBurn":{"description":"MonthlyBurn is net cash burned per month in cents; 0 when not losing cash.","format":"int64","type":"integer"},"months":{"description":"Months is the window length in whole months used to normalize MRR and burn.","format":"int64","type":"integer"},"mrr":{"description":"MRR is monthly recurring revenue in cents.","format":"int64","type":"integer"},"netIncome":{"description":"NetIncome is Revenue − Burn, in cents.","format":"int64","type":"integer"},"period":{"description":"Period is the human window label, e.g. \"2026-07\" or \"all-time\".","type":"string"},"revenue":{"description":"Revenue is recognized revenue in cents over the period.","format":"int64","type":"integer"},"runwayMonths":{"description":"RunwayMonths is Cash / MonthlyBurn; -1 means infinite (the org is not burning).","format":"int64","type":"integer"},"to":{"description":"To is the RFC3339 end of the reporting window, inclusive; absent for up to now.","type":"string"}},"type":"object"},"books.PnL":{"properties":{"expense":{"description":"Expense is the cost lines that moved in the period, one per account.","items":{"$ref":"#/components/schemas/books.PnLLine"},"type":"array"},"from":{"description":"From opens the period and is EXCLUSIVE — movement strictly after it, matching\nthe trial balance's opening boundary so the two reports agree on what belongs\nto a period. Absent means from the beginning of the ledger.","type":"string"},"income":{"description":"Income is the revenue lines that moved in the period, one per account.\nAccounts that did not move are omitted rather than listed at zero.","items":{"$ref":"#/components/schemas/books.PnLLine"},"type":"array"},"netIncome":{"description":"NetIncome is totalIncome minus totalExpense, in cents. Negative is a loss.","format":"int64","type":"integer"},"to":{"description":"To closes the period and is inclusive. Absent means up to now.","type":"string"},"totalExpense":{"description":"TotalExpense is cost MATCHED to that revenue, in cents, including accrued\ninfrastructure that has not been billed yet.","format":"int64","type":"integer"},"totalIncome":{"description":"TotalIncome is revenue RECOGNIZED in the period, in cents — accrual, not cash,\nso a prepaid top-up is not in it until the credit is consumed.","format":"int64","type":"integer"}},"type":"object"},"books.PnLLine":{"properties":{"account":{"description":"Account is the chart-of-accounts number this line reports on.","type":"string"},"amount":{"description":"Amount is the account's movement over the period in whole cents, in its\nNATURAL sign: positive when the account behaved normally, for income and\nexpense alike. Income is credit-normal so its stored net is flipped once here\nfor display; the ledger underneath is never sign-flipped. A negative amount\ntherefore means the account ran backwards — a refunded sale, a reversed cost.","format":"int64","type":"integer"},"name":{"description":"Name is that account's human name from the fixed chart.","type":"string"},"type":{"description":"Type is the account's fundamental class, which on this statement is always\nincome or expense — it tells a reader which half of the statement the line\ncame from without re-deriving it from the array it arrived in.","type":"string"}},"type":"object"},"books.Question":{"properties":{"account":{"description":"Account is the chart number the questioned entry posted to, where one applies.","type":"string"},"amount":{"description":"Amount is the figure that makes the question concrete, already FORMATTED for\ndisplay with its currency symbol — a string, not cents, and not for arithmetic.","type":"string"},"id":{"description":"ID is the source transaction the question is about, so answering it leads\nstraight back to the entry that raised it.","type":"string"},"kind":{"description":"Kind is what looked wrong: outlier (a charge far above the usual), reversal (a\nposting undone), roundoff (a balancing plug big enough to be worth explaining),\nuncosted (revenue booked with no cost matched to it), or overdrawn (a wallet\nspent past its balance).","type":"string"},"postedAt":{"description":"PostedAt anchors the question in time — when the entry it concerns posted.","type":"string"},"text":{"description":"Text is the question itself, written for a founder to answer directly.","type":"string"}},"type":"object"},"books.QuestionsResponse":{"properties":{"questions":{"description":"Questions are what the books want explained, SHARPEST FIRST — largest amounts\nahead of smaller ones, and capped, so this is the top of the list rather than\neverything. Empty means the ledger looks clean; the detector is deterministic\nover what was posted and invents nothing.","items":{"$ref":"#/components/schemas/books.Question"},"type":"array"}},"type":"object"},"books.Rule":{"properties":{"category":{"description":"Category is the COA expense account a matching bill books to. An upsert normalizes\na slug (\"cloud\") to its account number.","type":"string"},"pattern":{"description":"Pattern is the merchant substring the rule matches on, case-insensitively. It is\nalso the key an upsert writes by.","type":"string"},"priority":{"description":"Priority breaks ties: when several patterns match, the highest wins.","format":"int64","type":"integer"}},"type":"object"},"books.TrialBalance":{"properties":{"balanced":{"description":"Balanced is the proof this report exists to give: whether total debits equal\ntotal credits. It is computed from the rows above, never assumed, and false\nmeans the ledger itself is broken rather than that the report is wrong.","type":"boolean"},"from":{"description":"From is the posting time the window opens at, as it was asked for. Absent\nmeans the report runs from the beginning of the ledger.","type":"string"},"rows":{"description":"Rows are the accounts that MOVED in one of the windows. An account that never\nmoved is omitted rather than listed at zero, so this is shorter than the chart.","items":{"$ref":"#/components/schemas/books.TrialBalanceRow"},"type":"array"},"to":{"description":"To is the posting time the window closes at, inclusive. Absent means \"up to\nnow\" — every posting the ledger holds.","type":"string"},"totalCredit":{"description":"TotalCredit is the sum of every row's closing credit column, in cents.","format":"int64","type":"integer"},"totalDebit":{"description":"TotalDebit is the sum of every row's CLOSING debit column, in cents.","format":"int64","type":"integer"}},"type":"object"},"books.TrialBalanceRow":{"properties":{"account":{"description":"Account is the chart-of-accounts NUMBER this line reports on (\"1000\", \"4000\")\n— the stable posting key, not a display label.","type":"string"},"closingCredit":{"description":"ClosingCredit is that closing balance in cents when it is a credit balance.","format":"int64","type":"integer"},"closingDebit":{"description":"ClosingDebit is the balance at the end of the window, in cents, when it is a\ndebit balance. This is the column the report's totals are summed from.","format":"int64","type":"integer"},"credit":{"description":"Credit is the same window movement in cents when it was net credit.","format":"int64","type":"integer"},"debit":{"description":"Debit is the account's MOVEMENT within the window — closing minus opening, not\nthe closing balance — in cents, when that movement was net debit. Zero when the\naccount moved net credit.","format":"int64","type":"integer"},"name":{"description":"Name is that account's human name from the fixed chart.","type":"string"},"openingCredit":{"description":"OpeningCredit is the same opening balance in cents when it fell on the credit\nside. Zero when the balance was a debit one.","format":"int64","type":"integer"},"openingDebit":{"description":"OpeningDebit is the account's balance before the window began, in whole cents,\nwhen that balance was on the debit side. Zero when the balance was a credit\none — the pair is exclusive, never two halves of one number.","format":"int64","type":"integer"},"type":{"description":"Type is the account's fundamental class — asset, liability, income, expense or\nequity — which is also its normal balance side. It is carried for presentation\nand does NOT decide which column an amount lands in: placement follows the\nsign of the real net, so a contra balance shows up as one.","type":"string"}},"type":"object"},"books.Txn":{"properties":{"amountCents":{"description":"AmountCents is the voucher's total, in whole cents — its total debit, which\nequals its total credit because every voucher balances. It is the size of the\nentry and carries no direction; the category says which way it went.","format":"int64","type":"integer"},"category":{"description":"Category is the chart-of-accounts NUMBER of the income or expense account this\nvoucher touched — where it lands on the P\u0026L, not a free-text label.","type":"string"},"categoryName":{"description":"CategoryName is that account's human name, so a caller need not carry the\nchart to render the row.","type":"string"},"date":{"description":"Date is when the voucher POSTED — the accounting date the reports window on,\nwhich for an imported bank row is the bank's date and not the day it landed\nhere.","type":"string"},"description":{"description":"Description is the line a person reads: the memo carried in from the source.","type":"string"},"source":{"description":"Source is where the entry came from: bank_txn for an imported statement line,\nscan for a receipt or bill read by the scanner, commerce_txn for a sale\nbooked by the store.","type":"string"},"vendor":{"description":"Vendor is the counterparty, resolved from whatever the source knew — a bank\nrow's merchant, a scanned bill's supplier. Absent when the source named none.","type":"string"},"voucherId":{"description":"VoucherID identifies the underlying double-entry voucher, so a caller can open\nthe full set of legs behind this single register line.","format":"int64","type":"integer"}},"type":"object"},"books.VendorRow":{"properties":{"aliases":{"description":"Aliases are the other spellings a receipt may print the vendor under; a scan\nmatching any of them resolves to this vendor.","items":{"type":"string"},"type":"array"},"canonical":{"description":"Canonical is the vendor's one true name, and the key an upsert writes by.","type":"string"},"defaultCategory":{"description":"DefaultCategory is the COA expense account new bills from this vendor book to.\nAn upsert normalizes a slug (\"software\") to its account number.","type":"string"}},"type":"object"},"books.Voucher":{"properties":{"description":{"description":"Description is the human line for the event, e.g. the vendor a bill came from.","type":"string"},"legs":{"description":"Legs are the sides of the posting. They must balance: Σdebit == Σcredit, give or\ntake the 2¢ round-off allowance.","items":{"$ref":"#/components/schemas/books.Leg"},"type":"array"},"postingAt":{"description":"PostingAt is the RFC3339 instant the event posts at — the time every statement\nwindow filters on.","type":"string"},"sourceId":{"description":"SourceID is the source event's own id within that namespace. Together with\nSourceKind it is the key that makes a repeat posting a no-op.","type":"string"},"sourceKind":{"description":"SourceKind is the idempotency namespace naming what booked this, e.g. \"scan\".","type":"string"}},"type":"object"},"books.inboxOut":{"properties":{"items":{"description":"Items is every document still unsorted or in draft, newest first.","items":{"$ref":"#/components/schemas/books.InboxItem"},"type":"array"}},"type":"object"},"books.rulesOut":{"properties":{"rules":{"description":"Rules is every rule the org has set, highest priority first — the order they\nare matched in.","items":{"$ref":"#/components/schemas/books.Rule"},"type":"array"}},"type":"object"},"books.syncTally":{"properties":{"live":{"description":"Live is the number of vouchers newly posted to the live ledger.","format":"int64","type":"integer"},"sandbox":{"description":"Sandbox is the number newly posted to the sandbox ledger.","format":"int64","type":"integer"}},"type":"object"},"books.transactionsOut":{"properties":{"transactions":{"description":"Transactions is the matching register rows, newest first.","items":{"$ref":"#/components/schemas/books.Txn"},"type":"array"}},"type":"object"},"books.unreconciledOut":{"properties":{"questions":{"description":"Questions is the open clarifying question per unmatched inflow.","items":{"$ref":"#/components/schemas/books.BankQuestion"},"type":"array"},"transactions":{"description":"Transactions is every bank row still unmatched against the ledger.","items":{"$ref":"#/components/schemas/books.BankTxnRow"},"type":"array"}},"type":"object"},"books.vendorsOut":{"properties":{"vendors":{"description":"Vendors is every vendor the org has recorded, canonical name ascending.","items":{"$ref":"#/components/schemas/books.VendorRow"},"type":"array"}},"type":"object"},"bot.BotMember":{"properties":{"active":{"description":"Active is whether the agent projects as a LIVE space member, derived from\nits registry status: empty, \"active\" and \"ready\" are live, anything else\n(archived/retired) is not. An inactive bot drops out of the roster while its\npast authorship survives.","type":"boolean"},"id":{"description":"ID is the agent id.","type":"string"},"name":{"description":"Name is the display name.","type":"string"},"personRef":{"description":"PersonRef is the projected Person _id.","type":"string"},"userId":{"description":"UserID is the derived member account uuid (personUuid).","type":"string"}},"type":"object"},"bot.BotRoster":{"properties":{"bots":{"description":"Bots is one entry per bot, each carrying the member account uuid and the\nPerson reference the space roster addresses it by. Empty means the org has\nno bots — not that the roster could not be read, which is an error.","items":{"$ref":"#/components/schemas/bot.BotMember"},"type":"array"}},"type":"object"},"bot.BotRun":{"properties":{"runId":{"description":"RunID is the run's id in the bot runtime, and the node id its live VNC session\nis registered under.","type":"string"},"sessionUrl":{"description":"SessionURL is the live session the hanzo.app /vnc panel embeds to watch or\nattach to this run. Derived here from the run id, never sent by the runtime.","type":"string"},"startedAt":{"description":"StartedAt is when the run began, RFC 3339, as the runtime stamped it.","type":"string"},"status":{"description":"Status is the run's state as the runtime reports it; \"running\" when the runtime\nnames none of its own.","type":"string"},"surface":{"description":"Surface is what the bot drives: the desktop or terminal sandbox it runs in.","type":"string"},"task":{"description":"Task is the instruction the bot is executing.","type":"string"}},"type":"object"},"bot.BotRuns":{"properties":{"bots":{"description":"Bots is the org's live runs. Always an array, never null.","items":{"$ref":"#/components/schemas/bot.BotRun"},"type":"array"}},"type":"object"},"bot.BotStopped":{"properties":{"runId":{"description":"RunID is the run that was stopped.","type":"string"},"status":{"description":"Status is the run's terminal state: \"stopped\".","type":"string"}},"type":"object"},"bot.BotSync":{"properties":{"projected":{"description":"Projected is how many roster entries the reconcile touched.","format":"int64","type":"integer"},"synced":{"description":"Synced is true when the reconcile ran.","type":"boolean"}},"type":"object"},"browserTagOut":{"properties":{"events":{"additionalProperties":{"type":"string"},"type":"object"},"id":{"type":"string"},"platform":{"type":"string"},"type":{"type":"string"}},"type":"object"},"buildRef":{"properties":{"id":{"type":"string"},"image":{"type":"string"},"job":{"type":"string"},"ref":{"type":"string"},"repo":{"type":"string"},"status":{"type":"string"}},"type":"object"},"campaign.ChannelMetric":{"properties":{"externalId":{"description":"ExternalID is the provider-side id of the execution the spend belongs to.\nAbsent until the channel has launched.","type":"string"},"kind":{"description":"Kind is which channel this row is: paid, organic or email. It is also the\nrow's identity — a campaign carries at most one channel per kind.","type":"string"},"platform":{"description":"Platform is the provider the spend was read from: meta, google, x, instagram,\nor the email provider.","type":"string"},"spendCents":{"description":"SpendCents is what the provider itself reports this channel spent, in CENTS.\n0 when the channel never launched, when no executor is wired for it, or when\nthe read failed — SpendError tells the last case apart from a genuine zero.","format":"int64","type":"integer"},"spendError":{"description":"SpendError is why this channel's spend could not be read (connector not\nconnected, provider error), as one secret-free line. Present only on failure;\nthe campaign total then simply omits this channel rather than failing.","type":"string"},"status":{"description":"Status is the channel's launch state on the campaign — pending, live, paused,\nfailed or unavailable. Only a live channel is asked for its spend at all.","type":"string"}},"type":"object"},"campaign.ChannelSpec":{"properties":{"account":{"description":"Account is the provider account this channel runs under: an ad-account, a page\nor a mailing-list id. An executor may replace it at launch with the account it\nactually used.","type":"string"},"detail":{"description":"Detail is the last outcome in one secret-free line — the failure reason, or\nwhat the executor reported. Absent when there is nothing to explain.","type":"string"},"externalId":{"description":"ExternalID is the provider-side id of the running execution, recorded by the\norchestrator at launch and handed back verbatim to read spend or to pause.\nServer-owned and absent until this channel has launched; anything a caller\nsends for it is dropped.","type":"string"},"kind":{"description":"Kind is the channel and the identity a campaign holds at most one of: paid,\norganic or email. It picks the executor the launch fans out to.","type":"string"},"platform":{"description":"Platform is the provider within the kind — meta, google, x, instagram, or the\nemail provider.","type":"string"},"status":{"description":"Status is this channel's own launch outcome, not the campaign's: pending (added,\nnever launched), live, paused, failed (Detail says why) or unavailable (no\nexecutor wired on this deployment). Server-owned — a caller can never assert it.","type":"string"}},"type":"object"},"campaign.campaignPage":{"properties":{"data":{"description":"Data are the campaigns on this page.","items":{"$ref":"#/components/schemas/campaign.campaignRecord"},"type":"array"}},"type":"object"},"campaign.campaignRecord":{"properties":{"audience":{"description":"Audience is an opaque reference to the segment this campaign targets. It is\nstored and echoed but not yet handed to the executors — a channel targets\nthrough the provider account it runs under — so it is documentation for now.\nAbsent when never set.","type":"string"},"budget":{"description":"Budget is the campaign's total budget in CENTS, handed to each executor as the\nbudget for its channel. 0 means none was set.","format":"int64","type":"integer"},"channels":{"description":"Channels are the fan-out targets, at most one per kind and at most 12, each\ncarrying its own post-launch state. Empty means nothing to launch, which is\nwhat makes a launch of this campaign a 400.","items":{"$ref":"#/components/schemas/campaign.ChannelSpec"},"type":"array"},"content":{"description":"Content is the ordered creative set, at most 32, empty entries dropped.\nContent[0] is the creative that runs; the rest are A/B variants a wired\nexperiment can assign per launch.","items":{"type":"string"},"type":"array"},"createdAt":{"description":"CreatedAt is when the campaign was created, in unix seconds. Server-set.","format":"int64","type":"integer"},"id":{"description":"ID is the campaign's server-minted handle — \"cmp_\" and 128 random bits — and\nthe id every other campaign call is addressed by. Never read off the wire: a\ncreate that sends one has it ignored.","type":"string"},"name":{"description":"Name is the campaign's display name. Required on write, trimmed, and capped at\n2048 characters.","type":"string"},"scheduleAt":{"description":"ScheduleAt is when the campaign should run, in unix seconds. 0 (absent) means\nlaunch immediately. It is passed to each executor; nothing in this service\nwakes up to launch it for you.","format":"int64","type":"integer"},"status":{"description":"Status is the lifecycle state, server-owned and never accepted from a caller.\nFour values actually occur: draft (inert and fully mutable — nothing is sent\nand no budget is committed), live, paused and failed. After a fan-out live\nmeans AT LEAST ONE channel launched — read the channel rows for the rest —\nand failed means none did.","type":"string"},"updatedAt":{"description":"UpdatedAt is the last write in unix seconds — an edit, a launch or a pause.\nServer-set on every save.","format":"int64","type":"integer"}},"type":"object"},"campaign.campaignResults":{"properties":{"abTest":{"description":"ABTest is the creative A/B analysis from the experiments primitive\n(experiment.Analyze, pull-model), present only when the campaign runs\nmore than one creative and an experiment is wired. Opaque JSON — campaign\nstays decoupled from the experiments analysis type."},"available":{"description":"Available is false when the analytics warehouse is not connected or the query\nfailed: the funnel below is then zero because nothing could be read, not\nbecause nothing happened. Spend and Channels are still real — they come from\nthe connectors, not the warehouse.","type":"boolean"},"cac":{"description":"CAC is customer acquisition cost: spend DOLLARS per conversion, rounded to\ncents. 0 when nothing converted — that is \"not yet computable\", not \"free\".","format":"double","type":"number"},"campaignId":{"description":"CampaignID is the campaign these results are for, echoed from the request.","type":"string"},"channels":{"description":"Channels is the per-channel spend breakdown that SpendCents sums, one row per\nchannel on the campaign including the ones that never launched.","items":{"$ref":"#/components/schemas/campaign.ChannelMetric"},"type":"array"},"clicks":{"description":"Clicks is the campaign's click events over the window.","format":"int64","type":"integer"},"conversions":{"description":"Conversions is the terminal funnel events attributed to the campaign — orders\ncompleted, signups completed, explicit conversion events.","format":"int64","type":"integer"},"ctr":{"description":"CTR is clicks per impression, a fraction rounded to 4 places (0.0123 = 1.23%),\nnot a percentage. 0 when there were no impressions to divide by.","format":"double","type":"number"},"cvr":{"description":"CVR is conversions per click, a fraction rounded to 4 places. 0 when there\nwere no clicks.","format":"double","type":"number"},"end":{"description":"End is the window's end, RFC3339 UTC — the read's own clock unless an explicit\npair was given. The window is a LOOKBACK, not the campaign's own lifetime.","type":"string"},"impressions":{"description":"Impressions is how many times the campaign's creatives were shown, counted\nfrom its utm_campaign-tagged impression events.","format":"int64","type":"integer"},"name":{"description":"Name is the campaign's display name at read time, so a result can be labelled\nwithout a second fetch.","type":"string"},"range":{"description":"Range is the window actually used: 24h, 7d, 30d, 90d, or \"custom\" when an\nexplicit start/end pair was honored. An unparseable or absent range reads 30d,\nso this is the value to trust, not the one that was sent.","type":"string"},"revenue":{"description":"Revenue is the summed revenue attribute of the campaign's events, in whole\nCURRENCY UNITS (dollars) — the one money value here that is not in cents.","format":"double","type":"number"},"roas":{"description":"ROAS is return on ad spend: revenue per spend DOLLAR, rounded to 2 places\n(2.5 = $2.50 back per $1). 0 when nothing was spent.","format":"double","type":"number"},"source":{"description":"Source names the analytics table the funnel was read from, so an operator can\nsee exactly what was counted. Set even when Available is false.","type":"string"},"spendCents":{"description":"SpendCents is the campaign's total spend in CENTS: the sum of what each live\nchannel's provider reports. A channel whose spend could not be read\ncontributes 0 and says so on its own row.","format":"int64","type":"integer"},"start":{"description":"Start is the window's inclusive start, RFC3339 UTC.","type":"string"},"status":{"description":"Status is the campaign's lifecycle state at read time — draft, live, paused,\ncompleted or failed. A draft has never run, so its funnel is legitimately zero.","type":"string"},"visitors":{"description":"Visitors is how many distinct people the campaign reached, counted by event\nidentity across ALL its events in the window — not a subset of Impressions, so\nit can exceed them for a campaign whose provider reports clicks but not views.","format":"int64","type":"integer"}},"type":"object"},"campaign.campaignSummary":{"properties":{"budget":{"description":"Budget is the sum of every campaign's budget, in CENTS.","format":"int64","type":"integer"},"campaigns":{"description":"Campaigns is how many campaigns the org has, in any state.","format":"int64","type":"integer"},"channels":{"description":"Channels are the channel kinds this deployment has an executor wired for.\nA kind absent here is a kind a launch will honestly record as unavailable.","items":{"type":"string"},"type":"array"},"live":{"description":"Live is how many of them are currently live.","format":"int64","type":"integer"}},"type":"object"},"campaign.campaignUpdate":{"properties":{"audience":{"description":"Audience is the segment or audience selector this campaign targets.","type":"string"},"budget":{"description":"Budget is the campaign's total budget in CENTS. Negative reads as 0.","format":"int64","type":"integer"},"channels":{"description":"Channels are the fan-out targets, at most one per kind (paid, organic,\nemail) and at most 12. A channel's status and provider id are server-owned:\nwhatever the caller sends for them is replaced with \"pending\".","items":{"$ref":"#/components/schemas/campaign.ChannelSpec"},"type":"array"},"content":{"description":"Content is the ordered creative set. Content[0] is the active creative and\nthe rest are A/B variants; at most 32, empty entries dropped.","items":{"type":"string"},"type":"array"},"id":{"description":"ID is the campaign to update, from the path.","type":"string"},"name":{"description":"Name is the campaign's display name. Required; trimmed and capped at 2048\ncharacters.","type":"string"},"scheduleAt":{"description":"ScheduleAt is when the campaign should run, in unix seconds. Negative reads\nas 0 (immediately).","format":"int64","type":"integer"}},"type":"object"},"campaign.campaignWrite":{"properties":{"audience":{"description":"Audience is the segment or audience selector this campaign targets.","type":"string"},"budget":{"description":"Budget is the campaign's total budget in CENTS. Negative reads as 0.","format":"int64","type":"integer"},"channels":{"description":"Channels are the fan-out targets, at most one per kind (paid, organic,\nemail) and at most 12. A channel's status and provider id are server-owned:\nwhatever the caller sends for them is replaced with \"pending\".","items":{"$ref":"#/components/schemas/campaign.ChannelSpec"},"type":"array"},"content":{"description":"Content is the ordered creative set. Content[0] is the active creative and\nthe rest are A/B variants; at most 32, empty entries dropped.","items":{"type":"string"},"type":"array"},"name":{"description":"Name is the campaign's display name. Required; trimmed and capped at 2048\ncharacters.","type":"string"},"scheduleAt":{"description":"ScheduleAt is when the campaign should run, in unix seconds. Negative reads\nas 0 (immediately).","format":"int64","type":"integer"}},"type":"object"},"campaign.channelAdd":{"properties":{"account":{"description":"Account is the provider account this channel runs under: an ad-account, a\npage, or a mailing-list id.","type":"string"},"id":{"description":"ID is the campaign to add the channel to, from the path.","type":"string"},"kind":{"description":"Kind is the channel kind and the identity a campaign holds at most one of:\npaid, organic or email.","type":"string"},"platform":{"description":"Platform is the provider within the kind — meta, google, x, instagram, or\nthe email provider.","type":"string"}},"type":"object"},"captable.captableClassHolding":{"properties":{"authorized":{"description":"Authorized is how many shares of the class are authorized.","format":"int64","type":"integer"},"classType":{"description":"ClassType is COMMON or PREFERRED.","type":"string"},"issued":{"description":"Issued is how many shares of the class have been issued.","format":"int64","type":"integer"},"name":{"description":"Name is the class name.","type":"string"},"shareClassId":{"description":"ShareClassID addresses the class this position is for.","type":"string"}},"type":"object"},"captable.captableCompany":{"properties":{"createdAt":{"description":"CreatedAt is when the company row was seeded, in unix milliseconds.","format":"int64","type":"integer"},"id":{"description":"ID is the company id, which is the tenant's own org id.","type":"string"},"incorporationCountry":{"description":"IncorporationCountry is the ISO country the entity is incorporated in.","type":"string"},"incorporationState":{"description":"IncorporationState is the state or province of incorporation.","type":"string"},"incorporationType":{"description":"IncorporationType is the entity kind, e.g. LLC or C_CORP.","type":"string"},"name":{"description":"Name is the company's legal name.","type":"string"},"publicId":{"description":"PublicID is the company's shareable public identifier.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the company row last changed, in unix milliseconds.","format":"int64","type":"integer"}},"type":"object"},"captable.captableCompanyUpdate":{"properties":{"incorporationCountry":{"description":"IncorporationCountry is the ISO country the entity is incorporated in.\nOptional; omitted, null or empty clears it. Any JSON scalar is accepted\nand stored as its text."},"incorporationState":{"description":"IncorporationState is the state or province of incorporation. Optional;\nomitted, null or empty clears it. Any JSON scalar is accepted and stored\nas its text."},"incorporationType":{"description":"IncorporationType is the entity kind, e.g. LLC or C_CORP. Optional;\nomitted, null or empty clears it. Any JSON scalar is accepted and stored\nas its text."},"name":{"description":"Name is the company's legal name. Required, and it must be a non-empty\nstring — anything else is refused with the cap table's own validation\nerror."}},"type":"object"},"captable.captableConvertibleIn":{"properties":{"additionalTerms":{"description":"AdditionalTerms is free text for anything the fields above do not carry. Optional."},"boardApprovalDate":{"description":"BoardApprovalDate is when the board approved it, YYYY-MM-DD."},"capital":{"description":"Capital is the principal lent, in the company's currency."},"conversionCap":{"description":"ConversionCap is the valuation the note converts at, at most. Optional."},"discountRate":{"description":"DiscountRate is the discount to the next round's price, as a percentage. Optional."},"interestRate":{"description":"InterestRate is the annual interest the principal accrues, as a percentage. Optional."},"issueDate":{"description":"IssueDate is when the note was issued, YYYY-MM-DD."},"publicId":{"description":"PublicID is the note's identifier. It must be UNIQUE within the company; reusing one is refused 409."},"stakeholderId":{"description":"StakeholderID is the lender. It must name a stakeholder of THIS company."},"status":{"description":"Status is DRAFT, ACTIVE, PENDING, EXPIRED or CANCELLED."},"type":{"description":"Type is CCD, OCD or NOTE."}},"type":"object"},"captable.captableConvertibles":{"properties":{"notes":{"$ref":"#/components/schemas/captable.captableInstrumentTotal","description":"Notes is the convertible notes total."},"safes":{"$ref":"#/components/schemas/captable.captableInstrumentTotal","description":"Safes is the SAFEs total."}},"type":"object"},"captable.captableCreated":{"properties":{"id":{"description":"ID is the created row's id.","type":"string"},"message":{"description":"Message is the human sentence the cap table wrote, e.g. \"Share issued\".","type":"string"},"success":{"description":"Success is true when the row was written.","type":"boolean"}},"type":"object"},"captable.captableDeleted":{"properties":{"success":{"description":"Success is true when the row was removed.","type":"boolean"}},"type":"object"},"captable.captableEquityPlan":{"properties":{"boardApprovalDate":{"description":"BoardApprovalDate is the ISO date the board approved the plan.","type":"string"},"comments":{"description":"Comments is free-form notes on the plan.","type":"string"},"createdAt":{"description":"CreatedAt is when the plan was recorded, in unix milliseconds.","format":"int64","type":"integer"},"defaultCancellatonBehavior":{"description":"DefaultCancellatonBehavior is what happens to cancelled grants, RETIRE or\nRETURN_TO_POOL. The key is spelled as the cap-table wire spells it.","type":"string"},"id":{"description":"ID is the equity plan id.","type":"string"},"initialSharesReserved":{"description":"InitialSharesReserved is how many shares the plan reserves.","format":"int64","type":"integer"},"name":{"description":"Name is the plan name, e.g. \"2026 Stock Option Plan\".","type":"string"},"planEffectiveDate":{"description":"PlanEffectiveDate is the ISO date the plan takes effect.","type":"string"},"shareClassId":{"description":"ShareClassID is the class the reserved shares come from.","type":"string"}},"type":"object"},"captable.captableEquityPlanIn":{"properties":{"boardApprovalDate":{"description":"BoardApprovalDate is when the board adopted the plan, YYYY-MM-DD."},"comments":{"description":"Comments is a free-text note kept with the plan. Optional."},"defaultCancellatonBehavior":{"description":"DefaultCancellatonBehavior is what happens to cancelled grants: RETIRE, RETURN_TO_POOL, HOLD_AS_CAPITAL_STOCK or DEFINED_PER_PLAN_SECURITY.\n\nThe key is spelled `defaultCancellatonBehavior` — one `l` — because that is\nthe wire, and correcting it here would silently drop the field."},"initialSharesReserved":{"description":"InitialSharesReserved is how many shares the plan may grant. A whole number."},"name":{"description":"Name is the plan's name, e.g. \"2026 Stock Option Plan\"."},"planEffectiveDate":{"description":"PlanEffectiveDate is when the plan takes effect, YYYY-MM-DD. Optional."},"shareClassId":{"description":"ShareClassID is the class the plan grants from. It must name a class of THIS company."}},"type":"object"},"captable.captableEquityPlans":{"properties":{"data":{"description":"Data is every equity plan on the caller org's cap table, newest first.","items":{"$ref":"#/components/schemas/captable.captableEquityPlan"},"type":"array"}},"type":"object"},"captable.captableHolding":{"properties":{"fullyDiluted":{"description":"FullyDiluted is shares plus options.","format":"int64","type":"integer"},"name":{"description":"Name is the stakeholder's name.","type":"string"},"options":{"description":"Options is the shares under this stakeholder's non-terminal option grants.","format":"int64","type":"integer"},"ownershipPct":{"description":"OwnershipPct is fullyDiluted as a percentage of the company's\nfullyDilutedShares, rounded to two decimals; 0 when nothing is issued.","format":"double","type":"number"},"shares":{"description":"Shares is the shares this stakeholder holds by certificate.","format":"int64","type":"integer"},"stakeholderId":{"description":"StakeholderID addresses the stakeholder these totals are for.","type":"string"}},"type":"object"},"captable.captableInstrumentTotal":{"properties":{"capital":{"description":"Capital is the total capital across those instruments.","format":"double","type":"number"},"count":{"description":"Count is how many instruments there are.","format":"int64","type":"integer"}},"type":"object"},"captable.captableInvested":{"properties":{"id":{"description":"ID is the investment record's id.","type":"string"},"message":{"description":"Message is the human sentence the cap table wrote.","type":"string"},"newShareId":{"description":"NewShareID names the certificate the investment issued, when the round\ncarries a price per share. Null when the round prices later, which is a\nrecorded investment and not a failure.","type":"string"},"success":{"description":"Success is true when the investment was recorded.","type":"boolean"}},"type":"object"},"captable.captableInvestment":{"properties":{"amount":{"description":"Amount is the cash invested.","format":"double","type":"number"},"date":{"description":"Date is the ISO date of the investment.","type":"string"},"id":{"description":"ID is the investment id.","type":"string"},"roundId":{"description":"RoundID is the round the cheque went into.","type":"string"},"shareClassId":{"description":"ShareClassID is the class shares were issued in, for a priced round.","type":"string"},"shares":{"description":"Shares is how many shares the investment bought; 0 when the round issues\nno equity at the time of investment.","format":"int64","type":"integer"},"stakeholderId":{"description":"StakeholderID is the investor.","type":"string"},"stakeholderName":{"description":"StakeholderName is that investor's name.","type":"string"}},"type":"object"},"captable.captableInvestmentIn":{"properties":{"amount":{"description":"Amount is the money invested, in the round's own currency. Required and must\nbe positive."},"comments":{"description":"Comments is a free-text note kept with the investment. Optional."},"date":{"description":"Date is when the investment was made, YYYY-MM-DD. Optional: omitted, it is\nrecorded as today."},"id":{"description":"ID is the round to invest in. The URL is the addressing authority — a path\nsegment binds after the body and after the query — so the address decides\nwhich round is written whatever a body claims.","type":"string"},"stakeholderId":{"description":"StakeholderID is the investor. Required, and it must reference a stakeholder\nof the same company."}},"type":"object"},"captable.captableInvestments":{"properties":{"data":{"description":"Data is every investment across every round, newest first.","items":{"$ref":"#/components/schemas/captable.captableInvestment"},"type":"array"}},"type":"object"},"captable.captableNote":{"properties":{"capital":{"description":"Capital is the principal the investor lent.","format":"double","type":"number"},"conversionCap":{"description":"ConversionCap is the valuation cap on conversion, if any.","format":"double","type":"number"},"discountRate":{"description":"DiscountRate is the discount to the next round's price, if any.","format":"double","type":"number"},"id":{"description":"ID is the note id.","type":"string"},"interestRate":{"description":"InterestRate is the annual interest rate, if any.","format":"double","type":"number"},"issueDate":{"description":"IssueDate is the ISO date the note was signed.","type":"string"},"publicId":{"description":"PublicID is the note's shareable identifier, unique within the company.","type":"string"},"stakeholderId":{"description":"StakeholderID is the investor.","type":"string"},"stakeholderName":{"description":"StakeholderName is that investor's name.","type":"string"},"status":{"description":"Status is the note's state, e.g. DRAFT or ACTIVE.","type":"string"},"type":{"description":"Type is the instrument kind, e.g. NOTE.","type":"string"}},"type":"object"},"captable.captableNotes":{"properties":{"data":{"description":"Data is every convertible note, newest first.","items":{"$ref":"#/components/schemas/captable.captableNote"},"type":"array"}},"type":"object"},"captable.captableOption":{"properties":{"cliffYears":{"description":"CliffYears is how many years before any of the grant vests.","format":"int64","type":"integer"},"equityPlanId":{"description":"EquityPlanID is the plan the grant draws from.","type":"string"},"equityPlanName":{"description":"EquityPlanName is that plan's name.","type":"string"},"exercisePrice":{"description":"ExercisePrice is the strike price per share.","format":"double","type":"number"},"expirationDate":{"description":"ExpirationDate is the ISO date the grant expires.","type":"string"},"grantId":{"description":"GrantID is the grant number, unique within the company.","type":"string"},"id":{"description":"ID is the option id.","type":"string"},"issueDate":{"description":"IssueDate is the ISO date the grant was issued.","type":"string"},"quantity":{"description":"Quantity is how many shares the grant covers.","format":"int64","type":"integer"},"stakeholderId":{"description":"StakeholderID is the grantee.","type":"string"},"stakeholderName":{"description":"StakeholderName is that grantee's name.","type":"string"},"status":{"description":"Status is the grant's state, e.g. DRAFT, ACTIVE, EXERCISED, EXPIRED or\nCANCELLED. Only non-terminal grants dilute the cap table.","type":"string"},"type":{"description":"Type is the grant kind, ISO or NSO.","type":"string"},"vestingYears":{"description":"VestingYears is the total vesting period in years.","format":"int64","type":"integer"}},"type":"object"},"captable.captableOptionIn":{"properties":{"boardApprovalDate":{"description":"BoardApprovalDate is when the board approved the grant, YYYY-MM-DD."},"cliffYears":{"description":"CliffYears is how long before ANY of the grant vests. A whole number; 0 for no cliff."},"equityPlanId":{"description":"EquityPlanID is the plan the options come from. It must name a plan of THIS company."},"exercisePrice":{"description":"ExercisePrice is the strike price per share, in the company's currency."},"expirationDate":{"description":"ExpirationDate is when unexercised options lapse, YYYY-MM-DD."},"grantId":{"description":"GrantID is the grant's identifier. It must be UNIQUE within the company; reusing one is refused 409."},"issueDate":{"description":"IssueDate is when the grant was made, YYYY-MM-DD."},"notes":{"description":"Notes is a free-text note kept with the grant. Optional."},"quantity":{"description":"Quantity is how many options to grant. A whole number above 0."},"rule144Date":{"description":"Rule144Date is when the Rule 144 holding period starts, YYYY-MM-DD."},"stakeholderId":{"description":"StakeholderID is who receives the grant. It must name a stakeholder of THIS company."},"status":{"description":"Status is DRAFT, ACTIVE, EXERCISED, EXPIRED or CANCELLED."},"type":{"description":"Type is ISO, NSO or RSU."},"vestingStartDate":{"description":"VestingStartDate is when vesting begins, YYYY-MM-DD."},"vestingYears":{"description":"VestingYears is the total vesting period. A whole number."}},"type":"object"},"captable.captableOptions":{"properties":{"data":{"description":"Data is every option grant, newest first.","items":{"$ref":"#/components/schemas/captable.captableOption"},"type":"array"}},"type":"object"},"captable.captableRound":{"properties":{"closeDate":{"description":"CloseDate is the ISO date the round closed, once it has.","type":"string"},"createdAt":{"description":"CreatedAt is when the round was recorded, in unix milliseconds.","format":"int64","type":"integer"},"id":{"description":"ID is the round id.","type":"string"},"name":{"description":"Name is the round name, e.g. \"Series A\".","type":"string"},"preMoneyValuation":{"description":"PreMoneyValuation is the pre-money valuation, for a priced round.","format":"double","type":"number"},"pricePerShare":{"description":"PricePerShare is the price per share, for a priced round.","format":"double","type":"number"},"raisedAmount":{"description":"RaisedAmount is how much has been invested so far.","format":"double","type":"number"},"roundType":{"description":"RoundType is PRICED, SAFE or CONVERTIBLE_NOTE.","type":"string"},"shareClassId":{"description":"ShareClassID is the class a priced round issues into.","type":"string"},"status":{"description":"Status is OPEN or CLOSED.","type":"string"},"targetAmount":{"description":"TargetAmount is how much the round set out to raise.","format":"double","type":"number"}},"type":"object"},"captable.captableRoundCloseRequest":{"properties":{"closeDate":{"description":"CloseDate is the date to record the round as closed on. Optional: omitted,\nnull or empty records TODAY. Any JSON scalar is accepted and stored as its\ntext, and the text is stored unparsed, so a caller that wants an ISO date\nsends one."},"id":{"description":"ID is the round to close. It is the path segment: the URL is the\naddressing authority, and the org it is resolved in comes from the\ncaller's principal, so an id from another tenant is simply not found.","type":"string"}},"type":"object"},"captable.captableRoundDetail":{"properties":{"investments":{"description":"Investments is every investment into this round, oldest first.","items":{"$ref":"#/components/schemas/captable.captableRoundInvestment"},"type":"array"},"round":{"$ref":"#/components/schemas/captable.captableRound","description":"Round is the round's own terms — name, type, valuation, target and status —\nas against the investments beside it."}},"type":"object"},"captable.captableRoundIn":{"properties":{"name":{"description":"Name is the round's name, e.g. \"Series A\"."},"preMoneyValuation":{"description":"PreMoneyValuation is the company's valuation before the new money. Optional."},"pricePerShare":{"description":"PricePerShare is the price investors pay per share. An investment into a round with a price ISSUES the shares it buys; one into a round priced later records the money alone."},"roundType":{"description":"RoundType is PRICED, SAFE or CONVERTIBLE."},"shareClassId":{"description":"ShareClassID is the class investors receive. It must name a class of THIS company."},"targetAmount":{"description":"TargetAmount is how much the round aims to raise, in the company's currency."}},"type":"object"},"captable.captableRoundInvestment":{"properties":{"amount":{"description":"Amount is the cash invested.","format":"double","type":"number"},"comments":{"description":"Comments is the note recorded with the cheque, if any.","type":"string"},"date":{"description":"Date is the ISO date of the investment.","type":"string"},"id":{"description":"ID is the investment id.","type":"string"},"shares":{"description":"Shares is how many shares the investment bought; 0 when the round issues no\nequity at the time of investment.","format":"int64","type":"integer"},"stakeholderId":{"description":"StakeholderID is the investor.","type":"string"},"stakeholderName":{"description":"StakeholderName is that investor's name.","type":"string"}},"type":"object"},"captable.captableRoundTotals":{"properties":{"count":{"description":"Count is how many rounds the company has recorded.","format":"int64","type":"integer"},"totalRaised":{"description":"TotalRaised is the sum of every round's raised amount.","format":"double","type":"number"}},"type":"object"},"captable.captableRounds":{"properties":{"data":{"description":"Data is every round, newest first.","items":{"$ref":"#/components/schemas/captable.captableRound"},"type":"array"}},"type":"object"},"captable.captableSafe":{"properties":{"capital":{"description":"Capital is the cash the investor put in.","format":"double","type":"number"},"discountRate":{"description":"DiscountRate is the discount to the next round's price, if any.","format":"double","type":"number"},"id":{"description":"ID is the SAFE id.","type":"string"},"issueDate":{"description":"IssueDate is the ISO date the SAFE was signed.","type":"string"},"mfn":{"description":"MFN is true when the SAFE carries a most-favoured-nation clause.","type":"boolean"},"proRata":{"description":"ProRata is true when the SAFE carries pro-rata rights.","type":"boolean"},"publicId":{"description":"PublicID is the SAFE's shareable identifier, unique within the company.","type":"string"},"stakeholderId":{"description":"StakeholderID is the investor.","type":"string"},"stakeholderName":{"description":"StakeholderName is that investor's name.","type":"string"},"status":{"description":"Status is the SAFE's state, e.g. DRAFT or ACTIVE.","type":"string"},"type":{"description":"Type is POST_MONEY or PRE_MONEY.","type":"string"},"valuationCap":{"description":"ValuationCap is the valuation cap, if any.","format":"double","type":"number"}},"type":"object"},"captable.captableSafeIn":{"properties":{"additionalTerms":{"description":"AdditionalTerms is free text for anything the fields above do not carry. Optional."},"boardApprovalDate":{"description":"BoardApprovalDate is when the board approved it, YYYY-MM-DD."},"capital":{"description":"Capital is the money invested, in the company's currency."},"discountRate":{"description":"DiscountRate is the discount to the next round's price, as a percentage. Optional."},"issueDate":{"description":"IssueDate is when the SAFE was signed, YYYY-MM-DD."},"publicId":{"description":"PublicID is the SAFE's identifier. It must be UNIQUE within the company; reusing one is refused 409."},"stakeholderId":{"description":"StakeholderID is the investor. It must name a stakeholder of THIS company."},"status":{"description":"Status is DRAFT, ACTIVE, PENDING, EXPIRED or CANCELLED."},"type":{"description":"Type is PRE_MONEY or POST_MONEY — which side of the new money the cap is measured on."},"valuationCap":{"description":"ValuationCap is the valuation the SAFE converts at, at most. Optional; omit for an uncapped SAFE."}},"type":"object"},"captable.captableSafes":{"properties":{"data":{"description":"Data is every SAFE, newest first.","items":{"$ref":"#/components/schemas/captable.captableSafe"},"type":"array"}},"type":"object"},"captable.captableShare":{"properties":{"capitalContribution":{"description":"CapitalContribution is the cash paid for the certificate, if recorded.","format":"double","type":"number"},"certificateId":{"description":"CertificateID is the certificate number, unique within the company.","type":"string"},"companyLegends":{"description":"CompanyLegends are the restrictive legends printed on the certificate.","items":{"type":"string"},"type":"array"},"id":{"description":"ID is the share id.","type":"string"},"issueDate":{"description":"IssueDate is the ISO date the certificate was issued.","type":"string"},"pricePerShare":{"description":"PricePerShare is the price paid per share, if recorded.","format":"double","type":"number"},"quantity":{"description":"Quantity is how many shares the certificate covers.","format":"int64","type":"integer"},"shareClassId":{"description":"ShareClassID is the class the shares belong to.","type":"string"},"shareClassName":{"description":"ShareClassName is that class's name.","type":"string"},"shareClassType":{"description":"ShareClassType is that class's type, COMMON or PREFERRED.","type":"string"},"stakeholderId":{"description":"StakeholderID is the holder of the certificate.","type":"string"},"stakeholderName":{"description":"StakeholderName is that holder's name.","type":"string"},"status":{"description":"Status is ACTIVE or DRAFT.","type":"string"}},"type":"object"},"captable.captableShareClass":{"properties":{"classType":{"description":"ClassType is COMMON or PREFERRED.","type":"string"},"companyName":{"description":"CompanyName is the name of the company whose cap table this is.","type":"string"},"conversionRights":{"description":"ConversionRights describes what the class converts into, e.g.\nCONVERTS_TO_FUTURE_ROUND.","type":"string"},"id":{"description":"ID is the share class id.","type":"string"},"idx":{"description":"Idx is the class's 1-based position within the company, in creation order.","format":"int64","type":"integer"},"initialSharesAuthorized":{"description":"InitialSharesAuthorized is how many shares of this class are authorized.","format":"int64","type":"integer"},"liquidationPreferenceMultiple":{"description":"LiquidationPreferenceMultiple is the preference multiple on liquidation.","format":"double","type":"number"},"name":{"description":"Name is the class name, e.g. \"Common\" or \"Series A Preferred\".","type":"string"},"parValue":{"description":"ParValue is the par value per share.","format":"double","type":"number"},"participationCapMultiple":{"description":"ParticipationCapMultiple caps participation on liquidation; 0 is uncapped.","format":"double","type":"number"},"prefix":{"description":"Prefix is the certificate prefix, CS for common and PS for preferred.","type":"string"},"pricePerShare":{"description":"PricePerShare is the issue price per share.","format":"double","type":"number"},"seniority":{"description":"Seniority orders classes in a liquidation waterfall; higher is more senior.","format":"int64","type":"integer"},"votesPerShare":{"description":"VotesPerShare is how many votes one share of this class carries.","format":"int64","type":"integer"}},"type":"object"},"captable.captableShareClassAmend":{"properties":{"boardApprovalDate":{"description":"BoardApprovalDate is when the board approved the class, YYYY-MM-DD."},"classType":{"description":"ClassType is COMMON or PREFERRED."},"conversionRights":{"description":"ConversionRights is CONVERTS_TO_FUTURE_ROUND or CONVERTS_TO_SHARE_CLASS_ID. The second requires convertsToShareClassId."},"convertsToShareClassId":{"description":"ConvertsToShareClassID names the class this one converts into. Required when conversionRights is CONVERTS_TO_SHARE_CLASS_ID, ignored otherwise."},"id":{"description":"ID addresses the resource. The URL is the addressing authority — a path\nsegment binds after the body and after the query — so the address decides\nwhich row is written whatever a body claims.","type":"string"},"initialSharesAuthorized":{"description":"InitialSharesAuthorized is how many shares this class may issue. A whole number."},"liquidationPreferenceMultiple":{"description":"LiquidationPreferenceMultiple is the multiple of invested capital paid out before junior classes — 1 for a 1x preference."},"name":{"description":"Name is the share class's name, e.g. \"Series A Preferred\"."},"parValue":{"description":"ParValue is the nominal per-share value on the certificate, in the company's currency."},"participationCapMultiple":{"description":"ParticipationCapMultiple caps participation after the preference is paid, as a multiple of invested capital. 0 for no cap."},"pricePerShare":{"description":"PricePerShare is the issue price for this class, in the company's currency."},"seniority":{"description":"Seniority orders liquidation preference: LOWER is more senior, so 1 is paid before 2."},"stockholderApprovalDate":{"description":"StockholderApprovalDate is when the stockholders approved it, YYYY-MM-DD."},"votesPerShare":{"description":"VotesPerShare is how many votes one share of this class carries. A whole number; 0 for non-voting."}},"type":"object"},"captable.captableShareClassIn":{"properties":{"boardApprovalDate":{"description":"BoardApprovalDate is when the board approved the class, YYYY-MM-DD."},"classType":{"description":"ClassType is COMMON or PREFERRED."},"conversionRights":{"description":"ConversionRights is CONVERTS_TO_FUTURE_ROUND or CONVERTS_TO_SHARE_CLASS_ID. The second requires convertsToShareClassId."},"convertsToShareClassId":{"description":"ConvertsToShareClassID names the class this one converts into. Required when conversionRights is CONVERTS_TO_SHARE_CLASS_ID, ignored otherwise."},"initialSharesAuthorized":{"description":"InitialSharesAuthorized is how many shares this class may issue. A whole number."},"liquidationPreferenceMultiple":{"description":"LiquidationPreferenceMultiple is the multiple of invested capital paid out before junior classes — 1 for a 1x preference."},"name":{"description":"Name is the share class's name, e.g. \"Series A Preferred\"."},"parValue":{"description":"ParValue is the nominal per-share value on the certificate, in the company's currency."},"participationCapMultiple":{"description":"ParticipationCapMultiple caps participation after the preference is paid, as a multiple of invested capital. 0 for no cap."},"pricePerShare":{"description":"PricePerShare is the issue price for this class, in the company's currency."},"seniority":{"description":"Seniority orders liquidation preference: LOWER is more senior, so 1 is paid before 2."},"stockholderApprovalDate":{"description":"StockholderApprovalDate is when the stockholders approved it, YYYY-MM-DD."},"votesPerShare":{"description":"VotesPerShare is how many votes one share of this class carries. A whole number; 0 for non-voting."}},"type":"object"},"captable.captableShareIn":{"properties":{"boardApprovalDate":{"description":"BoardApprovalDate is when the board approved the issuance, YYYY-MM-DD."},"capitalContribution":{"description":"CapitalContribution is cash paid for the shares. Optional."},"certificateId":{"description":"CertificateID is the certificate number. It must be UNIQUE within the company; reusing one is refused 409."},"cliffYears":{"description":"CliffYears is how long before ANY of the grant vests. A whole number; 0 for no cliff."},"companyLegends":{"description":"CompanyLegends are the restrictive legends printed on the certificate.\n\nA LIST, and it must be sent as one: the bundle substitutes an EMPTY list for\nanything that is not an array, so a single string would be accepted and\nsilently discarded — the certificate issued with no legends and nothing\nreporting it.","items":{},"type":"array"},"debtCancelled":{"description":"DebtCancelled is debt forgiven as consideration. Optional."},"ipContribution":{"description":"IPContribution is intellectual property assigned as consideration, valued in the company's currency. Optional."},"issueDate":{"description":"IssueDate is when the shares were issued, YYYY-MM-DD."},"otherContributions":{"description":"OtherContributions is any other consideration, valued in the company's currency. Optional."},"pricePerShare":{"description":"PricePerShare is what was paid per share. Optional."},"quantity":{"description":"Quantity is how many shares to issue. A whole number above 0."},"rule144Date":{"description":"Rule144Date is when the Rule 144 holding period starts, YYYY-MM-DD. Optional."},"shareClassId":{"description":"ShareClassID is the class being issued. It must name a class of THIS company."},"stakeholderId":{"description":"StakeholderID is who receives the shares. It must name a stakeholder of THIS company."},"status":{"description":"Status is ACTIVE, DRAFT, SIGNED or PENDING."},"vestingStartDate":{"description":"VestingStartDate is when vesting begins, YYYY-MM-DD. Optional; defaults to the issue date."},"vestingYears":{"description":"VestingYears is the total vesting period. A whole number; 0 for fully vested at issue."}},"type":"object"},"captable.captableShareTransfer":{"properties":{"certificateId":{"description":"CertificateID names the NEW certificate a partial transfer issues, and is\nrequired for one — a partial transfer without it is refused 400. It is unused\nby a full transfer, which reassigns the existing certificate.\n\nIt must be unique within the company; reusing one is refused 409. Declaring\nit is not optional in the way the tag suggests: omitting this field from the\nGo type would leave `quantity` accepted and every PARTIAL transfer answering\n\"certificateId is required\" with no way for a caller to supply it — the\nsilent-drop failure this whole conversion was blocked on, one field wide."},"quantity":{"description":"Quantity is how many shares to move. OPTIONAL, and its absence is not zero:\nomitted or null transfers the WHOLE certificate. A value outside 1..held is\nrefused, so a partial transfer can never over-issue.\n\nA full transfer REASSIGNS the certificate and mints no new one; a partial\ntransfer splits it and answers with the new share's id. That is the fact a\ncaller needs from the answer, not from this comment."},"shareId":{"description":"ShareID is the certificate being transferred. Required, and it must name a\nshare in the caller org's own company — a share id from another tenant\nresolves to not-found rather than to another company's certificate."},"toStakeholderId":{"description":"ToStakeholderID is who receives them. Required, and it must reference a\nstakeholder of the SAME company; one that does not is refused 400 rather\nthan creating a dangling holder."}},"type":"object"},"captable.captableShares":{"properties":{"data":{"description":"Data is every issued share certificate, newest first.","items":{"$ref":"#/components/schemas/captable.captableShare"},"type":"array"}},"type":"object"},"captable.captableStakeholder":{"properties":{"city":{"description":"City is the stakeholder's city, if recorded.","type":"string"},"companyName":{"description":"CompanyName is the name of the company whose cap table this is.","type":"string"},"country":{"description":"Country is the stakeholder's two-letter country code.","type":"string"},"createdAt":{"description":"CreatedAt is when the stakeholder was added, in unix milliseconds.","format":"int64","type":"integer"},"currentRelationship":{"description":"CurrentRelationship is how the stakeholder relates to the company, e.g.\nFOUNDER, INVESTOR or EMPLOYEE.","type":"string"},"email":{"description":"Email is the stakeholder's email, unique within the company.","type":"string"},"id":{"description":"ID is the stakeholder id.","type":"string"},"institutionName":{"description":"InstitutionName names the institution, when the stakeholder is one.","type":"string"},"name":{"description":"Name is the stakeholder's full name.","type":"string"},"stakeholderType":{"description":"StakeholderType is INDIVIDUAL or INSTITUTION.","type":"string"},"state":{"description":"State is the stakeholder's state or province, if recorded.","type":"string"},"streetAddress":{"description":"StreetAddress is the stakeholder's street address, if recorded.","type":"string"},"taxId":{"description":"TaxID is the stakeholder's tax identifier, if recorded.","type":"string"},"zipcode":{"description":"Zipcode is the stakeholder's postal code, if recorded.","type":"string"}},"type":"object"},"captable.captableStakeholderPatch":{"properties":{"city":{"description":"City is the stakeholder's city."},"currentRelationship":{"description":"CurrentRelationship is how the stakeholder relates to the company, e.g.\nFOUNDER, INVESTOR or EMPLOYEE. This route stores it as sent — unlike\nadding a stakeholder, it is not checked against the vocabulary."},"email":{"description":"Email is the stakeholder's email. This route stores it as sent — unlike\nadding a stakeholder, it is not checked for shape or uniqueness."},"id":{"description":"ID is the stakeholder to update. It is the path segment: the URL is the\naddressing authority, and the org it is resolved in comes from the\ncaller's principal, so an id from another tenant is simply not found.","type":"string"},"institutionName":{"description":"InstitutionName names the institution, when the stakeholder is one."},"name":{"description":"Name is the stakeholder's full name."},"stakeholderType":{"description":"StakeholderType is INDIVIDUAL or INSTITUTION. This route stores it as\nsent — unlike adding a stakeholder, it is not checked against the\nvocabulary."},"state":{"description":"State is the stakeholder's state or province."},"streetAddress":{"description":"StreetAddress is the stakeholder's street address."},"taxId":{"description":"TaxID is the stakeholder's tax identifier."},"zipcode":{"description":"Zipcode is the stakeholder's postal code."}},"type":"object"},"captable.captableSummary":{"properties":{"byShareClass":{"description":"ByShareClass is each share class's authorized-versus-issued position, in\nclass creation order.","items":{"$ref":"#/components/schemas/captable.captableClassHolding"},"type":"array"},"byStakeholder":{"description":"ByStakeholder is each stakeholder's position, largest holding first.","items":{"$ref":"#/components/schemas/captable.captableHolding"},"type":"array"},"company":{"$ref":"#/components/schemas/captable.captableSummaryCompany","description":"Company names the company the cap table is computed for."},"convertibles":{"$ref":"#/components/schemas/captable.captableConvertibles","description":"Convertibles is the capital on SAFEs and notes that have not converted."},"rounds":{"$ref":"#/components/schemas/captable.captableRoundTotals","description":"Rounds is the fundraising rollup."},"totals":{"$ref":"#/components/schemas/captable.captableTotals","description":"Totals is the company-wide share count."}},"type":"object"},"captable.captableSummaryCompany":{"properties":{"id":{"description":"ID is the company id, which is the tenant's own org id.","type":"string"},"name":{"description":"Name is the company's legal name.","type":"string"}},"type":"object"},"captable.captableTotals":{"properties":{"fullyDilutedShares":{"description":"FullyDilutedShares is outstandingShares plus grantedOptions.","format":"int64","type":"integer"},"grantedOptions":{"description":"GrantedOptions is the shares under non-terminal option grants — grants that\nare EXERCISED, EXPIRED or CANCELLED are excluded, so nothing double-counts.","format":"int64","type":"integer"},"outstandingShares":{"description":"OutstandingShares is the sum of every issued share certificate.","format":"int64","type":"integer"},"shareClasses":{"description":"ShareClasses is how many share classes the company has authorized.","format":"int64","type":"integer"},"stakeholders":{"description":"Stakeholders is how many stakeholders the company has.","format":"int64","type":"integer"}},"type":"object"},"captable.captableTransferred":{"properties":{"message":{"description":"Message is the human sentence the cap table wrote, e.g. \"Share transferred\".","type":"string"},"newShareId":{"description":"NewShareID names the certificate a PARTIAL transfer created. It is null on a\nfull transfer, which reassigns the existing certificate instead of splitting\nit — so null here means \"no new certificate\", never \"the transfer failed\".","type":"string"},"success":{"description":"Success is true when the transfer was applied.","type":"boolean"},"transferred":{"description":"Transferred is how many shares moved.","format":"int64","type":"integer"}},"type":"object"},"captable.captableUpdated":{"properties":{"message":{"description":"Message is the human sentence the cap table wrote, e.g. \"Company updated\".","type":"string"},"success":{"description":"Success is true when the update was applied.","type":"boolean"}},"type":"object"},"catalog.Entry":{"properties":{"archetype":{"description":"Archetype is WHAT KIND OF THING this is, from a closed and ordered list —\nmodel | contract | chain | sdk | template | infra | site | app — derived from\nthe repository's own topics, name and description, first match winning, and\nalways `site` for a deployed site. It is DERIVED, never guessed by a model,\nbecause a wrong archetype hides a row from the browse rail more thoroughly\nthan a missing one does. Empty when no topic matched: unclassified, not\nuncategorisable.","type":"string"},"description":{"description":"Description is the repository's own one-line GitHub description, carried\nverbatim. It comes from the SOURCE half of a row, so a site that was never\nmatched to a repository has none, and nothing here is written by us.","type":"string"},"forkable":{"description":"Forkable is NOT omitempty: false is an answer here, not a missing field.\nOmitted, a client could not tell \"you cannot fork this\" from \"nobody said\".","type":"boolean"},"id":{"description":"ID is \"\u003corg\u003e/\u003cname\u003e\" and is the corpus's primary key: a re-published entry\nupdates in place under it rather than accumulating duplicates, so it is the\none handle stable enough to link to or to name in a `template` filter. Two\norgs can spell the same id, and `canonical` picks which one keeps it.","type":"string"},"kind":{"description":"repo | site","type":"string"},"language":{"description":"Language is the repository's primary implementation language as GitHub\ncomputes it (\"Go\", \"TypeScript\"), and the case is GitHub's. Empty for a site\nwith no source half and for a repository GitHub could not classify.","type":"string"},"license":{"description":"License is the terms that upstream work carries, in whichever form the half\nthat credited it had: an SPDX id (\"MIT\", \"Apache-2.0\") on a GitHub fork,\nfree text on a site whose publisher declared it. GitHub's NOASSERTION — \"we\ncould not identify it\" — reads as none rather than as a licence by that name.\nSo empty means UNDECLARED and never unencumbered, and Upstream is what says\nwhether the question applies at all.","type":"string"},"name":{"description":"Name is the short identifier inside the org — the repository's name, or the\nsite's slug — and is the half of ID after the slash. Not a display name;\nTitle is.","type":"string"},"note":{"description":"Note is why a row is NOT in the published catalog, set by the admission gate\n(gate.go) on the sites it holds back. It is the difference between a demo\nthat silently vanished from the public lens and one whose owner can read the\nreason and fix it. A published row never carries one.","type":"string"},"org":{"description":"hanzo | lux | zoo","type":"string"},"origin":{"description":"Origin is WHAT THIS IS TO YOU: template | community | third-party | product\n(origin.go owns the four nouns and derives them). Not omitempty, for the\nsame reason Forkable is not: every row has an answer, and a missing one is\nexactly the flattening this field exists to end.","type":"string"},"repo":{"description":"source","type":"string"},"scope":{"description":"Scope is provenance, not storage: \"public\" for a row from the published\ncorpus, \"org\" for one only this caller can see. A UI that cannot tell them\napart cannot warn before sharing a link.","type":"string"},"stars":{"description":"Stars is GitHub's stargazer count for the source repository, read at the last\nsync and never accumulated here. It is not a ranking — the page sorts on\nUpdated — but it is the tiebreak when two orgs claim one ID. Absent for a\nsite with no repository behind it, and for a repository nobody has starred.","format":"int64","type":"integer"},"template":{"description":"lineage, if forked from one","type":"string"},"title":{"description":"Title is what to SHOW. A site's human name wins where it has one; a repo row\nfalls back to the repository name, so on a repo this usually just repeats\nName. Absent only for a site whose project was never named — render Name.","type":"string"},"updated":{"description":"Updated is when the thing last MOVED, as RFC 3339 in UTC: a repository's last\npush, or a site's last deploy. The page is ordered on it, most recent first,\nby comparing these strings — so the format is load-bearing and not cosmetic.\nAbsent means the source reported no timestamp, and such a row sorts last.","type":"string"},"upstream":{"description":"Upstream/License credit the third-party work an entry was published from:\nthe difference between \"this org built it\" and \"somebody else built it and\nwe are showing it to you\".\n\nWHO built it is Org, above — the account that paid for the project. There\nwas once a separate admin-gated `official` boolean here claiming the same\nthing, and because it was gated it disagreed: apps Hanzo wrote and hosts\nwere published by a script holding an ordinary org token, so it stayed\nfalse on all of them and this directory filed our own work as somebody\nelse's. A field that restates an unforgeable fact can only ever be the\nwrong copy of it.","type":"string"},"url":{"description":"live, if it is deployed","type":"string"}},"type":"object"},"catalog.catalogPage":{"properties":{"data":{"description":"Data is the page of matching entries, most recently updated first.","items":{"$ref":"#/components/schemas/catalog.Entry"},"type":"array"},"facets":{"additionalProperties":{"additionalProperties":{"format":"int64","type":"integer"},"type":"object"},"description":"Facets counts the whole matching set along every browse axis, so a rail a\nclient renders is a rail that has results behind it. Keyed axis → value → count.","type":"object"},"total":{"description":"Total is how many entries matched BEFORE paging — what a pager sizes itself on.","format":"int64","type":"integer"}},"type":"object"},"channel.allowlistPutIn":{"properties":{"accessGroups":{"additionalProperties":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"description":"AccessGroups REPLACES the org's named access groups, as\ngroup name -\u003e channel -\u003e entries. Absent or null leaves them alone.","type":"object"},"channel":{"description":"Channel is the transport to edit: discord, github, linear, slack, teams, telegram or whatsapp.\nRequired; an unknown value is a 404.","type":"string"},"dm":{"description":"DM REPLACES the config-managed DM allow entries. Absent or null leaves them\nalone; an empty list clears them. It never touches senders approved through\npairing — a policy edit cannot revoke an approved pairing.","items":{"type":"string"},"type":"array"},"dmPolicy":{"description":"DMPolicy sets how direct messages are admitted: \"pairing\" (a person must be\napproved first), \"allowlist\" (only listed senders) or \"open\". Empty leaves\nit unchanged.","type":"string"},"group":{"description":"Group REPLACES the config-managed group allow entries. Absent or null\nleaves them alone; an empty list clears them.","items":{"type":"string"},"type":"array"},"groupPolicy":{"description":"GroupPolicy sets how group and thread rooms are admitted: \"open\",\n\"allowlist\" or \"disabled\". Empty leaves it unchanged.","type":"string"}},"type":"object"},"channel.allowlistView":{"properties":{"accessGroups":{"additionalProperties":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"description":"AccessGroups is the org's named sender sets, as group name -\u003e channel -\u003e\nmember entries, held once for the whole org. A DM or Group entry written\n`accessGroup:\u003cname\u003e` admits any sender listed under that name for THIS\nchannel, or under the channel `*`, which is how one set covers every\ntransport at once. Replaced wholesale by the PUT.","type":"object"},"dm":{"description":"DM is the CONFIG-managed DM allow entries — the list PUT\n/v1/channel/allowlist owns and replaces wholesale. An entry matches a sender\neither EXACTLY, as the transport-native id inbox messages carry, or as\n`accessGroup:\u003cname\u003e` resolved through AccessGroups. A bare `*` admits\neveryone, but only while DMPolicy is \"open\": it is gate syntax, not an\nidentity, so under \"allowlist\" it matches nobody.","items":{"type":"string"},"type":"array"},"dmPolicy":{"description":"DMPolicy decides every inbound DIRECT message, defaulting to \"pairing\" when\nthe org has never set one. \"pairing\": a sender with no entry is sent a\npairing code and the message is DROPPED — it never reaches the inbox — and\nthey are admitted only once an admin approves. \"allowlist\": only DM admits,\nand Paired senders are suspended, since a pairing grant counts under\n\"pairing\" alone. \"open\" is not unconditional either — it still requires `*`\nor a matching entry in DM.","type":"string"},"group":{"description":"Group is the CONFIG-managed group allow entries, consulted only while\nGroupPolicy is \"allowlist\". Entries match the same two ways as DM, and here a\nbare `*` admits every sender in the room.","items":{"type":"string"},"type":"array"},"groupPolicy":{"description":"GroupPolicy decides every inbound GROUP or THREAD message — a thread is a\ngroup surface — defaulting to \"open\". \"open\" admits every sender in the room.\n\"allowlist\" admits only what Group lists, so an EMPTY Group blocks the\nchannel's group rooms outright. \"disabled\" drops all of them.","type":"string"},"paired":{"description":"Paired is the senders admitted by PAIRING — the entries POST\n/v1/channel/pairing/approve minted, DM scope only. READ-ONLY on this\nendpoint: the PUT writes config entries and can never revoke one of these\n(listing a paired sender under DM instead promotes that entry to config,\nwhich the admin then owns). They admit only while DMPolicy is \"pairing\".","items":{"type":"string"},"type":"array"}},"type":"object"},"channel.approvePairingIn":{"properties":{"channel":{"description":"Channel is the transport the request came in on: discord, slack, teams,\ntelegram or whatsapp.","type":"string"},"code":{"description":"Code is the pairing code from GET /v1/channel/pairing. It is a capability:\nholding it is what authorises the approval, alongside org admin.","type":"string"}},"type":"object"},"channel.capabilities":{"properties":{"actions":{"description":"Actions is whether the transport renders an INTERACTIVE control natively, and\nit is the flag to read before composing one. The vocabulary is a closed\nkind-tagged union (envelope.go), exactly four kinds, each carrying only its\nown field plus an optional label:\n\n\tcommand  — a bot command to run (`command`), rendered as a button that\n\t           invokes it.\n\turl      — an external link (`url`), rendered as a link button.\n\tselect   — a menu (`options`, each a label and the value choosing it\n\t           returns), rendered as a picker.\n\tapproval — a reference to an approval request (`approval.id`), rendered as\n\t           approve/deny controls bound to that id.\n\nFalse on every transport, and nothing refuses a send for it:\nactions are accepted, validated per kind, and flattened by renderText to one\nline each after the text — `[label] command`, `[label] url`,\n`[label] opt | opt`, `[label] approval requested: \u003cid\u003e`. So a caller that\nneeds a real control must read this flag and degrade itself; a caller that\nonly needs the choice communicated can send actions and take the text form.","type":"boolean"},"dm":{"description":"DM is whether the transport carries a DIRECT message at all. True for slack,\nteams, telegram and whatsapp — whatsapp is nothing else, since the Cloud API\naddresses a person's number and there is no room a third party joins. False\nfor discord, honestly: that ingress is guild-scoped slash commands — an\ninteraction without a guild id is refused at the endpoint — so nothing ever\narrives classified as a DM, no reply route is ever learned for one, and a\nsend addressed at a Discord DM is refused 409.","type":"boolean"},"edit":{"description":"Edit is whether a sent message can be rewritten in place. True for slack\nalone. It is what lets a turn keep ONE message — progress, then the answer —\nand a transport without it shows the answer only.","type":"boolean"},"group":{"description":"Group is whether the transport carries multi-person rooms — a Discord guild\nchannel, a Slack channel, a Teams channel or group chat, a Telegram group or\nsupergroup. False on whatsapp alone, which has no such room to carry.","type":"boolean"},"media":{"description":"Media is whether the transport renders an ATTACHMENT natively. False\neverywhere, and a send is not refused for it: renderText flattens each\nattachment to one `kind: url (mime)` line after the text rather than dropping\nit. A transport whose egress passes the raw text straight through would drop the\nattachment instead, and an attachment-only send would reach the platform\nwith nothing to say — which is why the flag and the flattening are pinned\ntogether.","type":"boolean"},"thread":{"description":"Thread is whether a reply can be threaded UNDER a specific message. True for\nslack alone: it is the only transport whose ingress reports a thread\n(thread_ts, published as the envelope's replyTo) and whose send posts back\ninto it. Discord's replyTo makes an inline reply rather than a thread,\nTelegram's and WhatsApp's each quote one message, and Teams carries no reply\ntarget at all — a replyTo sent to it is ignored.","type":"boolean"}},"type":"object"},"channel.channelAgents":{"properties":{"channel":{"description":"Channel is the transport these bindings are for.","type":"string"},"default":{"description":"Default is the agent that answers any room without a binding of its own;\n\"hanzo\" when the org has never set one.","type":"string"},"rooms":{"additionalProperties":{"type":"string"},"description":"Rooms maps a platform room id to the agent that answers there.","type":"object"}},"type":"object"},"channel.channelAgentsPut":{"properties":{"channel":{"description":"Channel is the transport to edit. Required; an unknown value is a 404.","type":"string"},"default":{"description":"Default sets the agent for rooms with no binding of their own; \"hanzo\"\nrestores the built-in. Empty or absent leaves it unchanged.","type":"string"},"rooms":{"additionalProperties":{"type":"string"},"description":"Rooms binds platform room ids to agents; rooms not named are left alone.","type":"object"},"unbind":{"description":"Unbind removes the bindings of these rooms, so they fall back to Default.","items":{"type":"string"},"type":"array"}},"type":"object"},"channel.channelView":{"properties":{"account":{"description":"Account is the id-shaped fact about that connection: the lowercased external\nid integrations custodies for it — a Discord guild id, a Slack team\n(workspace) id, a Teams AAD tenant id, or the Telegram chat the org bound.\nEmpty when not connected. Informational: the access policy keys on\n(org, channel), so exactly one account is representable per pair.","type":"string"},"accountLabel":{"description":"AccountLabel is the human label of that same account — the Discord guild\nname, the Slack team name, the Teams tenant name (falling back to the tenant\nid), the Telegram chat title. DISPLAY ONLY: never a key, and never swapped\nwith Account, on any surface.","type":"string"},"capabilities":{"$ref":"#/components/schemas/channel.capabilities","description":"Capabilities is what this transport renders natively — read it before\ncomposing a message that needs threading, media or interactive actions."},"connected":{"description":"Connected is whether integrations holds a connection for (this org, this\ntransport) — whether someone finished its connect flow. False leaves Account\nand AccountLabel empty, and a send is then refused downstream rather than\nhere: by the transport's own binding check (403 for a Telegram chat this org\nhas not bound, 409 for a Discord or Teams room with no inbound-learned\nroute), or on Slack by the absent per-org bot token, which surfaces as 502.","type":"boolean"},"dmPolicy":{"description":"DMPolicy is how this org admits direct messages here: \"pairing\", \"allowlist\"\nor \"open\", defaulting to \"pairing\" when the org has never set one.","type":"string"},"groupPolicy":{"description":"GroupPolicy is how this org admits group and thread rooms here: \"open\",\n\"allowlist\" or \"disabled\", defaulting to \"open\". Both policy fields come\nback EMPTY — rather than the listing failing — when the policy cannot be\nread; GET /v1/channel/allowlist carries the same two with the entries they\nconsult.","type":"string"},"id":{"description":"ID is the fixed transport identifier — discord, slack, teams, telegram or\nwhatsapp — and the value every route on this surface names a channel by, including the\n`:channel` segment of the send path. The listing is always in that order.","type":"string"},"pendingPairing":{"description":"PendingPairing counts the org's UNEXPIRED pairing requests on this channel:\nexactly the rows GET /v1/channel/pairing returns for it, one per person\nwaiting on an admin. It never exceeds three — the pending cap per\n(org, channel) — and expired requests are not counted.","format":"int64","type":"integer"}},"type":"object"},"channel.chatChannels":{"properties":{"channels":{"description":"Channels is every chat transport this deployment supports, in a fixed\norder, each carrying whether the org has connected it, the account behind\nthe connection, what the transport can do, the org's DM/group access\npolicies for it, and how many pairing requests are waiting.","items":{"$ref":"#/components/schemas/channel.channelView"},"type":"array"}},"type":"object"},"channel.inboxPage":{"properties":{"cursor":{"description":"Cursor is the row id to pass back as `since` for the next page. It is the\nlast message's id, or the requested cursor when the page is empty.","format":"int64","type":"integer"},"messages":{"description":"Messages are the inbound messages, oldest first.","items":{"$ref":"#/components/schemas/channel.inboxView"},"type":"array"}},"type":"object"},"channel.inboxView":{"properties":{"account":{"description":"Account is the lowercased external id of the org's connected account on that\ntransport: the Discord guild id, the Slack team id, the Teams AAD tenant id,\nor the bound Telegram chat id. Informational only — the gate keys on\n(org, channel), never on the account.","type":"string"},"channel":{"description":"Channel is the transport this message arrived on — discord, slack, teams or\ntelegram — and the `:channel` segment to reply through.","type":"string"},"createdAt":{"description":"CreatedAt is Unix SECONDS, stamped by the ingest goroutine when the message\nwas accepted — not the transport's own send time. Rows are dropped 30 days\nafter it.","format":"int64","type":"integer"},"id":{"description":"ID is the store's row id, assigned on insert — SERVER-SET, and the cursor:\npass a page's last id back as `since`. It rises with arrival order but is\nnot contiguous, because one sequence is shared by every org in the store and\na caller reads only its own rows.","format":"int64","type":"integer"},"replyTo":{"description":"ReplyTo is the transport's reply target for this message: Slack's thread_ts,\nor the Telegram message id it arrived as. Send it back as the body's\n`replyTo` to answer in the SAME thread. Empty means the transport reported\nnone — a top-level Slack message, and every Discord and Teams message, since\nneither carries one — and a reply then lands at the top level of the room.","type":"string"},"roomId":{"description":"RoomID is the conversation on the ORIGINATING transport, and the value to\nsend back as `room.id`: a Discord channel snowflake, a Slack conversation id\n(D… IM, C… public channel, G… private or mpim), a Teams conversation id\n(19:…@thread.… for a channel or group chat, a:… for a personal chat), or a\nTelegram chat id in decimal (negative for a group, positive for a DM). It is\nstable for the life of the room, so every message from one conversation\ncarries the same value.","type":"string"},"roomKind":{"description":"RoomKind is how ingest classified the room: \"dm\", \"group\" or \"thread\". It\ndecides which policy gated the message — dmPolicy for \"dm\", groupPolicy for\nBOTH \"group\" and \"thread\". Only Slack ever reports \"thread\"; Telegram's\nreply-to id becomes ReplyTo instead, and Discord's ingress is guild-scoped\nso its rooms are always \"group\".","type":"string"},"sender":{"description":"Sender is the TRANSPORT-NATIVE user id of whoever wrote the message — a\nDiscord member.user.id, a Slack U… user id, a Teams aadObjectId (falling\nback to from.id), a Telegram from.id in decimal. Stable per person per\ntransport, and the identity the gate keys on: an allow entry, an access-group\nmember and a pairing approval all name exactly this value.","type":"string"},"senderUser":{"description":"SenderUser is the HANZO account subject that chat identity is linked to,\nresolved at ingest through the org's user link. Best-effort and omitted when\nabsent: a person who never linked their chat account — or a link store that\ncould not be read — leaves it empty and is never blocked for it.","type":"string"},"text":{"description":"Text is the body as the transport delivered it, with the bot mention already\nstripped by the ingress adapter (on Discord it is the /hanzo prompt argument,\nsince that ingress is slash commands only), truncated to 8 KiB on store.\nInbound attachments are not stored — this is the whole of what was said.","type":"string"}},"type":"object"},"channel.pairingApproved":{"properties":{"ownerBootstrapped":{"description":"OwnerBootstrapped is true when this approval was the org's FIRST on the\nchannel and therefore also made the sender its owner.","type":"boolean"},"sender":{"description":"Sender is the external chat identity that is now allowed to DM the org's bot.","type":"string"}},"type":"object"},"channel.pairingQueue":{"properties":{"pending":{"description":"Pending is every unexpired pairing request waiting on an org admin, each\ncarrying the channel, the requesting sender and the code to approve it with.","items":{"$ref":"#/components/schemas/channel.pairingView"},"type":"array"}},"type":"object"},"channel.pairingView":{"properties":{"channel":{"description":"Channel is the transport the request arrived on — discord, slack, teams or\ntelegram — and half of what approval names. The cap of three unapproved\nrequests applies per (org, channel); while it is full no further code is\nminted until one is approved or expires.","type":"string"},"code":{"description":"Code is the CAPABILITY that authorises the approval: eight characters from a\n32-symbol uppercase alphabet (A-Z0-9 minus the confusables 0, O, 1 and I),\nminted with crypto/rand and also sent to the requester in chat. An org admin\npasses it with the channel to POST /v1/channel/pairing/approve, which\nCONSUMES it — the request row is deleted, so a code approves once — and which\ntakes org admin as well as the code. It lives ONE HOUR from CreatedAt;\nexpired requests are not listed here, and approving one is a 404. It is shown\non this admin surface and NEVER logged.","type":"string"},"createdAt":{"description":"CreatedAt is Unix SECONDS of FIRST contact: when the request was minted and\nthe code sent. Expiry is measured from here and from nowhere else.","format":"int64","type":"integer"},"lastSeen":{"description":"LastSeen is Unix SECONDS of the MOST RECENT message from this sender while\nthe request has been pending. It moves as they keep writing, which is how an\nadmin tells a live request from an abandoned one — but it does not extend the\nhour and does not re-send the code, since one request sends exactly one chat\nreply.","format":"int64","type":"integer"},"sender":{"description":"Sender is the transport-native user id waiting for access — the same\nidentity inbox messages carry. Approving mints a DM allow entry for exactly\nthis value and nothing wider: pairing never grants group access.","type":"string"}},"type":"object"},"ci.Artifact":{"properties":{"digest":{"type":"string"},"tag":{"type":"string"}},"type":"object"},"ci.Check":{"properties":{"at":{"format":"date-time","type":"string"},"job":{"description":"Job is the job that decided State. A run reports one conclusion for\nhowever many jobs it holds, and the jobs are not interchangeable: the\npipeline fails at `gate` before it builds anything and at `receipt` after\nit has already built, pinned and proved the release live. Both read\n`failure` on the run, and only the first one means nothing shipped.","type":"string"},"number":{"format":"int64","type":"integer"},"state":{"description":"State is success | failure | running | absent. `absent` is not a kind of\nfailure and is kept apart from one: a failing run is a build that ran and\nsaid no, while an absent run is Hanzo Git never having constructed a run\nfor the commit at all — a workflow it cannot parse or a reference it\ncannot resolve. There is no log to open for the second, so a page that\ndraws them the same sends you looking for one that does not exist.","type":"string"},"tested":{"description":"Tested reports that the run's tests executed; Verdict reports that the run\nsaid anything about tests at all. They are separate because the interesting\ncase is a run that passed while its test step was skipped — a green build\nthat proved nothing — and that is invisible if the two are one flag.","type":"boolean"},"url":{"type":"string"},"verdict":{"type":"boolean"}},"type":"object"},"ci.Execution":{"properties":{"actor":{"type":"string"},"branch":{"type":"string"},"conclusion":{"type":"string"},"endedAt":{"format":"date-time","type":"string"},"event":{"type":"string"},"id":{"format":"int64","type":"integer"},"number":{"format":"int64","type":"integer"},"org":{"type":"string"},"repo":{"type":"string"},"sha":{"type":"string"},"startedAt":{"format":"date-time","type":"string"},"status":{"description":"Status and Conclusion are BOTH required to know how a run went, and\nreading only one is wrong in a way that looks fine. Status answers\n\"is it over\" (queued | in_progress | completed); Conclusion answers\n\"how did it end\" and is empty until it is over. A view that buckets on\nStatus alone sees `completed` and cannot tell a pass from a failure, so\nit draws every finished run — successes and cancellations included — the\nsame way.","type":"string"},"title":{"type":"string"},"url":{"type":"string"},"workflow":{"type":"string"}},"type":"object"},"ci.Executions":{"properties":{"fetchedAt":{"format":"date-time","type":"string"},"orgs":{"items":{"type":"string"},"type":"array"},"repos":{"format":"int64","type":"integer"},"runs":{"items":{"$ref":"#/components/schemas/ci.Execution"},"type":"array"},"sourceErr":{"type":"string"},"stale":{"type":"boolean"}},"type":"object"},"ci.Pipeline":{"properties":{"behind":{"description":"Behind counts commits after the one that last produced an image whose own\nbuild has FINISHED without producing one, and Since is when the oldest of\nthem landed. A commit still building is not counted, so a push in flight is\nnot drift and a service appears here only once something has actually\nstopped without shipping. How long that has stood is the number worth\nacting on; that it is true says nothing about whether anyone should move.","format":"int64","type":"integer"},"built":{"$ref":"#/components/schemas/ci.Artifact"},"declared":{"$ref":"#/components/schemas/ci.Artifact"},"drift":{"items":{"type":"string"},"type":"array"},"head":{"$ref":"#/components/schemas/ci.Tip"},"image":{"description":"ghcr.io/hanzoai/cloud","type":"string"},"name":{"description":"cloud","type":"string"},"namespace":{"description":"hanzo","type":"string"},"org":{"description":"Hanzo Git owner; empty when the repo is unresolved","type":"string"},"pinnedAt":{"format":"date-time","type":"string"},"ready":{"format":"int64","type":"integer"},"repo":{"description":"hanzo-inc/cloud","type":"string"},"running":{"$ref":"#/components/schemas/ci.Artifact"},"since":{"format":"date-time","type":"string"},"want":{"format":"int64","type":"integer"}},"type":"object"},"ci.Pipelines":{"properties":{"fetchedAt":{"format":"date-time","type":"string"},"orgs":{"items":{"type":"string"},"type":"array"},"services":{"items":{"$ref":"#/components/schemas/ci.Pipeline"},"type":"array"},"sourceErr":{"type":"string"},"stale":{"type":"boolean"}},"type":"object"},"ci.Tip":{"properties":{"at":{"format":"date-time","type":"string"},"build":{"$ref":"#/components/schemas/ci.Check"},"sha":{"type":"string"},"title":{"type":"string"}},"type":"object"},"cloudflare.D1Query":{"properties":{"params":{"description":"Params are the statement's bound values, in the order its `?` placeholders\nappear — a string, a number, a boolean or null, whatever the column takes.\nAbsent means the statement carries no placeholders; bind values here rather\nthan interpolating them into the statement.","items":{},"type":"array"},"sql":{"description":"SQL is the statement to run. Blank (or absent) is refused before anything\nreaches D1.","type":"string"}},"type":"object"},"cloudflare.PagesBuildConfig":{"properties":{"build_command":{"description":"BuildCommand is what Cloudflare runs to build the site (\"npm run build\").\nOmitted means no build step: the repository is published as it stands.","type":"string"},"destination_dir":{"description":"DestinationDir is the directory the build leaves the site in (\"dist\"),\nrelative to RootDir. It is what gets served.","type":"string"},"root_dir":{"description":"RootDir is where in the repository the build runs, for a project that is not at\nthe repository root. Omitted means the root.","type":"string"}},"type":"object"},"cloudflare.PagesD1Binding":{"properties":{"id":{"description":"ID is the D1 database this binding points at, by Cloudflare's uuid. The binding\nname the Worker code reads it as is the map key, not a field here.","type":"string"}},"type":"object"},"cloudflare.PagesDeploymentConfig":{"properties":{"compatibility_date":{"description":"CompatibilityDate pins which Workers runtime behaviour the functions run under,\nas a date (\"2024-01-01\"). It is a pin, not a version: the runtime keeps that\ndate's semantics for code deployed against it.","type":"string"},"compatibility_flags":{"description":"CompatibilityFlags turn individual runtime behaviours on or off ahead of, or\nbehind, the date above (\"nodejs_compat\").","items":{"type":"string"},"type":"array"},"d1_databases":{"additionalProperties":{"$ref":"#/components/schemas/cloudflare.PagesD1Binding"},"description":"D1Databases binds D1 databases in, keyed by binding name.","type":"object"},"env_vars":{"additionalProperties":{"$ref":"#/components/schemas/cloudflare.PagesEnvVar"},"description":"EnvVars are the environment variables the functions see, KEYED BY VARIABLE NAME.\nThe key is the name; the value carries the value and whether it is a secret.","type":"object"},"kv_namespaces":{"additionalProperties":{"$ref":"#/components/schemas/cloudflare.PagesKVBinding"},"description":"KVNamespaces binds KV namespaces into the functions, KEYED BY THE BINDING NAME\nthe code reads (`env.SESSIONS`). Same shape for the two below.","type":"object"},"r2_buckets":{"additionalProperties":{"$ref":"#/components/schemas/cloudflare.PagesR2Binding"},"description":"R2Buckets binds R2 buckets in, keyed by binding name.","type":"object"}},"type":"object"},"cloudflare.PagesDeploymentConfigs":{"properties":{"preview":{"$ref":"#/components/schemas/cloudflare.PagesDeploymentConfig","description":"Preview is the config every branch build other than the production branch runs\nunder. It is a SEPARATE set of bindings and variables, which is what lets a\npreview point at test data."},"production":{"$ref":"#/components/schemas/cloudflare.PagesDeploymentConfig","description":"Production is the config the production branch builds under."}},"type":"object"},"cloudflare.PagesEnvVar":{"properties":{"type":{"description":"Type is \"plain_text\" or \"secret_text\" and decides that: plain text is readable\nafterwards, secret text is write-only. Empty is Cloudflare's default,\nplain_text — so a secret with no type set is stored in the clear.","type":"string"},"value":{"description":"Value is the variable's value. Under type \"secret_text\" Cloudflare encrypts it\non arrival and never reads it back, so a later read of the project shows the\nvariable without this.","type":"string"}},"type":"object"},"cloudflare.PagesKVBinding":{"properties":{"namespace_id":{"description":"NamespaceID is the KV namespace this binding points at, by Cloudflare's id\nrather than its title. The BINDING NAME — what the Worker code reads it as — is\nthe map key this value sits under, not a field here.","type":"string"}},"type":"object"},"cloudflare.PagesProjectCreate":{"properties":{"build_config":{"$ref":"#/components/schemas/cloudflare.PagesBuildConfig","description":"BuildConfig says how to build the site. Omitted means no build step."},"deployment_configs":{"$ref":"#/components/schemas/cloudflare.PagesDeploymentConfigs","description":"DeploymentConfigs carries the preview and production runtime configs — the\nbindings and variables the built site's functions run with."},"name":{"description":"Name is the project name, and it is also the address: the site answers at\n\u003cname\u003e.pages.dev. Cloudflare will not rename a project afterwards.","type":"string"},"production_branch":{"description":"ProductionBranch is which git branch builds to production; every other branch\nbuilds a preview. Omitted leaves Cloudflare's own default.","type":"string"}},"type":"object"},"cloudflare.PagesR2Binding":{"properties":{"name":{"description":"Name is the R2 bucket this binding points at, by bucket name — R2 addresses\nbuckets by name where KV and D1 use ids. The binding name the Worker code reads\nit as is the map key.","type":"string"}},"type":"object"},"cloudflare.WorkerScriptPut":{"properties":{"bindings":{"description":"Bindings are the resources the script can reach (KV, D1, R2, secrets, …), in\nCloudflare's own binding vocabulary, passed through as written: this plane\ndeliberately does not model Cloudflare's shapes. Absent uploads a script with\nNO bindings, which replaces whatever the previous version had."},"compatibilityDate":{"description":"CompatibilityDate pins which Workers runtime behaviour the script runs under,\nas a plain calendar date (\"2024-01-01\"). Absent leaves the account's own\ndefault in force.","type":"string"},"compatibilityFlags":{"description":"CompatibilityFlags turn individual runtime behaviours on or off around that\ndate (\"nodejs_compat\"), in Cloudflare's own flag vocabulary. Absent means the\ndate alone decides.","items":{"type":"string"},"type":"array"},"mainModule":{"description":"MainModule is the module file the runtime starts at. Absent means \"worker.js\".","type":"string"},"script":{"description":"Script means two things on this route, and the document says so in both places\nit appears: the PATH segment names the Worker to publish, and the BODY field\ncarries that Worker's ES-module source — the code itself, never a name or a\nURL. A blank or absent source is refused; there is no empty Worker.","type":"string"}},"type":"object"},"cloudflare.bucketCreateIn":{"properties":{"name":{"description":"Name is the bucket name to create.","type":"string"}},"type":"object"},"cloudflare.databaseCreateIn":{"properties":{"name":{"description":"Name is the database name to create.","type":"string"}},"type":"object"},"cloudflare.domainAddIn":{"properties":{"name":{"description":"Name is the custom domain to attach, e.g. \"www.acme.com\".","type":"string"},"project":{"description":"Project is the Pages project name, from the path.","type":"string"}},"type":"object"},"cloudflare.namespaceCreateIn":{"properties":{"title":{"description":"Title is the namespace's display title. Cloudflare mints the id.","type":"string"}},"type":"object"},"cloudflare.purgeIn":{"properties":{"files":{"description":"Files purges exactly the listed URLs — at most 30, Cloudflare's per-request cap.","items":{"type":"string"},"type":"array"},"purge_everything":{"description":"Everything drops the zone's entire edge cache.","type":"boolean"},"zone":{"description":"Zone is the 32-hex Cloudflare zone id, from the path.","type":"string"}},"type":"object"},"cloudflare.routeCreateIn":{"properties":{"pattern":{"description":"Pattern is the URL pattern to bind, e.g. \"acme.com/api/*\".","type":"string"},"script":{"description":"Script is the Worker script to dispatch to. Omit it to leave the pattern\nbound to no script, which is how Cloudflare expresses \"bypass the Worker here\".","type":"string"},"zone":{"description":"Zone is the 32-hex Cloudflare zone id, from the path.","type":"string"}},"type":"object"},"cloudflare.subdomainSetIn":{"properties":{"enabled":{"description":"Enabled publishes the script on \u003cscript\u003e.\u003csubdomain\u003e.workers.dev when true,\nand withdraws it when false.","type":"boolean"},"script":{"description":"Script is the Worker script name, from the path.","type":"string"}},"type":"object"},"cluster.Serving":{"properties":{"modelId":{"type":"string"},"namespace":{"type":"string"},"provider":{"type":"string"},"service":{"type":"string"},"url":{"type":"string"}},"type":"object"},"code.AskAnswer":{"properties":{"answer":{"description":"Answer is the synthesized prose. EMPTY is a real answer here: nothing in the\nindex matched, or synthesis was unavailable — read `degraded` and `citations`\nto tell those apart. It is never written without grounding.","type":"string"},"citations":{"description":"Citations are the exact regions the answer was grounded on, and they are the\npoint: an answer is checkable only because every claim in it can be read back\nat a file and line. Present even when Answer is empty.","items":{"$ref":"#/components/schemas/code.Citation"},"type":"array"},"degraded":{"description":"Degraded is true when retrieval worked but no synthesizer was reachable. The\ncitations are still real code, so a caller can answer from them itself; a\ncaller that treats this like an error throws away a usable result.","type":"boolean"},"question":{"description":"Question is the ask, echoed back.","type":"string"}},"type":"object"},"code.Citation":{"properties":{"endLine":{"description":"EndLine is its last line, inclusive.","format":"int64","type":"integer"},"file":{"description":"File is the path inside the repo, relative to its root.","type":"string"},"line":{"description":"Line is the first line of the cited region, 1-based.","format":"int64","type":"integer"},"repo":{"description":"Repo is the repository the cited code lives in (\"owner/name\"), absent when the\nask was already scoped to one.","type":"string"},"symbol":{"description":"Symbol is the declaration the region belongs to, when it belongs to one.","type":"string"}},"type":"object"},"code.ContextBundle":{"properties":{"budgetTokens":{"description":"BudgetTokens is the ceiling the caller asked for. Packing stops under it, so\nthis is a bound and not a target.","format":"int64","type":"integer"},"capped":{"description":"Capped is true when the semantic tier stopped at its scan cap — it compares\na query with at most 50000 stored vectors — with more left unread, so code\npast the cap could not be picked by meaning. The lexical and symbol tiers\nread the whole index either way. Absent otherwise.","type":"boolean"},"query":{"description":"Query is the ask this bundle was packed for, echoed back so a cached or\nforwarded bundle still says what it answers.","type":"string"},"repo":{"description":"Repo narrows the retrieval to one repository. Absent means every indexed repo\nwas searched.","type":"string"},"spans":{"description":"Spans are the packed chunks, most relevant first, each expanded with the\ndefinitions it calls and its notable callers. The top match is always present\neven if it had to be truncated to fit, so a matched query never comes back\nwith nothing.","items":{"$ref":"#/components/schemas/code.Span"},"type":"array"},"usedTokens":{"description":"UsedTokens is what the returned spans actually cost, by the same estimate the\npacker used (roughly one token per four characters — an estimate, not a\ntokenizer's count, so size a real window with headroom).","format":"int64","type":"integer"}},"type":"object"},"code.Span":{"properties":{"endLine":{"description":"EndLine is the last line of the span, inclusive. It equals Line for a\none-line span rather than being zero or absent.","format":"int64","type":"integer"},"file":{"description":"File is the path inside the repo, relative to its root and never absolute.","type":"string"},"kind":{"description":"Kind is what the indexer decided this chunk IS — \"func\", \"method\", \"type\",\n\"struct\", \"interface\", \"var\", \"const\", or \"block\" for a run of code that\ndeclares nothing. Absent when the chunker could not classify it.","type":"string"},"line":{"description":"Line is where the span starts, 1-based, as an editor counts.","format":"int64","type":"integer"},"repo":{"description":"Repo is the indexed repository the span was found in, as it was indexed\n(\"owner/name\"). A search may be scoped to one repo or run across all of them,\nso this is how a caller tells the results apart.","type":"string"},"role":{"description":"context: match | definition | caller","type":"string"},"score":{"description":"Score ranks this span against the OTHERS IN THE SAME RESPONSE and means\nnothing across responses or between tiers: the hybrid tier's number is a\nreciprocal-rank fusion sum (Σ 1/(60+rank), so tenths at best), the symbol\ntier's is a descending position count, and the text and semantic tiers pass\nthrough bm25 and cosine. Compare within a list; never threshold on it.","format":"double","type":"number"},"snippet":{"description":"Snippet is the code itself: a bounded excerpt on /search, the whole chunk on\n/context — which is why the same type serves both and why a /context span is\nthe one an agent pastes into its window.","type":"string"},"symbol":{"description":"Symbol is the declared name, when the span declares one. Absent on a block.","type":"string"},"tier":{"description":"Tier is which retrieval produced the span: \"hybrid\" (the default — all three\nfused), \"text\" (trigram/FTS), \"regex\", \"semantic\" (vector), or \"symbol\". It is\nwhat explains a Score, so the two travel together.","type":"string"}},"type":"object"},"code.TreeEntry":{"properties":{"lang":{"description":"Lang is the language the indexer parsed the file as (\"go\", \"python\", …), or\nempty when it recognised none — in which case Symbols is 0 because nothing was\nextracted, not because the file declares nothing.","type":"string"},"path":{"description":"Path is the file, relative to the repo root. The list is ordered by it, so a\nreader can see module layout without sorting.","type":"string"},"symbols":{"description":"Symbols is how many top-level declarations the file defines. A file with none\nis still listed: the file set is the authority here and the counts decorate it.","format":"int64","type":"integer"}},"type":"object"},"code.askPostIn":{"properties":{"query":{"description":"Query is the question, from the BODY. Takes precedence over `?q=`.","type":"string"},"repo":{"description":"Repo is the repository narrowing, from the BODY. Takes precedence over `?repo=`.","type":"string"}},"type":"object"},"code.contextIn":{"properties":{"budgetTokens":{"description":"BudgetTokens caps the bundle's size. Clamped to [256, 32000]; 0 or absent\nuses 4000.","format":"int64","type":"integer"},"query":{"description":"Query is what to retrieve context for. Required, max 4000 bytes.","type":"string"},"repo":{"description":"Repo narrows retrieval to one repository. Empty searches every repo the org\nhas indexed.","type":"string"}},"type":"object"},"code.fileContent":{"properties":{"content":{"description":"Content is the file's text as the index stored it. It is NOT guaranteed\nbyte-verbatim — the git object plane is the source of record for exact\nbytes, history and blame.","type":"string"},"lang":{"description":"Lang is the detected language.","type":"string"},"path":{"description":"Path echoes the file that was read.","type":"string"},"repo":{"description":"Repo echoes the repository it came from.","type":"string"}},"type":"object"},"code.fileInput":{"properties":{"content":{"description":"Content is the file's full text. Max 1 MiB per file; binary files should\nsimply be omitted rather than sent.","type":"string"},"path":{"description":"Path is the file's repo-relative path, e.g. \"internal/store/db.go\".","type":"string"}},"type":"object"},"code.indexIn":{"properties":{"files":{"description":"Files is the full set of files to index. Required and non-empty; max 20000\nfiles, 1 MiB per file and 1 GiB in total. Unchanged files are skipped by\ncontent hash, so re-sending the whole tree is cheap.","items":{"$ref":"#/components/schemas/code.fileInput"},"type":"array"},"prune":{"description":"Prune deletes indexed files that are NOT in this request — which makes the\ncall a full sync of the repo rather than an upsert. Only pass it when Files\nis the complete tree.","type":"boolean"},"repo":{"description":"Repo is the repository label to index under. Required, max 200 bytes. It is\na stored column value, not a filesystem path.","type":"string"}},"type":"object"},"code.indexResult":{"properties":{"chunks":{"description":"Chunks is how many AST-boundary chunks the repo holds after this pass.","format":"int64","type":"integer"},"files":{"description":"Files is how many files the repo holds after this pass.","format":"int64","type":"integer"},"indexed":{"description":"Indexed is how many files were parsed and written on this pass.","format":"int64","type":"integer"},"pruned":{"description":"Pruned is how many stored files were deleted because prune was set and they\nwere absent from the request.","format":"int64","type":"integer"},"repo":{"description":"Repo is the repository that was indexed.","type":"string"},"semantic":{"description":"Semantic reports whether the semantic tier was available for this pass. When\nfalse the index is lexical + symbolic only and hybrid search still works.","type":"boolean"},"skipped":{"description":"Skipped is how many files were unchanged by content hash and left alone.","format":"int64","type":"integer"},"symbols":{"description":"Symbols is how many symbol definitions the repo holds after this pass.","format":"int64","type":"integer"},"vectors":{"description":"Vectors is how many of those chunks carry an embedding.","format":"int64","type":"integer"}},"type":"object"},"code.repoTree":{"properties":{"files":{"description":"Files are the repo's indexed files in path order, each with its language\nand how many symbols it defines. Never null.","items":{"$ref":"#/components/schemas/code.TreeEntry"},"type":"array"},"repo":{"description":"Repo echoes the repository that was walked.","type":"string"}},"type":"object"},"code.searchResults":{"properties":{"capped":{"description":"Capped is true when the semantic tier stopped at its scan cap — it compares\na query with at most 50000 stored vectors — with more left unread, so a\nchunk past the cap could not be found by meaning. The text, regex and\nsymbol tiers read the whole index either way. Absent otherwise.","type":"boolean"},"degraded":{"description":"Degraded is true when retrieval failed and the empty result set is an\noutage rather than a real absence of matches. Absent on a healthy answer.","type":"boolean"},"query":{"description":"Query echoes the query that was run.","type":"string"},"results":{"description":"Results are the matching spans, best first. Never null — an empty search is\nan empty array.","items":{"$ref":"#/components/schemas/code.Span"},"type":"array"},"type":{"description":"Type echoes the retrieval tier that ran, after defaulting.","type":"string"}},"type":"object"},"company.Charge":{"properties":{"amountCents":{"description":"AmountCents is what this line costs.","format":"int64","type":"integer"},"asOf":{"description":"AsOf is when a pass-through amount was last checked against its source.","type":"string"},"code":{"description":"Code names the line so a caller can branch on it without reading prose.","type":"string"},"label":{"description":"Label is what the payer sees on the invoice.","type":"string"},"passThrough":{"description":"PassThrough marks money we collect and remit rather than keep — the state's\nfee is not our revenue, and a quote that hides that is a quote that reads\nas a bigger margin than it is.","type":"boolean"},"recurring":{"description":"Recurring marks a line that repeats. An agent of record is billed every\nyear for as long as the entity stands, and a payer agreeing to a one-time\ntotal is not agreeing to that.","type":"string"},"source":{"description":"Source names who publishes this amount, for a line we merely pass through.\nEmpty for a price of ours, which needs no external authority.","type":"string"},"stale":{"description":"Stale reports that AsOf is older than the review window — the figure may\nhave moved and nobody has looked. It does not block; it tells.","type":"boolean"}},"type":"object"},"company.EIN":{"properties":{"expedited":{"description":"Expedited reports that prioritised handling was asked for.","type":"boolean"},"forms":{"description":"Forms are the forms this application owes, with what each is for.","items":{"$ref":"#/components/schemas/company.Form"},"type":"array"},"naics":{"description":"NAICS is the six-digit code for what the business does. The SS-4 asks it\nand the IRS will not process an application without one.","type":"string"},"number":{"description":"Number is the issued EIN, absent until the IRS issues it.","type":"string"},"online":{"description":"Online reports that this application can be filed with the IRS online and\nissued in a sitting, rather than signed and posted. It is the single fact\nthat decides how long a customer waits, so it is answered rather than\nimplied by the absence of forms.","type":"boolean"},"responsible":{"$ref":"#/components/schemas/company.Responsible","description":"Responsible is the person the IRS holds answerable."},"status":{"description":"Status is how far it has got.","type":"string"}},"type":"object"},"company.Filing":{"properties":{"at":{"description":"At is the unix second the filing record was written.","format":"int64","type":"integer"},"note":{"description":"Note explains a filing Hanzo did not perform itself: what remains to be done\nand by whom.","type":"string"},"provider":{"description":"Provider is the filing partner that performed the filing, or \"manual\" when no\npartner is wired.","type":"string"},"ref":{"description":"Ref is the partner's or the state's filing reference. Empty when nothing was\nactually filed — no filing id is ever fabricated.","type":"string"},"status":{"description":"Status is manual (no partner wired — a registered agent files out-of-band),\nsubmitted (the partner accepted it, awaiting the state), filed (the state\naccepted it) or rejected.","type":"string"}},"type":"object"},"company.Form":{"properties":{"code":{"description":"Code is the IRS designation, e.g. \"SS-4\".","type":"string"},"name":{"description":"Name is the form's own title, so a reader need not already know the code.","type":"string"},"signed":{"description":"Signed reports whether we hold the signature.","type":"boolean"},"why":{"description":"Why states what this form is for in this application — the same form is\nowed for different reasons on different paths.","type":"string"}},"type":"object"},"company.Formation":{"properties":{"alreadyIncorporated":{"description":"AlreadyIncorporated declares an org that already has a legal entity, which\ntakes the import path (structure → import → company) instead of forming one.","type":"boolean"},"capTableImported":{"description":"CapTableImported reports whether the existing company's cap table has been\nimported onto the canonical cap table.","type":"boolean"},"createdAt":{"description":"CreatedAt is the unix second the formation was opened.","format":"int64","type":"integer"},"documentIds":{"description":"DocumentIDs are the data room ids of the GENERATED formation documents.","items":{"type":"string"},"type":"array"},"esignRef":{"description":"EsignRef is the e-signature provider's reference for the signature request.","type":"string"},"filing":{"$ref":"#/components/schemas/company.Filing","description":"Filing is the state-of-incorporation filing record, once documents exist."},"founders":{"description":"Founders is every founding stakeholder, with its equity split and KYC state.","items":{"$ref":"#/components/schemas/company.Founder"},"type":"array"},"genesis":{"$ref":"#/components/schemas/company.Genesis","description":"Genesis is the cap-table equity genesis, once recorded."},"imported":{"description":"Imported reports whether the existing company's corporate documents have been\ningested into the org's data room.","type":"boolean"},"importedDocs":{"description":"ImportedDocs are the data room ids of the documents ingested from Drive.","items":{"type":"string"},"type":"array"},"jurisdiction":{"description":"Jurisdiction is the state of formation: DE or WY.","type":"string"},"name":{"description":"Name is the company name the entity is being formed under.","type":"string"},"org":{"description":"Org is the owning org — the tenant key, and the reason there is exactly one\nformation per org.","type":"string"},"paid":{"description":"Paid reports whether the one-time formation fee has been charged.","type":"boolean"},"paymentRef":{"description":"PaymentRef is the billing reference recorded for the charged formation fee on\nthe org's own ledger.","type":"string"},"signed":{"description":"Signed reports whether the formation documents have come back signed — the\ne-signature provider's answer, which a real provider's webhook drives.","type":"boolean"},"stage":{"description":"Stage is the machine's current state: structure, founders, payment, documents,\nesign or genesis on the formation path, import on the skip path, and company\nat the terminal.","type":"string"},"structure":{"description":"Structure is the legal entity being formed: c-corp, llc or dao-llc.","type":"string"},"updatedAt":{"description":"UpdatedAt is the unix second of the most recent write to the formation.","format":"int64","type":"integer"}},"type":"object"},"company.Founder":{"properties":{"decidedBy":{"description":"DecidedBy is who settled a terminal KYC status: the provider name, or a\nreviewer's user id.","type":"string"},"email":{"description":"Email is the founder's email, and the key a KYC decision addresses a founder\nby — POST /v1/company/kyc/decision matches on it.","type":"string"},"equityBps":{"description":"EquityBps is the founder's ownership in basis points, 0–10000 (1% == 100 bps,\nso 10000 is the whole company). The founders' shares seed the cap-table genesis.","format":"int64","type":"integer"},"kycRef":{"description":"KYCRef is the idv provider's session reference for this founder.","type":"string"},"kycStatus":{"description":"KYCStatus is the founder's identity-verification state: pending, verified (a\nreal idv provider reported a pass), reviewer_confirmed (a privileged reviewer\nconfirmed out-of-band) or failed. The payment stage is unreachable until every\nfounder passes.","type":"string"},"name":{"description":"Name is the founder's full legal name, as it appears on the formation documents.","type":"string"}},"type":"object"},"company.Genesis":{"properties":{"at":{"description":"At is the unix second the genesis root was computed.","format":"int64","type":"integer"},"block":{"description":"Block is the L1 block the anchoring transaction landed in. Set only once the\nreceipt has been read; absent otherwise.","format":"uint64","type":"integer"},"chainId":{"description":"ChainID is the EVM chain the root is committed to — the Hanzo L1 by default.","format":"int64","type":"integer"},"note":{"description":"Note explains an unanchored genesis honestly — anchor wiring absent, or the\nsubmit error — rather than reporting a commit that did not happen.","type":"string"},"root":{"description":"Root is the 0x-prefixed keccak256 root of the founding allocation. It is\nALWAYS computed, whether or not the on-chain anchor is wired, because the root\nis the tamper-evident witness.","type":"string"},"status":{"description":"Status is pending (root computed, not yet on-chain) or anchored (committed).","type":"string"},"txHash":{"description":"TxHash is the L1 transaction hash of the anchoring commit. Empty until anchored.","type":"string"}},"type":"object"},"company.Registration":{"properties":{"createdAt":{"description":"CreatedAt is the unix second the formation was opened.","format":"int64","type":"integer"},"name":{"description":"Name is the company name the entity is being formed under.","type":"string"},"org":{"description":"Org is the org whose formation this row projects.","type":"string"},"stage":{"description":"Stage is the formation's current state — what the platform reads to see which\nformations are stalled and where.","type":"string"},"structure":{"description":"Structure is the legal entity being formed: c-corp, llc or dao-llc.","type":"string"},"updatedAt":{"description":"UpdatedAt is the unix second of the most recent write to the formation, and\nthe key the register sorts on (newest activity first).","format":"int64","type":"integer"}},"type":"object"},"company.Responsible":{"properties":{"country":{"description":"Country is where they reside, ISO 3166-1 alpha-2.","type":"string"},"email":{"description":"Email reaches them for signature.","type":"string"},"name":{"description":"Name is their full legal name as the IRS will hold it.","type":"string"},"usTaxId":{"description":"USTaxID reports that they hold an SSN or ITIN. It is a BOOLEAN on purpose:\nthe number itself is never needed here and a field that could hold it is a\nfield that will eventually be logged.","type":"boolean"}},"type":"object"},"company.RoundInput":{"properties":{"name":{"description":"Name is the round's name on the cap table, e.g. \"Seed\". Required.","type":"string"},"preMoneyValuation":{"description":"PreMoneyValuation is the valuation the round prices off, before the new money.","format":"double","type":"number"},"pricePerShare":{"description":"PricePerShare is the per-share price of a priced round.","format":"double","type":"number"},"roundType":{"description":"RoundType is PRICED, SAFE or CONVERTIBLE_NOTE. Defaults to PRICED.","type":"string"},"shareClassId":{"description":"ShareClassID is the cap table's share class the round issues into.","type":"string"},"targetAmount":{"description":"TargetAmount is the amount the round is raising, recorded verbatim on the\ncanonical cap table's rounds.create contract.","format":"double","type":"number"}},"type":"object"},"company.Signer":{"properties":{"email":{"description":"Email is the address the signature request is sent to.","type":"string"},"name":{"description":"Name is the recipient's name, as it appears on the signature request.","type":"string"}},"type":"object"},"company.Tariff":{"properties":{"currency":{"description":"Currency is the ISO code every amount on this quote is denominated in.","type":"string"},"dueNowCents":{"description":"DueNowCents is what is charged to begin: every non-recurring line.","format":"int64","type":"integer"},"jurisdiction":{"description":"Jurisdiction is the state of formation the filing fee belongs to.","type":"string"},"lines":{"description":"Lines are the charges, in the order a reader should see them.","items":{"$ref":"#/components/schemas/company.Charge"},"type":"array"},"recurring":{"description":"Recurring is how often RecurringCents repeats — \"yearly\" for an agent of\nrecord. Empty when nothing on this quote recurs.","type":"string"},"recurringCents":{"description":"RecurringCents is what repeats, and Recurring says how often.","format":"int64","type":"integer"},"structure":{"description":"Structure is the entity this prices: c-corp, llc or dao-llc.","type":"string"}},"type":"object"},"company.advanceIn":{"properties":{"to":{"description":"To is the target stage: structure, founders, payment, documents, esign,\ngenesis, import or company.","type":"string"}},"type":"object"},"company.beginIn":{"properties":{"alreadyIncorporated":{"description":"AlreadyIncorporated declares an org that already has an entity, which takes\nthe import path (POST /v1/company/skip) instead of the formation path.","type":"boolean"},"jurisdiction":{"description":"Jurisdiction is the state of formation: DE or WY.","type":"string"},"name":{"description":"Name is the proposed company name.","type":"string"},"structure":{"description":"Structure is the legal entity to form: c-corp, llc or dao-llc.","type":"string"}},"type":"object"},"company.einIn":{"properties":{"expedited":{"description":"Expedited asks for prioritised handling. Only meaningful when the\nresponsible party cannot file online.","type":"boolean"},"naics":{"description":"NAICS is the six-digit code for what the business does.","type":"string"},"responsible":{"$ref":"#/components/schemas/company.Responsible","description":"Responsible is the person the IRS holds answerable for the entity."}},"type":"object"},"company.esignCompleteIn":{"properties":{"signed":{"description":"Signed, when present, overrides what the provider reports — the manual path\nfor a provider whose webhook is not wired. Omit it to take the provider's answer.","type":"boolean"}},"type":"object"},"company.esignOut":{"properties":{"esignRef":{"description":"EsignRef is the provider's reference for the signature request.","type":"string"},"formation":{"$ref":"#/components/schemas/company.Formation","description":"Formation is the org's incorporation record with the reference recorded on it."},"provider":{"description":"Provider is the wired e-signature provider's name.","type":"string"}},"type":"object"},"company.formationView":{"properties":{"formation":{"$ref":"#/components/schemas/company.Formation","description":"Formation is the org's one incorporation record."},"nextStages":{"description":"NextStages are the stages reachable from the formation's current stage,\nwhether or not their guards are satisfied yet.","items":{"type":"string"},"type":"array"}},"type":"object"},"company.foundersIn":{"properties":{"founders":{"description":"Founders is every founding stakeholder. Each needs a name and an email, and\nequityBps between 0 and 10000 (1% == 100 bps).","items":{"$ref":"#/components/schemas/company.Founder"},"type":"array"}},"type":"object"},"company.importCapTableIn":{"properties":{"range":{"description":"Range is an optional A1 range within the sheet; empty reads the default range.","type":"string"},"spreadsheetId":{"description":"SpreadsheetID is a Google Sheets id. Required.","type":"string"}},"type":"object"},"company.importCapTableOut":{"properties":{"formation":{"$ref":"#/components/schemas/company.Formation","description":"Formation is the org's incorporation record, now marked cap-table-imported."},"rows":{"description":"Rows is how many rows were read from the sheet, header included.","format":"int64","type":"integer"},"stakeholdersImported":{"description":"StakeholdersImported is how many stakeholders the cap table accepted.","format":"int64","type":"integer"}},"type":"object"},"company.importDocumentsIn":{"properties":{"folderId":{"description":"FolderID is a Google Drive folder id. Required.","type":"string"}},"type":"object"},"company.importDocumentsOut":{"properties":{"formation":{"$ref":"#/components/schemas/company.Formation","description":"Formation is the org's incorporation record with the imported document ids."},"ingested":{"description":"Ingested is how many files this call put in the data room.","format":"int64","type":"integer"}},"type":"object"},"company.kycRefreshOut":{"properties":{"formation":{"$ref":"#/components/schemas/company.Formation","description":"Formation is the org's incorporation record with each founder's reconciled status."},"provider":{"description":"Provider is the identity-verification provider that was consulted.","type":"string"}},"type":"object"},"company.kycSession":{"properties":{"email":{"description":"Email is the founder the session belongs to.","type":"string"},"ref":{"description":"Ref is the provider's reference for the session.","type":"string"},"status":{"description":"Status is the session's status at start, which is always pending.","type":"string"},"verifyUrl":{"description":"VerifyURL is the hosted flow the founder visits; empty for the manual provider.","type":"string"}},"type":"object"},"company.kycStartOut":{"properties":{"formation":{"$ref":"#/components/schemas/company.Formation","description":"Formation is the org's incorporation record, with each founder's session\nreference and status recorded on it."},"provider":{"description":"Provider is the wired identity-verification provider's name.","type":"string"},"sessions":{"description":"Sessions is one entry per founder, in the order the founders are recorded.","items":{"$ref":"#/components/schemas/company.kycSession"},"type":"array"}},"type":"object"},"company.registerCounts":{"properties":{"byStage":{"additionalProperties":{"format":"int64","type":"integer"},"description":"ByStage counts formations per stage, keyed by the stage name.","type":"object"},"total":{"description":"Total is every formation in the register.","format":"int64","type":"integer"}},"type":"object"},"company.registerPage":{"properties":{"count":{"description":"Count is how many rows this page holds.","format":"int64","type":"integer"},"formations":{"description":"Formations are the rows, newest activity first.","items":{"$ref":"#/components/schemas/company.Registration"},"type":"array"},"limit":{"description":"Limit is the page size that was applied.","format":"int64","type":"integer"},"offset":{"description":"Offset is the offset that was applied.","format":"int64","type":"integer"}},"type":"object"},"company.reviewQueue":{"properties":{"count":{"description":"Count is how many founders are waiting.","format":"int64","type":"integer"},"queue":{"description":"Queue is one entry per unsettled founder, oldest formation first.","items":{"$ref":"#/components/schemas/company.waiting"},"type":"array"}},"type":"object"},"company.roundOut":{"properties":{"roundId":{"description":"RoundID is the cap table's id for the recorded round.","type":"string"}},"type":"object"},"company.safeIn":{"properties":{"documentIds":{"description":"DocumentIDs are data room document ids to raise a signature request over. Required.","items":{"type":"string"},"type":"array"},"signers":{"description":"Signers are the recipients, each a name and an email. Required.","items":{"$ref":"#/components/schemas/company.Signer"},"type":"array"}},"type":"object"},"company.safeOut":{"properties":{"esignRef":{"description":"EsignRef is the provider's reference for the signature request.","type":"string"},"provider":{"description":"Provider is the wired e-signature provider's name.","type":"string"}},"type":"object"},"company.structureIn":{"properties":{"jurisdiction":{"description":"Jurisdiction is the state of formation: DE or WY.","type":"string"},"name":{"description":"Name is the proposed company name.","type":"string"},"structure":{"description":"Structure is the legal entity: c-corp, llc or dao-llc.","type":"string"}},"type":"object"},"company.tariffIn":{"properties":{"agentOfRecord":{"description":"AgentOfRecord puts us on file as the entity's agent, yearly.","type":"boolean"},"expeditedEin":{"description":"ExpeditedEIN prioritises the EIN.","type":"boolean"},"jurisdiction":{"description":"Jurisdiction is the state of formation.","type":"string"},"structure":{"description":"Structure is the entity being formed: c-corp, llc or dao-llc.","type":"string"}},"type":"object"},"company.waiting":{"properties":{"email":{"description":"Email is the founder's email — the key a decision is posted against.","type":"string"},"founder":{"description":"Founder is the founder's name.","type":"string"},"kycRef":{"description":"KYCRef is the identity-verification session reference, when one was opened.","type":"string"},"kycStatus":{"description":"KYCStatus is the founder's unsettled status.","type":"string"},"name":{"description":"Name is the proposed company name.","type":"string"},"org":{"description":"Org is the tenant whose formation the founder belongs to.","type":"string"},"since":{"description":"Since is when the formation was last touched, as a unix second.","format":"int64","type":"integer"}},"type":"object"},"compliance.Act":{"properties":{"name":{"description":"Name is the operator's IAM username.","type":"string"},"owner":{"description":"Owner is the org of the operator's IAM row: \"admin\" for a SuperAdmin.","type":"string"},"sub":{"description":"Sub is the operator's IAM subject.","type":"string"}},"type":"object"},"compliance.Subject":{"properties":{"createdAt":{"description":"CreatedAt is when the subject was first recorded, Unix SECONDS.","format":"int64","type":"integer"},"email":{"description":"Email is the party's address, when the org supplied one. It is PII: sealed at\nrest, returned only to the owning org, and never copied into a check record.","type":"string"},"id":{"description":"ID is the opaque handle every other record uses to point at this party. It is\nthe only reference that leaves this type, which is what keeps the PII in one\nplace: a check, an accreditation and an audit row all carry the id and none of\nthem carry the name.","type":"string"},"kind":{"description":"Kind is what is being verified: \"individual\" (a natural person, so KYC) or\n\"business\" (a legal entity, so KYB). It decides which provider flow runs.","type":"string"},"name":{"description":"Name is the party's name, under the same PII rule as Email. For a business it\nis the legal entity name rather than a trading name, since that is what a\nprovider verifies against.","type":"string"},"org":{"description":"Org is the tenant that is doing the verifying — the party who must answer for\nthis record, not the party being verified. A subject is returned only to it.","type":"string"},"ref":{"description":"Ref is the org's OWN identifier for this party, carried so a caller can match a\nsubject back to their system without keeping a second mapping. Opaque here:\nnothing in this plane parses or enforces it.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the subject's own fields last changed, Unix seconds. A check\nmoving to a new status does not touch it — that history lives on the check.","format":"int64","type":"integer"}},"type":"object"},"compliance.Wire":{"properties":{"act":{"$ref":"#/components/schemas/compliance.Act","description":"Act is present ONLY on an action taken in a support session: the platform\noperator IAM signed in AS this row's sub, while org, sub and email stay the\nperson's. A console row carrying `act` was done by the operator it names."},"action":{"description":"Action is the verb that was performed. It is the event's name, not the HTTP\nmethod — a request-sourced record carries both, and the pair is what makes a\nrow readable (\"grant.create\" at POST /v1/admin/grants).","type":"string"},"after":{"description":"After is the changed thing as the action left it, redacted the same way."},"agent":{"description":"Agent is present ONLY on an action a delegated token took: who acted for\nthis row's sub — the deployment that ran their work in a sandbox — while\norg, sub and email stay the person's, who is billed for it.","type":"string"},"authMethod":{"description":"Auth is the credential the actor presented: \"jwt\", \"api-key\", or \"none\".","type":"string"},"before":{"description":"Before is the changed thing as it stood before the action, as JSON, with every\nsecret-shaped field already redacted. Only an emit point that changed something\nsets it; a request-sourced row never does."},"email":{"description":"Email is the actor's validated address, absent when the credential carried\nnone. It comes from the verified token, never from a client header.","type":"string"},"hash":{"description":"Hash is this record's SHA-256 over its own canonical JSON with both hash\nfields cleared, folded with prevHash. Recomputing it from the row's other\nfields is what proves the row has not been edited.","type":"string"},"home":{"description":"Home is present ONLY on a cross-org action: the org the actor came FROM,\nwhile Org is the org they acted IN. A console row carrying `home` is a\nplatform-admin impersonation and should be rendered as one.","type":"string"},"isAdmin":{"description":"IsAdmin is the VALIDATED platform-SuperAdmin bit at decision time\n(owner == \"admin\", principal.Super), never the client's own claim to be one.","type":"boolean"},"method":{"description":"Method is the HTTP verb, on a record a request produced. Absent on an event\nemitted from inside the binary with no request behind it.","type":"string"},"org":{"description":"Org is the tenant the action was taken IN — the effective org, which for\neveryone but an impersonating SuperAdmin is also the actor's own. Empty on an\nunauthenticated request.","type":"string"},"path":{"description":"Path is the request's route. Any segment shaped like a credential is replaced\nbefore the record is written, so a key that rides in a path is not preserved\nhere by the very control meant to watch it.","type":"string"},"prevHash":{"description":"PrevHash is the hash of record seq-1, which is what links the rows into a\nchain: a deleted or reordered record breaks the recomputation at that point.\nThe first record of a chain carries 64 zeros rather than an empty string, so\n\"start of chain\" and \"field missing\" cannot look alike.","type":"string"},"reason":{"description":"Reason is a short explanation for a deny or an error (\"SuperAdmin required\",\n\"insufficient_balance\"). It is never a secret and never a raw upstream error\nbody; absent on a success.","type":"string"},"requestId":{"description":"RequestID ties this row to the request-line log and any downstream trace — the\nX-Request-Id the pipeline minted for that request.","type":"string"},"resource":{"description":"Resource is the KIND of thing acted upon (\"org\", \"role\", \"secret\",\n\"provider-config\", \"credit\"). Where a mutation has no finer semantics than its\nroute, this is the route family and resourceId is empty — the action and the\npath already pin the object.","type":"string"},"resourceId":{"description":"ResourceID is the specific instance, absent when the kind alone identifies it.","type":"string"},"result":{"description":"Result is how the action ended: \"success\", \"deny\" or \"error\". A deny is a\ndecision this binary made and is as much evidence as a success.","type":"string"},"seq":{"description":"Seq is the record's position in the chain, 0-based and gapless. The Recorder\nassigns it under its own lock, so it is a true total order: seq n+1 was\nwritten after seq n, and a missing number is a missing record.","format":"uint64","type":"integer"},"sourceIp":{"description":"SourceIP is the client address the edge resolved for the request, after the\nproxy chain — the address a responder would act on, not the socket peer.","type":"string"},"status":{"description":"Status is the HTTP status the caller received. It is the outcome as the client\nsaw it, so a 200 carrying a domain refusal still reads 200 here.","format":"int64","type":"integer"},"sub":{"description":"Sub is the acting user (the IAM subject). Empty for a machine principal or an\nanonymous request, which is how a service action is told from a person's.","type":"string"},"time":{"description":"Time is when the action happened, RFC3339Nano in UTC. The stored column has\nthe same precision and sorts the same way, so a client can range and order on\nthis string verbatim.","type":"string"},"userAgent":{"description":"UserAgent is the client the request announced itself as. Client-supplied, so\nit is evidence about what claimed to act, not proof of it.","type":"string"}},"type":"object"},"compliance.accList":{"properties":{"data":{"description":"Data is the org's tracked accreditation records, newest first.","items":{"$ref":"#/components/schemas/compliance.accView"},"type":"array"},"disclaimer":{"description":"Disclaimer states that statuses are tracked or provider-reported, never a\nplatform assertion of legal or regulatory compliance.","type":"string"}},"type":"object"},"compliance.accView":{"properties":{"basis":{"description":"Basis is the qualification category: income, net_worth, professional_license,\nor entity.","type":"string"},"createdAt":{"description":"CreatedAt is the unix second the record was created.","format":"int64","type":"integer"},"evidenceDocId":{"description":"EvidenceDocID references an evidence document in the org's sealed data room.","type":"string"},"expiresAt":{"description":"ExpiresAt is the unix second a confirmation ages out; 0 means none.","format":"int64","type":"integer"},"id":{"description":"ID is the accreditation record's opaque id.","type":"string"},"method":{"description":"Method is how the state was established: self_attested, third_party_letter,\nor provider_verified.","type":"string"},"note":{"description":"Note is a non-PII operator note.","type":"string"},"reviewerSub":{"description":"ReviewerSub is the org user who recorded a decision on this record.","type":"string"},"status":{"description":"Status is the tracked state: asserted, provider_verified, reviewer_confirmed,\nrejected, or expired.","type":"string"},"subjectId":{"description":"SubjectID is the opaque id of the subject the record is about.","type":"string"},"updatedAt":{"description":"UpdatedAt is the unix second the record last changed.","format":"int64","type":"integer"}},"type":"object"},"compliance.accreditationDecision":{"properties":{"id":{"description":"ID is the accreditation record to decide, from the path.","type":"string"},"status":{"description":"Status is the decision being recorded: reviewer_confirmed, provider_verified,\nrejected, or expired.","type":"string"}},"type":"object"},"compliance.accreditationReq":{"properties":{"basis":{"description":"Basis is the qualification category: income, net_worth, professional_license,\nor entity.","type":"string"},"evidenceDocId":{"description":"EvidenceDocID references an evidence document in the org's sealed data room.","type":"string"},"expiresAt":{"description":"ExpiresAt is the unix second a confirmation ages out; 0 means none.","format":"int64","type":"integer"},"method":{"description":"Method is how the state was established: self_attested, third_party_letter,\nor provider_verified.","type":"string"},"note":{"description":"Note is a non-PII operator note.","type":"string"},"status":{"description":"Status may only be \"asserted\" (empty reads as asserted); every confirmed,\nrejected or expired state is recorded via the decision endpoint.","type":"string"},"subjectId":{"description":"SubjectID names the subject this record is about; it must exist within the org.","type":"string"}},"type":"object"},"compliance.auditList":{"properties":{"data":{"description":"Data is the org's compliance.* audit rows, newest first.","items":{"$ref":"#/components/schemas/compliance.Wire"},"type":"array"},"disclaimer":{"description":"Disclaimer states that statuses are provider-reported or tracked, never a\nplatform assertion of legal or regulatory compliance.","type":"string"}},"type":"object"},"compliance.checkList":{"properties":{"data":{"description":"Data is the org's verifications, newest first, without subject PII.","items":{"$ref":"#/components/schemas/compliance.checkView"},"type":"array"},"disclaimer":{"description":"Disclaimer states that statuses are provider-reported, never a platform\nassertion of legal or regulatory compliance.","type":"string"}},"type":"object"},"compliance.checkView":{"properties":{"createdAt":{"description":"CreatedAt is the unix second the verification was started.","format":"int64","type":"integer"},"decidedAt":{"description":"DecidedAt is the unix second a terminal status was recorded.","format":"int64","type":"integer"},"decidedBy":{"description":"DecidedBy records who settled a terminal status: the provider name, or a\nreviewer's user id for a recorded manual decision.","type":"string"},"id":{"description":"ID is the verification's opaque id.","type":"string"},"kind":{"description":"Kind is the party type: \"individual\" (KYC) or \"business\" (KYB).","type":"string"},"provider":{"description":"Provider is the verification provider this check runs through.","type":"string"},"status":{"description":"Status is the check's state: pending, provider_verified, provider_rejected,\nmanual_review, or expired (provider-reported), or reviewer_confirmed — the\none value a privileged human reviewer records, never a provider.","type":"string"},"subjectId":{"description":"SubjectID is the opaque id of the subject under verification.","type":"string"},"updatedAt":{"description":"UpdatedAt is the unix second the verification last changed.","format":"int64","type":"integer"},"verifyUrl":{"description":"VerifyURL is the provider's hosted verification flow for the subject, when one exists.","type":"string"}},"type":"object"},"compliance.healthView":{"properties":{"provider":{"description":"Provider is the wired verification provider's name (\"manual\" by default).","type":"string"},"status":{"description":"Status is \"ok\" when the subsystem is live.","type":"string"}},"type":"object"},"compliance.recordList":{"properties":{"accreditation":{"description":"Accreditation is the org's tracked accreditation-state records.","items":{"$ref":"#/components/schemas/compliance.accView"},"type":"array"},"disclaimer":{"description":"Disclaimer states that statuses are provider-reported or tracked, never a\nplatform assertion of legal or regulatory compliance.","type":"string"},"verifications":{"description":"Verifications is the org's KYC/KYB checks, provider-reported statuses only.","items":{"$ref":"#/components/schemas/compliance.checkView"},"type":"array"}},"type":"object"},"compliance.statusView":{"properties":{"disclaimer":{"description":"Disclaimer states that statuses are provider-reported, never a platform\nassertion of legal or regulatory compliance.","type":"string"},"provider":{"description":"Provider is the wired verification provider's name.","type":"string"},"verifications":{"$ref":"#/components/schemas/compliance.verificationTally","description":"Verifications tallies the org's verifications by provider-reported status."}},"type":"object"},"compliance.subjectList":{"properties":{"data":{"description":"Data is the org's subjects, newest first, without contact PII.","items":{"$ref":"#/components/schemas/compliance.subjectSummary"},"type":"array"}},"type":"object"},"compliance.subjectReq":{"properties":{"email":{"description":"Email is the subject's contact email, sealed at rest.","type":"string"},"kind":{"description":"Kind is the party type: \"individual\" (KYC) or \"business\" (KYB).","type":"string"},"name":{"description":"Name is the subject's name, sealed at rest.","type":"string"},"ref":{"description":"Ref is the org's own opaque external id for this subject.","type":"string"}},"type":"object"},"compliance.subjectSummary":{"properties":{"createdAt":{"description":"CreatedAt is the unix second the subject was recorded.","format":"int64","type":"integer"},"hasEmail":{"description":"HasEmail reports whether a contact email is on file, without exposing it.","type":"boolean"},"id":{"description":"ID is the subject's opaque id.","type":"string"},"kind":{"description":"Kind is the party type: \"individual\" (KYC) or \"business\" (KYB).","type":"string"},"ref":{"description":"Ref is the org's own opaque external id for this subject.","type":"string"}},"type":"object"},"compliance.verificationDecision":{"properties":{"id":{"description":"ID is the verification to decide, from the path.","type":"string"},"status":{"description":"Status is the reviewer's decision: \"reviewer_confirmed\" (a pass) or\n\"manual_review\" (withheld for review) — never a provider status.","type":"string"}},"type":"object"},"compliance.verificationReq":{"properties":{"email":{"description":"Email is an inline subject's contact email, sealed at rest.","type":"string"},"kind":{"description":"Kind is an inline subject's party type: \"individual\" (KYC) or \"business\" (KYB).","type":"string"},"name":{"description":"Name is an inline subject's name, sealed at rest.","type":"string"},"ref":{"description":"Ref is the org's own opaque external id for an inline subject.","type":"string"},"subjectId":{"description":"SubjectID names an existing subject to verify; empty creates one inline.","type":"string"}},"type":"object"},"compliance.verificationTally":{"properties":{"byStatus":{"additionalProperties":{"format":"int64","type":"integer"},"description":"ByStatus tallies the org's verifications by provider-reported status.","type":"object"},"total":{"description":"Total is the sum over every status.","format":"int64","type":"integer"}},"type":"object"},"compute.agentBinding":{"properties":{"agentName":{"description":"AgentName is the cloud Agent (/v1/agent) this machine runs — the agent a\nmessage to the bot is actually run against. It is the one field that decides\nwhat the bot DOES.","type":"string"},"botVersion":{"description":"BotVersion pins the @hanzo/bot runtime version the machine runs. Empty means\nthe machine took the default in force when it was bound.","type":"string"},"createdTime":{"description":"CreatedTime is when the binding was first made.","type":"string"},"machineId":{"description":"MachineId is the bound machine as vm addresses it, owner-qualified\n(\"\u003corg\u003e/\u003cmachine\u003e\"). The unqualified half is what this surface's :id routes\ntake.","type":"string"},"message":{"description":"Message is vm's human-readable detail on Status (\"machine provisioning;\n@hanzo/bot runtime not yet confirmed\") — the reason behind the state, not a\nsecond state.","type":"string"},"name":{"description":"Name is the binding's own key, which is the machine's id: a machine hosts at\nmost one agent, so the binding is named for it. This is the key a bots list\njoins bindings onto machines by.","type":"string"},"org":{"description":"Org is the Hanzo tenant the binding belongs to.","type":"string"},"owner":{"description":"Owner is the tenant vm filed the binding under, resolved from the ?owner it\nwas called with — which is the caller's validated org and never a body field.","type":"string"},"provider":{"description":"Provider is the cloud the bound machine runs on, carried here so a bindings\nlist says where each bot lives without a second read per machine.","type":"string"},"publicIp":{"description":"PublicIp is the bound machine's public address as vm recorded it on the\nbinding. Empty while the machine has none yet.","type":"string"},"status":{"description":"Status is the binding's lifecycle in VM's OWN words — \"Pending\" while the\nmachine provisions and the runtime is unconfirmed, \"running\" once vm has\nconfirmed it. The vocabulary is vm's and passes through unmapped, which is\nwhy its capitalization does not match the machine states beside it, and it is\nvm's reconciled reading rather than anything asserted here.","type":"string"},"updatedTime":{"description":"UpdatedTime is when vm last reconciled it — the age of Status.","type":"string"}},"type":"object"},"compute.bindAgentReq":{"properties":{"agentName":{"description":"AgentName is the cloud Agent (/v1/agent) the machine will run. Required.","type":"string"},"botVersion":{"description":"BotVersion pins the @hanzo/bot runtime version; empty takes the default.","type":"string"},"id":{"description":"ID is the machine to bind, from the URL path.","type":"string"}},"type":"object"},"compute.bindingList":{"properties":{"agentBindings":{"description":"AgentBindings is one row per bound machine, emitted verbatim as vm reports\nit.","items":{"$ref":"#/components/schemas/compute.agentBinding"},"type":"array"}},"type":"object"},"compute.byoGPU":{"properties":{"arch":{"description":"Arch is the card's native compile target (\"gfx1151\"), which is what a kernel\nhas to be built for. AMD reports one; NVIDIA cards leave it empty.","type":"string"},"memoryTotal":{"description":"MemoryTotal is the card's VRAM in the units the host reported it in\n(\"122880 MiB\") — a display string, not a byte count. On a unified part it is\nthe shared CPU/GPU pool, so it is not memory reserved for the GPU.","type":"string"},"name":{"description":"Name is the card's model exactly as its own tooling named it (\"NVIDIA\nGB10\"), never normalized — an operator matches what they see here against\nwhat nvidia-smi tells them on the box.","type":"string"},"unified":{"description":"Unified reports that CPU and GPU share one memory pool (an APU or SoC), so\nMemoryTotal is not private to the GPU and the host competes for it.","type":"boolean"}},"type":"object"},"compute.byoWorker":{"properties":{"arch":{"description":"Arch/CPUs/Memory are the connecting host's static CPU spec, mirrored from the\nregistration: Arch is runtime.GOARCH (amd64 | arm64), Memory is total RAM in\nBYTES — the same fields a code-linked run-target carries, so the /v1/compute/fleet\nboard renders a linked node's arch + cores + RAM like any other unit.","type":"string"},"capabilities":{"description":"Capabilities is what this worker offers the org: \"studio.render\" when the\nnode can render, \"engine.serve\" when it serves a model endpoint. A node\nadvertises one only once it can honour it, so an absent list means a node\nthat has dialed in but is not ready to serve any of them yet.","items":{"type":"string"},"type":"array"},"cpuModel":{"description":"CPUModel is the processor as the host names it (\"Apple M3 Max\"), for display.","type":"string"},"cpus":{"description":"CPUs is the host's logical core count.","format":"int64","type":"integer"},"cuda":{"description":"Cuda is the host's CUDA toolkit version. NVIDIA hosts report it.","type":"string"},"driver":{"description":"Driver is the host's NVIDIA kernel driver version — distinct from Cuda, and\nthe one that bounds which CUDA versions can run on this box.","type":"string"},"engine":{"$ref":"#/components/schemas/compute.engineAdvertisement","description":"Engine is the hanzo-engine model server this node runs, when it runs one\n(`hanzo link --serve-engine`). Absent means the node takes jobs but serves\nno model endpoint."},"firstSeen":{"description":"FirstSeen is when this node first dialed in, RFC 3339 — the start of its\npresence record, which `hanzo unlink` ends.","type":"string"},"gpus":{"description":"GPUs are the accelerators the host found on itself. Empty is a real answer:\na CPU-only machine can dial in and take non-GPU work.","items":{"$ref":"#/components/schemas/compute.byoGPU"},"type":"array"},"hip":{"description":"Hip is the host's HIP runtime version, the AMD counterpart to Cuda.","type":"string"},"hostname":{"description":"Hostname is what the host calls itself. It equals ID for any hostname already\nin the [a-z0-9-] alphabet, and differs when sanitizing had to change it.","type":"string"},"id":{"description":"ID is the node's id in the fleet — the sanitized hostname it registered\nunder, which is also the `unit` its samples and its gpu-jobs lane key on.\nThis is the id to use everywhere else on the compute surface.","type":"string"},"jobQueue":{"description":"JobQueue is the tasks NAMESPACE this worker claims render jobs out of —\n\"gpu-jobs\" unless `hanzo link` was pointed at another. Within it, a job aimed\nat this node alone rides the task-queue value \"gpu:\u003cid\u003e\".","type":"string"},"lanes":{"description":"Lanes are the Studio render lanes the node's engine can run now (image.zen,\nedit.qwen, video.wan, mesh, ...): advertised only when every weight file a\nlane loads is on the node, so a page offers a GPU card only where it renders.","items":{"type":"string"},"type":"array"},"lastHeartbeat":{"description":"LastHeartbeat is the most recent beat this node sent, RFC 3339. It is what\nStatus is computed from, so a reader can check the judgement.","type":"string"},"location":{"description":"Location is always \"on-prem\" — a machine that dialed in has no cloud region,\nand inventing one would put it somewhere it is not.","type":"string"},"memory":{"description":"Memory is the host's total RAM in BYTES.","format":"int64","type":"integer"},"models":{"description":"Models are the weights behind those lanes, each with its SPDX licence.","items":{"$ref":"#/components/schemas/compute.laneModel"},"type":"array"},"os":{"description":"Os is the host's operating system: linux, darwin or windows.","type":"string"},"provider":{"description":"Provider is always \"byo\": this machine is the operator's, not one Hanzo\nprovisioned. It exists so a fold into the machines/GPUs pages says which\nrows are rented and which are the customer's own.","type":"string"},"rocm":{"description":"Rocm is the host's ROCm version. AMD hosts report it; empty otherwise.","type":"string"},"status":{"description":"Status is \"online\" when the last heartbeat landed within 90s, else\n\"offline\" — so it is a fact about heartbeat freshness, not about the box\nbeing powered on. A worker that has never beaten reads offline.","type":"string"},"version":{"description":"Version is the `hanzo` CLI version running on the node. It is what to check\nwhen a worker is missing a field a newer registration reports.","type":"string"}},"type":"object"},"compute.clusterAttach":{"properties":{"default":{"description":"Default marks this the org's default cluster for scheduling.","type":"boolean"},"kubeconfig":{"description":"Kubeconfig is the cluster's kubeconfig, verbatim. Required — a body without\none is not an attach.","type":"string"},"name":{"description":"Name is the fleet-local name for the cluster; lower-cased, and the key the\ndetach route addresses it by. Required.","type":"string"},"provider":{"description":"Provider is a free-form label for where the cluster runs (\"gke\", \"on-prem\");\nit is display only, not a routing key.","type":"string"}},"type":"object"},"compute.clusterDetached":{"properties":{"detached":{"description":"Detached is the lower-cased fleet name that was removed.","type":"string"}},"type":"object"},"compute.clusterDetailView":{"properties":{"amdGpu":{"description":"AmdGPU is the same count for `amd.com/gpu`: AMD accelerators across the BYO\ncluster's nodes, as of the attach.","format":"int64","type":"integer"},"createdAt":{"description":"CreatedAt is when the cluster started existing: the earliest creation time\namong its pools for a managed cluster, and for a BYO one the RFC 3339 moment\nit was attached. Empty when the source states none.","type":"string"},"doClusterId":{"description":"DoClusterID carries the SAME id as DoksClusterID. Both names exist because\nthe console's Cluster type reads either one; neither is a second identifier.","type":"string"},"doksClusterId":{"description":"DoksClusterID is the provider's own id for the cluster, and the value the\n/v1/compute/k8s/clusters/:id routes take. Empty for a BYO cluster: an attached\nkubeconfig was never provisioned, so there is no provider id to state.","type":"string"},"kind":{"description":"Kind says which of the two kinds of cluster this row is, and there are only\ntwo: \"managed\" — Visor provisioned it and Hanzo's account pays the provider —\nor \"byo\", an existing cluster the org attached by kubeconfig.","type":"string"},"name":{"description":"Name is the cluster's name: the provider's for a managed cluster, and for a\nBYO one the lower-cased fleet name it was attached under — which is also how\nthe detach route addresses it.","type":"string"},"nodeCount":{"description":"NodeCount is how many worker nodes the cluster has — the sum over its pools\nfor a managed cluster, and for a BYO one the node count read off the cluster\nwhen it was attached.","format":"int64","type":"integer"},"nodePools":{"description":"NodePools is the authoritative node inventory — every pool, each with its own\nsize and count. It is empty in two cases that are not \"no pools\": a row from\nthe /v1/compute/k8s/clusters LIST, which is deliberately lightweight and whose\n:id detail carries them, and a BYO cluster, whose pools were never read.","items":{"$ref":"#/components/schemas/compute.nodePoolView"},"type":"array"},"nodeSize":{"description":"NodeSize is a display convenience: the size slug of the FIRST pool. A cluster\nmixing sizes has more than one, and NodePools is where they all are.","type":"string"},"nodes":{"description":"Nodes is every worker node in the cluster, each in the same shape the\nmachines surface uses — a node IS a machine, addressable by its own id. This\nis the individual hardware behind the pool counts above.","items":{"$ref":"#/components/schemas/compute.machineView"},"type":"array"},"nvidiaGpu":{"description":"NvidiaGPU is how many NVIDIA accelerators the cluster's nodes advertise, the\nsum of `nvidia.com/gpu` allocatable across them. BYO only, and counted ONCE\nwhen the cluster was attached — it is an inventory, not live capacity.","format":"int64","type":"integer"},"region":{"description":"Region is the provider region slug for a managed cluster. A BYO cluster has\nno region we can read, so it carries the free-form `provider` label the\nattach named it with (\"gke\", \"on-prem\") instead.","type":"string"},"status":{"description":"Status is the cluster's state: the provider's own word for a managed cluster\n(\"running\", \"provisioning\"), \"unknown\" when the provider stated none, and\nalways \"attached\" for a BYO cluster — that one says the kubeconfig is on\nfile, not that the cluster is reachable this second.","type":"string"}},"type":"object"},"compute.clusterList":{"properties":{"clusters":{"description":"Clusters is the merged fleet — kind \"managed\" for Visor-provisioned, \"byo\"\nfor an attached kubeconfig.","items":{"$ref":"#/components/schemas/compute.clusterView"},"type":"array"},"degraded":{"description":"Degraded names any source that did not answer, so an empty Clusters means\n\"you have none\" only when this is absent. Omitted when everything answered,\nso a healthy response is unchanged. See degraded.go.","items":{"$ref":"#/components/schemas/compute.sourceFailure"},"type":"array"}},"type":"object"},"compute.clusterView":{"properties":{"amdGpu":{"description":"AmdGPU is the same count for `amd.com/gpu`: AMD accelerators across the BYO\ncluster's nodes, as of the attach.","format":"int64","type":"integer"},"createdAt":{"description":"CreatedAt is when the cluster started existing: the earliest creation time\namong its pools for a managed cluster, and for a BYO one the RFC 3339 moment\nit was attached. Empty when the source states none.","type":"string"},"doClusterId":{"description":"DoClusterID carries the SAME id as DoksClusterID. Both names exist because\nthe console's Cluster type reads either one; neither is a second identifier.","type":"string"},"doksClusterId":{"description":"DoksClusterID is the provider's own id for the cluster, and the value the\n/v1/compute/k8s/clusters/:id routes take. Empty for a BYO cluster: an attached\nkubeconfig was never provisioned, so there is no provider id to state.","type":"string"},"kind":{"description":"Kind says which of the two kinds of cluster this row is, and there are only\ntwo: \"managed\" — Visor provisioned it and Hanzo's account pays the provider —\nor \"byo\", an existing cluster the org attached by kubeconfig.","type":"string"},"name":{"description":"Name is the cluster's name: the provider's for a managed cluster, and for a\nBYO one the lower-cased fleet name it was attached under — which is also how\nthe detach route addresses it.","type":"string"},"nodeCount":{"description":"NodeCount is how many worker nodes the cluster has — the sum over its pools\nfor a managed cluster, and for a BYO one the node count read off the cluster\nwhen it was attached.","format":"int64","type":"integer"},"nodePools":{"description":"NodePools is the authoritative node inventory — every pool, each with its own\nsize and count. It is empty in two cases that are not \"no pools\": a row from\nthe /v1/compute/k8s/clusters LIST, which is deliberately lightweight and whose\n:id detail carries them, and a BYO cluster, whose pools were never read.","items":{"$ref":"#/components/schemas/compute.nodePoolView"},"type":"array"},"nodeSize":{"description":"NodeSize is a display convenience: the size slug of the FIRST pool. A cluster\nmixing sizes has more than one, and NodePools is where they all are.","type":"string"},"nvidiaGpu":{"description":"NvidiaGPU is how many NVIDIA accelerators the cluster's nodes advertise, the\nsum of `nvidia.com/gpu` allocatable across them. BYO only, and counted ONCE\nwhen the cluster was attached — it is an inventory, not live capacity.","format":"int64","type":"integer"},"region":{"description":"Region is the provider region slug for a managed cluster. A BYO cluster has\nno region we can read, so it carries the free-form `provider` label the\nattach named it with (\"gke\", \"on-prem\") instead.","type":"string"},"status":{"description":"Status is the cluster's state: the provider's own word for a managed cluster\n(\"running\", \"provisioning\"), \"unknown\" when the provider stated none, and\nalways \"attached\" for a BYO cluster — that one says the kubeconfig is on\nfile, not that the cluster is reachable this second.","type":"string"}},"type":"object"},"compute.createClusterReq":{"properties":{"name":{"description":"Name is the cluster's name. Required.","type":"string"},"nodePool":{"description":"NodePool is the ONE pool the cluster is born with — a cluster with no nodes\nruns nothing, so it is not optional. More pools are added afterwards through\nPOST /v1/compute/clusters/:clusterId/pools.","properties":{"count":{"format":"int64","type":"integer"},"name":{"type":"string"},"size":{"type":"string"}},"type":"object"},"region":{"description":"Region is the provider region slug (e.g. \"nyc3\"). Required.","type":"string"},"version":{"description":"Version is the Kubernetes version slug; empty takes the provider default.","type":"string"}},"type":"object"},"compute.engineAdvertisement":{"properties":{"apis":{"description":"APIs are the wire formats the engine serves on that one port: \"openai\",\n\"anthropic\", or both.","items":{"type":"string"},"type":"array"},"models":{"description":"Models are the model ids the node's own GET /v1/models answered with — what\nthis GPU can actually be asked for.","items":{"type":"string"},"type":"array"},"status":{"description":"Status is \"ready\" when the node's engine answered, \"unreachable\" when it did\nnot. Advertised is not the same as serving, and this is the difference.","type":"string"},"url":{"description":"URL is the base address the node advertised its engine on — where a model\ncall to this GPU is sent. The node chose it, so reaching it is a question\nabout the node's network, not about this surface.","type":"string"}},"type":"object"},"compute.fleetBoard":{"properties":{"units":{"description":"Units is the union across sources — agent run-targets, BYO workers, BYO\nclusters and Visor machines — each row naming the source it came from.","items":{"$ref":"#/components/schemas/compute.fleetUnit"},"type":"array"}},"type":"object"},"compute.fleetMetrics":{"properties":{"at":{"description":"At is when this reading was MEASURED, RFC 3339 in UTC — not when the board\nwas built. A console decides staleness by comparing it to now; the board\ndeliberately does not decide that for it.","type":"string"},"gpuUtil":{"description":"GPUUtil is aggregate accelerator utilization as a FRACTION of 1 — 0.42 is\n42% busy, never 42. Across all of the unit's cards, not one of them.","format":"double","type":"number"},"load1":{"description":"Load1 is the host's 1-minute load average — runnable processes, not a\npercentage, so it is read against the unit's core count and can exceed 1.","format":"double","type":"number"},"memFree":{"description":"MemFree is host memory still available, in BYTES. It is what the source\nreported, not fleetSpec.Memory minus MemUsed.","format":"int64","type":"integer"},"memUsed":{"description":"MemUsed is host memory in use, in BYTES.","format":"int64","type":"integer"}},"type":"object"},"compute.fleetSpec":{"properties":{"arch":{"description":"Arch is the CPU architecture, amd64 or arm64, and it is what decides whether\na binary built for the fleet will run here. Only the sources that report one\ncarry it (a linked run-target, a BYO worker).","type":"string"},"cpus":{"description":"CPUs is logical cores on the unit.","format":"int64","type":"integer"},"gpuModel":{"description":"GPUModel names the FIRST accelerator (\"NVIDIA GB10\") as the representative of\nthe set; GPUs carries how many. Empty for a cluster, whose cards are counted\nrather than modelled, and for a unit with none.","type":"string"},"gpus":{"description":"GPUs is how many accelerators the unit has. For a cluster it is the vendor\ntotals summed across every node, so it counts cards, not machines.","format":"int64","type":"integer"},"memory":{"description":"Memory is total system RAM in BYTES — not GB, and not what is free right now\n(fleetMetrics carries that). Absent when the source reports no RAM figure.","format":"int64","type":"integer"},"os":{"description":"OS is the operating system the unit runs: linux, darwin or windows. Empty\nwhen the source does not report one — a cluster row does not.","type":"string"}},"type":"object"},"compute.fleetUnit":{"properties":{"host":{"description":"Host is the unit's hostname. Empty for a unit that is not one host: a cluster\nrow has no hostname to report.","type":"string"},"kind":{"description":"Kind is what the unit IS: laptop, cloud, gpu, cluster, machine or worker.","type":"string"},"label":{"description":"Label is the name to show a human — a target's label, a worker's hostname, a\nmachine's display name. Empty when the source has none to give.","type":"string"},"metrics":{"$ref":"#/components/schemas/compute.fleetMetrics","description":"Metrics is the unit's latest utilization: its own live snapshot when it keeps\none (a run-target's heartbeat wins), else the newest sample from the series\nfor the SAME source. Absent means nothing is known about this unit's load —\nwhich is deliberately not the same as a reading of zero."},"queued":{"description":"Queued is how many renders are waiting on THIS GPU's own lane in the org's\ngpu-jobs queue. BYO units only — an agent run-target dispatches, it does not\nqueue — and omitted when nothing is waiting.","format":"int64","type":"integer"},"running":{"description":"Running is what the unit is executing right now: agent sessions in flight for\na run-target, claimed renders for a BYO GPU.","format":"int64","type":"integer"},"sessions":{"description":"Sessions is how many agent sessions are open on this unit. Always present,\nand 0 for a source that cannot host agent sessions at all — a fact about that\nplane, not a gap in the reading.","format":"int64","type":"integer"},"source":{"description":"Source is the plane this row came from: \"agent\" (a linked run-target), \"byo\"\n(a worker or cluster the org dialed in) or \"visor\" (a machine Hanzo\nprovisioned). It is half the row's identity, and it says which face owns the\nunit — /v1/agent/targets, /v1/compute/fleet/workers, /v1/compute/machines.","type":"string"},"spec":{"$ref":"#/components/schemas/compute.fleetSpec","description":"Spec is the unit's static capability. Absent when the source reported none —\nunknown capability, never a zeroed one."},"status":{"description":"Status is liveness in the SOURCE's own vocabulary, because each plane decides\nit differently: a run-target's is derived from its heartbeat, a BYO worker's\nis online/offline on the 90s window, a BYO cluster's is \"attached\", and a\nVisor machine's is the provider's word for its lifecycle state.","type":"string"},"unit":{"description":"Unit is the SOURCE's own id for this unit — a run-target id, a BYO worker id,\na Visor machine name — so a row links straight back to the face that owns it.\nIt is unique within a source, not across them: two planes may mint the same\nid, which is why (source, unit) together is the identity.","type":"string"}},"type":"object"},"compute.gpuAlertList":{"properties":{"alerts":{"description":"Alerts is always empty, and typed as a raw list because Visor exposes no\nalert inventory for this surface to shape: there is nothing to describe\nuntil there is something to return.","items":{},"type":"array"}},"type":"object"},"compute.gpuJob":{"properties":{"attempt":{"description":"Attempt is which try this is, counting from 1. Above 1 means the job was\nretried after a failed or abandoned run.","format":"int64","type":"integer"},"closeTime":{"description":"CloseTime is when the job reached a terminal state, RFC 3339. Empty means it\nis still live — queued, running or stalled.","type":"string"},"failureCause":{"description":"FailureCause is the engine's reason the job failed. Empty unless it did.","type":"string"},"gpu":{"description":"GPU is the node this job is aimed AT — the lane \"gpu:\u003cnode\u003e\" it was submitted\non. Empty means the shared any-GPU lane: it was not aimed anywhere and the\nfirst free worker takes it.","type":"string"},"id":{"description":"ID is the job's id, and the id the cancel route takes. The dispatcher sets it\nequal to the render's prompt id, so it is the same value the studio knows the\njob by.","type":"string"},"label":{"description":"Label is the cheap human name for the render — the output filename prefix\nlifted out of the submitted graph. Empty when the graph carried none. The\ngraph itself is never in this list; the tasks describe endpoint serves it.","type":"string"},"lastHeartbeat":{"description":"LastHeartbeat is the claiming worker's most recent beat on this job, RFC 3339\n— the evidence a long render is still alive rather than wedged.","type":"string"},"leaseExpiry":{"description":"LeaseExpiry is when the worker's claim lapses, RFC 3339. Past it with the job\nstill STARTED, the claimant is presumed dead and Status reads \"stalled\".","type":"string"},"runId":{"description":"RunID identifies this execution of the job. It equals ID for a job the\ndispatcher submitted, which is why a cancel that omits it still works.","type":"string"},"startTime":{"description":"StartTime is when a worker began executing the job, RFC 3339. Empty while it\nis still queued.","type":"string"},"status":{"description":"Status is the job's lifecycle state: queued, running, completed, failed or\ncanceled — plus \"stalled\", which is this surface's own reading of a job that\nis STARTED whose worker died: its lease has elapsed and no reaper has taken\nit back yet. Without it such a job reads \"running\" forever. An engine state\nthis surface does not recognize passes through lower-cased rather than being\ncoerced into one of these.","type":"string"},"type":{"description":"Type is the work being done (\"studio.render\") — what the claiming worker has\nto be able to execute.","type":"string"},"worker":{"description":"Worker is the node that actually CLAIMED the job, which is not always the one\nit was aimed at: a shared-lane job has no GPU but does have a Worker once\npicked up. Empty while the job is still waiting.","type":"string"}},"type":"object"},"compute.gpuList":{"properties":{"gpus":{"description":"GPUs is every accelerator the org has, from Visor GPU droplets and from BYO\nworkers alike.","items":{"$ref":"#/components/schemas/compute.gpuView"},"type":"array"}},"type":"object"},"compute.gpuView":{"properties":{"id":{"description":"ID is the card's address: its host machine's id, \"#\", and the card's ordinal\nwithin that machine (\"gpu-1#0\"). Stable for as long as the machine is, and\nthe only id a single accelerator has — providers do not name cards.","type":"string"},"location":{"description":"Location is where the card physically sits, which for every source today is\nthe same value Region carries — the console renders it in its own column.","type":"string"},"machine":{"description":"Machine is the id of the machine holding this card, addressable as-is on\n/v1/compute/machines/:id.","type":"string"},"memory":{"description":"Memory is the card's VRAM as its own tooling reported it (\"122880 MiB\") — a\ndisplay string in the reporter's units, not a byte count. BYO cards carry it\n(nvidia-smi); Visor's machine object states no VRAM, so a rented card leaves\nit empty and the console renders \"—\" rather than a fabricated 0.","type":"string"},"model":{"description":"Model is the accelerator: the model token read out of the size slug for a\nVisor GPU droplet (\"H100\", \"MI300X\"), or the name nvidia-smi reported for a\nBYO card (\"NVIDIA GB10\").","type":"string"},"name":{"description":"Name is the HOST MACHINE's display name, not the card's — every card in a\ngpu-h100x8 node repeats it. Model is what says which accelerator this is.","type":"string"},"provider":{"description":"Provider distinguishes a BYO accelerator (\"byo\") from a Visor-provisioned one\n(the host machine's real provider). It is what tells a card the org owns from\na card the org rents.","type":"string"},"region":{"description":"Region is the host machine's provider region slug; \"on-prem\" for a BYO card.","type":"string"},"status":{"description":"Status is the HOST MACHINE's lifecycle state, because nothing upstream\nreports a card's own health. A card reads running because its machine does.","type":"string"}},"type":"object"},"compute.jobCancel":{"properties":{"id":{"description":"ID is the job (activity) id, from the URL path.","type":"string"},"reason":{"description":"Reason is recorded on the cancellation; empty records \"canceled from console\".","type":"string"},"run":{"description":"Run is the run id; empty defaults to the job id, which is what the dispatcher\nsets (runId == activityId == prompt_id), so the common case sends no body.","type":"string"}},"type":"object"},"compute.jobCanceled":{"properties":{"canceled":{"description":"Canceled is the job id that was canceled.","type":"string"},"run":{"description":"Run is the run id the cancel was applied to.","type":"string"}},"type":"object"},"compute.jobList":{"properties":{"jobs":{"description":"Jobs is the queue, most-recent-first. Every LIVE job is present; terminal\nhistory is capped, so a busy org's running work is never crowded out.","items":{"$ref":"#/components/schemas/compute.gpuJob"},"type":"array"}},"type":"object"},"compute.laneModel":{"properties":{"id":{"description":"ID is the weight set's id, as the node's engine loads it (triposr, wan2.2, ...).","type":"string"},"lane":{"description":"Lane is the Studio render lane these weights serve first (mesh, video.wan, ...).","type":"string"},"licence":{"description":"Licence is the weights' SPDX licence identifier (MIT, Apache-2.0, ...).","type":"string"}},"type":"object"},"compute.machineList":{"properties":{"machines":{"description":"Machines is every machine the org has: Visor-provisioned and BYO together.","items":{"$ref":"#/components/schemas/compute.machineView"},"type":"array"}},"type":"object"},"compute.machineView":{"properties":{"agent":{"description":"Agent is the cloud Agent this machine runs, lifted out of the binding so a\nlist reads without following one. Empty means nothing is bound — for a\nkind=bot machine that means it costs money and answers nothing.","type":"string"},"binding":{"$ref":"#/components/schemas/compute.agentBinding","description":"Binding is the record joining this machine to that agent, carrying vm's own\nreconciled status and its reason. Absent means no runtime is bound, which is\nalso what a stopped bot looks like: stopping unbinds and leaves the machine\nrunning."},"createdTime":{"description":"CreatedTime is when the machine came into being: the provider's own creation\ntimestamp for a Visor machine, passed through in whatever form it states it,\nand for a BYO machine the RFC 3339 moment it first dialed in.","type":"string"},"gpu":{"description":"GPU names the accelerators this machine holds (\"H100\", or \"2× NVIDIA GB10\"\nfor a BYO machine reporting a matched pair). Empty means the machine is not\na GPU machine — the size slug does not parse as one, or nvidia-smi found\nnothing.","type":"string"},"id":{"description":"ID addresses this machine on the /v1/compute/machines/:id routes: the\norg-scoped NAME Visor keys a machine by, falling back to the provider id for\na machine that has no name. A BYO machine's is the id it dialed in under.","type":"string"},"image":{"description":"Image is the OS image the machine booted from, as the provider names it.","type":"string"},"mem":{"description":"Mem is system RAM rendered for a human (\"8 GB\"), not a number to compute\nwith. Empty when the provider's figure is ambiguous, or when the only figure\navailable is a GPU slug's gb — that is VRAM, and reporting it as system RAM\nwould be a fabrication. A BYO machine's RAM is on /v1/compute/fleet/workers.","type":"string"},"name":{"description":"Name is the label to show a human — Visor's displayName, or the machine name\nwhen it carries none. A BYO machine's is its hostname. It is not an address:\nID is what the routes take.","type":"string"},"os":{"description":"Os is the operating system on the machine — Visor's record for a provisioned\none, the host's own report (linux, darwin, windows) for a BYO one.","type":"string"},"privateIp":{"description":"PrivateIp is the address on the provider's own network, reachable from the\norg's other machines in the same region. Empty on the same terms as PublicIp.","type":"string"},"provider":{"description":"Provider is the cloud that runs the machine (\"digitalocean\"), or \"byo\" for\none the operator dialed in with `hanzo link`.","type":"string"},"publicIp":{"description":"PublicIp is the internet-facing address the provider assigned. Empty while a\nmachine is still provisioning, and empty for a BYO machine — it dials out\nfrom behind NAT, so no address is ever learned for it.","type":"string"},"region":{"description":"Region is the provider region slug (\"sfo3\"), or the zone when the provider\nreports only that. \"on-prem\" for a BYO machine, which has no cloud region.","type":"string"},"status":{"description":"Status is the lifecycle state in the PROVIDER's own words (\"active\",\n\"running\", \"off\"), passed through rather than mapped onto a vocabulary of\nours. A BYO machine's is \"online\" or \"offline\", decided by whether its last\nheartbeat is within 90s.","type":"string"},"type":{"description":"Type is the provider SIZE SLUG the machine runs at (\"s-2vcpu-4gb\",\n\"gpu-h100x8-640gb\") — the value a launch asks for, and what Vcpu/Mem/GPU are\nread out of when the provider states them no other way. \"byo-gpu\" for a\ndialed-in machine, which was never bought from a size catalog.","type":"string"},"vcpu":{"description":"Vcpu is logical cores — the provider's own cpuSize when that is a clean\ninteger, else the count read out of the size slug (4 from \"s-4vcpu-8gb\").\nABSENT, never 0, when neither says. A BYO machine leaves it absent here; its\nreal core count is on GET /v1/compute/fleet/workers.","format":"int64","type":"integer"}},"type":"object"},"compute.nodeList":{"properties":{"nodes":{"description":"Nodes is one row per worker node, in the SAME machineView shape the machines\nsurface emits — a node IS a machine.","items":{"$ref":"#/components/schemas/compute.machineView"},"type":"array"}},"type":"object"},"compute.nodePoolView":{"properties":{"autoScale":{"description":"AutoScale reports whether the provider's cluster autoscaler owns this pool's\nsize, moving Count between MinNodes and MaxNodes as workloads demand. False\nmeans Count changes only when someone scales the pool.","type":"boolean"},"count":{"description":"Count is how many nodes the pool has right now. Always present, so 0 means a\npool that is genuinely empty rather than a figure the provider withheld.","format":"int64","type":"integer"},"maxNodes":{"description":"MaxNodes is the ceiling the autoscaler will not grow the pool past, and so\nthe bound on what this pool can cost. Read it only with AutoScale set.","format":"int64","type":"integer"},"minNodes":{"description":"MinNodes is the floor the autoscaler will not shrink the pool below. Read it\nonly with AutoScale set — the provider ignores it otherwise.","format":"int64","type":"integer"},"name":{"description":"Name is the pool's name as the provider knows it.","type":"string"},"poolId":{"description":"PoolID is the provider's id for the pool — the value the scale and delete\nroutes address it by. It falls back to the pool's name when the provider\nanswered without one, so it is always something the routes accept.","type":"string"},"size":{"description":"Size is the provider size slug every node in the pool runs at\n(\"s-4vcpu-8gb\", \"gpu-h100x8-640gb\"). One pool is one size — a mixed cluster\nis several pools.","type":"string"}},"type":"object"},"compute.poolCreate":{"properties":{"autoScale":{"description":"AutoScale turns the provider's cluster autoscaler on for this pool.","type":"boolean"},"clusterId":{"description":"ClusterID is the cluster to add the pool to, from the URL path.","type":"string"},"count":{"description":"Count is how many nodes the pool starts with.","format":"int64","type":"integer"},"maxNodes":{"description":"MaxNodes is the ceiling the autoscaler may not grow the pool past, and so the\nbound on what this pool can spend. Ignored unless AutoScale is set.","format":"int64","type":"integer"},"minNodes":{"description":"MinNodes is the floor the autoscaler may not shrink the pool below. Ignored\nunless AutoScale is set.","format":"int64","type":"integer"},"name":{"description":"Name is the pool's name.","type":"string"},"provider":{"description":"Provider is the cloud the cluster lives on (e.g. \"digitalocean\"). Required —\nVisor routes the create by it. Accepted from the body or ?provider=.","type":"string"},"size":{"description":"Size is the provider size slug for each node (e.g. \"s-4vcpu-8gb\").","type":"string"}},"type":"object"},"compute.poolScale":{"properties":{"clusterId":{"description":"ClusterID is the cluster holding the pool, from the URL path.","type":"string"},"count":{"description":"Count is the node count to scale TO — an absolute target, not a delta, and\nnever negative.","format":"int64","type":"integer"},"poolId":{"description":"PoolID is the pool to resize, from the URL path — the `poolId` a cluster read\nreports for it. Required.","type":"string"},"provider":{"description":"Provider is the cloud the cluster lives on. Required; body or ?provider=.","type":"string"}},"type":"object"},"compute.sampleAccepted":{"properties":{"recorded":{"description":"Recorded is always true: the response is an acknowledgement, and the\nwarehouse write is detached, so it reports acceptance, not durability.","type":"boolean"}},"type":"object"},"compute.sampleIngest":{"properties":{"gpuModel":{"description":"GPUModel names the representative accelerator (\"GB10\"); GPUs carries how\nmany. A heterogeneous host names its first card rather than inventing a\nsummary.","type":"string"},"gpuUtil":{"description":"GPUUtil is accelerator utilization as a fraction 0..1; the warehouse clamps\nanything outside that.","format":"double","type":"number"},"gpus":{"description":"GPUs is how many accelerators this reading covers.","format":"int64","type":"integer"},"host":{"description":"Host is the node's hostname, for display.","type":"string"},"memFree":{"description":"MemFree is host memory still available, in BYTES.","format":"int64","type":"integer"},"memUsed":{"description":"MemUsed is host memory in use, in BYTES.","format":"int64","type":"integer"},"unit":{"description":"Unit is the reporting node's own id — the same id it registered under, and\nthe key the board joins this series onto. Required.","type":"string"}},"type":"object"},"compute.sampleList":{"properties":{"samples":{"description":"Samples are the readings, OLDEST first — the order a chart plots.","items":{"$ref":"#/components/schemas/compute.sampleView"},"type":"array"}},"type":"object"},"compute.sampleView":{"properties":{"at":{"description":"At is when the reading was MEASURED, RFC 3339 in UTC — the x-axis a chart\nplots against. The series is returned oldest first, so it only increases.","type":"string"},"costCents":{"description":"CostCents is what this unit resold for over the hour the reading falls in, in\nwhole US cents. 0 means UNPRICED, not free: the operator's own machines — a\nlinked run-target, a dialed-in BYO worker — are metered for utilization and\nnever resold, so only a priced source ever fills it.","format":"int64","type":"integer"},"cpuTemp":{"description":"CPUTemp is the CPU package temperature in °C.","format":"double","type":"number"},"cpuUtil":{"description":"CPUUtil is the busy fraction of all cores over the sample window, 0..1.","format":"double","type":"number"},"cpus":{"description":"CPUs is logical cores. The static capability rides every row on purpose: a\nchart can size load against cores without joining a registry whose row may\nsince have been rewritten or the unit deregistered.","format":"int64","type":"integer"},"decode":{"description":"Decode is generation throughput over the sample window, in tokens per second.","format":"double","type":"number"},"diskRead":{"description":"DiskRead is the block-device read rate in bytes per second.","format":"double","type":"number"},"diskTotal":{"description":"DiskTotal is the size of those filesystems, in BYTES.","format":"int64","type":"integer"},"diskUsed":{"description":"DiskUsed is the space used across local block filesystems, in BYTES.","format":"int64","type":"integer"},"diskWrite":{"description":"DiskWrite is the block-device write rate in bytes per second.","format":"double","type":"number"},"gpuMemTotal":{"description":"GPUMemTotal is dedicated VRAM in BYTES; absent when the GPU shares system memory (unified).","format":"int64","type":"integer"},"gpuMemUsed":{"description":"GPUMemUsed is the memory held by GPU processes, in BYTES.","format":"int64","type":"integer"},"gpuModel":{"description":"GPUModel names the representative accelerator (\"GB10\"); GPUs carries how many.","type":"string"},"gpuPower":{"description":"GPUPower is the total GPU power draw in watts.","format":"double","type":"number"},"gpuPowerLimit":{"description":"GPUPowerLimit is the total enforced GPU power limit in watts; absent when the driver reports none.","format":"double","type":"number"},"gpuTemp":{"description":"GPUTemp is the hottest GPU's temperature in °C.","format":"double","type":"number"},"gpuUtil":{"description":"GPUUtil is aggregate accelerator utilization as a FRACTION of 1 — 0.42 is\n42% busy. Anything a reporter sends outside 0..1 is clamped into it on write.","format":"double","type":"number"},"gpus":{"description":"GPUs is how many accelerators the reading covers.","format":"int64","type":"integer"},"host":{"description":"Host is the hostname the unit reported at the time of the reading.","type":"string"},"kind":{"description":"Kind is what the measured unit is: laptop, cloud, gpu, cluster, machine or\nworker.","type":"string"},"kvCache":{"description":"KVCache is the KV-cache occupancy, 0..1.","format":"double","type":"number"},"load1":{"description":"Load1 is the 1-minute load average — runnable processes, not a percentage.","format":"double","type":"number"},"load15":{"description":"Load15 is the 15-minute load average, the same units as Load1.","format":"double","type":"number"},"load5":{"description":"Load5 is the 5-minute load average, the same units as Load1.","format":"double","type":"number"},"memFree":{"description":"MemFree is host memory available, in BYTES, as reported rather than derived.","format":"int64","type":"integer"},"memUsed":{"description":"MemUsed is host memory in use, in BYTES.","format":"int64","type":"integer"},"memory":{"description":"Memory is total system RAM in BYTES at the time of the reading.","format":"int64","type":"integer"},"model":{"description":"Model is the model id(s) served on the unit, comma-separated, at most 128 bytes.","type":"string"},"netRx":{"description":"NetRx is the receive rate of physical interfaces in bytes per second.","format":"double","type":"number"},"netTx":{"description":"NetTx is the transmit rate of physical interfaces in bytes per second.","format":"double","type":"number"},"prefill":{"description":"Prefill is prompt (prefill) throughput over the sample window, in tokens per second.","format":"double","type":"number"},"running":{"description":"Running is the number of requests being served at the reading.","format":"int64","type":"integer"},"source":{"description":"Source is the plane that reported the reading: \"agent\", \"byo\" or \"visor\" —\nthe same vocabulary the board's rows carry, and what ?source= narrows on.","type":"string"},"ttft":{"description":"TTFT is the mean time to first token, in seconds, of requests that started in the window.","format":"double","type":"number"},"unit":{"description":"Unit is the source's own id for the measured unit. With Source it is the key\nthe chart groups by, and the key the board joins a unit's latest reading on.","type":"string"},"waiting":{"description":"Waiting is the number of requests queued at the reading.","format":"int64","type":"integer"}},"type":"object"},"compute.sourceFailure":{"properties":{"reason":{"description":"Reason is a terse, log-safe summary — never the upstream's response body.","type":"string"},"source":{"description":"Source is the dependency that failed, named as an operator names it.","type":"string"}},"type":"object"},"compute.workerList":{"properties":{"workers":{"description":"Workers is one row per connected BYO machine, each carrying the host's own\nreport (GPUs, driver versions, capabilities) rather than a normalized view.","items":{"$ref":"#/components/schemas/compute.byoWorker"},"type":"array"}},"type":"object"},"content.Channel":{"properties":{"disabled":{"description":"Disabled is true for a channel the org switched off at the social edge. It\nis still listed — this is what the org has CONNECTED, not what it can post\nto — but a publish never targets it, neither by name nor as part of the\n\"every channel\" default.","type":"boolean"},"id":{"description":"ID is the social integration id a post targets. It is the exact value to put\nin a content item's `channels` list to reach this one connected account.","type":"string"},"name":{"description":"Name is the account label as the org connected it — the handle a human\nrecognises. It is never an address: a publish resolves channels by ID or by\nProvider and never by this.","type":"string"},"provider":{"description":"Provider is the network behind the integration: \"x\", \"instagram\", \"tiktok\"\nand the rest of what the org connected. Naming a provider in a publish\ntargets EVERY connected account of it, so it is the coarse handle where ID\nis the precise one.","type":"string"}},"type":"object"},"content.ChannelResult":{"properties":{"channel":{"description":"the social integration id targeted","type":"string"},"error":{"description":"short reason, when it failed","type":"string"},"externalId":{"description":"social post id, when it went out","type":"string"},"provider":{"description":"\"x\" | \"instagram\" | ... when known","type":"string"},"status":{"description":"\"distributed\" | \"scheduled\" | \"failed\"","type":"string"}},"type":"object"},"content.GenerateInput":{"properties":{"brief":{"description":"the brief/goal driving copy generation","type":"string"},"channels":{"description":"target channels (SocialPost)","type":"string"},"design":{"description":"studio design slug (asset source)","type":"string"},"doctype":{"description":"marketing.Campaign | marketing.SocialPost | marketing.Asset","type":"string"},"kind":{"description":"asset kind: ecom|product|lifestyle|hover|hero","type":"string"},"model":{"description":"optional zen model override (copy)","type":"string"},"product":{"description":"commerce product handle (copy context)","type":"string"},"project":{"description":"brand/site sub-scope (billing + tenancy axis)","type":"string"},"source_media":{"description":"asset source image (design CAD/photo)","type":"string"},"title":{"description":"optional explicit title","type":"string"},"tone":{"description":"tone override for a single draft","type":"string"},"voice":{"description":"brand-voice guidance for the copy director","type":"string"}},"type":"object"},"content.GenerateResult":{"properties":{"doctype":{"description":"the marketing type the draft was filed as","type":"string"},"name":{"description":"the new document's name — its address for every later call","type":"string"},"status":{"description":"always \"draft\"; the lifecycle owns the initial state","type":"string"}},"type":"object"},"content.PublishInput":{"properties":{"doctype":{"description":"DocType is the content type holding the item: Campaign, SocialPost or Asset.\nAny other name is refused as an unknown content type.","type":"string"},"name":{"description":"Name is the document within that type — the item to distribute. Its caption,\nmedia and channel list come off the stored document, so this names WHICH\nitem and says nothing about what goes out.","type":"string"},"scheduleAt":{"description":"ScheduleAt hands a future go-live to the channel's own scheduler, as an\nISO-8601 time. Empty posts now.","type":"string"}},"type":"object"},"content.PublishResult":{"properties":{"channels":{"description":"Channels is the channel list read off the content document — integration ids\nor provider names, as the item declares them. Empty when the item names\nnone, which targets every connected, enabled channel. It is what was ASKED\nfor; Results is what happened.","items":{"type":"string"},"type":"array"},"externalIds":{"additionalProperties":{"type":"string"},"description":"ExternalIDs maps channel id → the post id that channel returned, merged with\neverything earlier publishes recorded. Successes only, and it is the\nidempotency ledger: a channel named here is skipped by every later publish\nof this item, so the map only ever grows.","type":"object"},"results":{"description":"Results is the outcome per channel — which went out, which did not and why —\ncovering the whole fan-out including failures, so partial success is never\nflattened into one verdict. A channel the org has not connected appears here\nas failed with \"channel not connected\".","items":{"$ref":"#/components/schemas/content.ChannelResult"},"type":"array"},"status":{"description":"Status is the ONE headline, drawn from: \"distributed\" (something is on\nrecord and went out now), \"scheduled\" (same, handed to the channel's own\nscheduler for later), \"failed\" (nothing is on record — this fan-out missed\nentirely and no earlier one landed), \"in_progress\" (another publisher holds\nthe item, so this call posted NOTHING and the caller retries), and\n\"not_configured\" (no distribution edge is wired; a transition records it\ninstead of failing). A partial fan-out is \"distributed\"/\"scheduled\", never\n\"failed\" — the per-channel truth is in Results.","type":"string"}},"type":"object"},"content.StorefrontResult":{"properties":{"imageUrl":{"description":"ImageURL is the absolute URL the listing's headerImage now points at. The\nimage is REFERENCED, not copied — it stays in the org's studio output\nbucket, so removing it there empties the storefront tile.","type":"string"},"slug":{"description":"Slug is the product handle the image was attached to. It IS the asset's\n`design` field — that equality is the whole join between the studio and the\ncatalog, which is why an asset with no design produces no storefront result\nat all.","type":"string"},"status":{"description":"Status is one of \"published\" (the product image was set), \"not_configured\"\n(no commerce edge, no store provisioned for the org, or a token that is not\nadmin on the store — a fail-closed no-op) or \"failed\" (commerce answered and\nerrored). None of the three fails the transition that produced it.","type":"string"},"store":{"description":"Store is the commerce store id the image landed in, resolved for the org\nmid-call. Present only on \"published\": a result that never got that far\ncarries none.","type":"string"}},"type":"object"},"content.TransitionResult":{"properties":{"distribution":{"$ref":"#/components/schemas/content.PublishResult","description":"Distribution is the channel fan-out this move triggered. Present ONLY on the\nmove to published, the single edge that distributes — so its absence means\nno fan-out was attempted, never that one failed quietly. A fan-out that DID\nfail is present carrying its own honest status, because distribution never\nrolls the status change back."},"doctype":{"description":"DocType is the content type that moved — Campaign, SocialPost or Asset —\nechoed from the path.","type":"string"},"from":{"description":"From is the state the item held when it was read. A document carrying no\nstatus yet reads as \"draft\".","type":"string"},"name":{"description":"Name is the document that moved, echoed from the path.","type":"string"},"storefront":{"$ref":"#/components/schemas/content.StorefrontResult","description":"Storefront is the catalog side effect, present only when a published Asset\nwas product imagery — it carries a design and a kind of ecom, product or\nlifestyle. Absent for everything else, so absence reads as \"not catalog\nimagery\" rather than \"the catalog failed\"."},"to":{"description":"To is the state it holds now. From == To on an idempotent re-transition,\nwhich is legal and is where a caller that lost a publish race lands.","type":"string"}},"type":"object"},"content.boardItem":{"properties":{"doctype":{"description":"DocType is which content type the row came from: Campaign, SocialPost or\nAsset. The board spans all three at once, so this is what tells them apart.","type":"string"},"name":{"description":"Name is the document within that type. (doctype, name) is the pair every\n/v1/content write addresses an item by.","type":"string"},"project":{"description":"Project is the brand/site sub-scope within the org. Absent for an item held\nat org level rather than under one brand.","type":"string"},"status":{"description":"Status is the lifecycle state: draft, in_review, approved, queued, published\nor archived. It decides what a reader may see — the public site pulls\nexactly \"published\" and nothing else — so it is a visibility fact, not a\nworkflow label.","type":"string"},"title":{"description":"Title is the item's headline, read from its type's own title field. Empty\nfor a document that has none.","type":"string"},"updatedAt":{"description":"UpdatedAt is unix seconds of the document's last write, and the key the\nboard sorts on, newest first.","format":"int64","type":"integer"}},"type":"object"},"content.boardPage":{"properties":{"count":{"description":"Count is the number of rows in THIS page — never the org's total.","format":"int64","type":"integer"},"data":{"description":"Data is the matching items, most recently updated first.","items":{"$ref":"#/components/schemas/content.boardItem"},"type":"array"}},"type":"object"},"content.channelList":{"properties":{"data":{"description":"Data is every social channel the caller's org has connected, disabled ones\nincluded (Disabled says which).","items":{"$ref":"#/components/schemas/content.Channel"},"type":"array"}},"type":"object"},"content.stateGraph":{"properties":{"initial":{"description":"Initial is the state a fresh document starts in — \"draft\". A stored document\nwith no status at all is read as this too.","type":"string"},"live":{"description":"Live is the ONE state that is publicly readable — \"published\". The site\npulls only documents in it, so reaching Live IS site-publish; every other\nstate is invisible to a reader.","type":"string"},"states":{"description":"States is every lifecycle state in canonical order: draft, in_review,\napproved, queued, published, archived. The console lays its board columns\nout in exactly this order, so the order is part of the answer.","items":{"type":"string"},"type":"array"},"transitions":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"description":"Transitions maps each state to the states it may move to. A target absent\nfrom a state's list is REFUSED, at the endpoint and again at the storage\nboundary — this is the whole rule, not a hint for the UI. A state never\nlists itself; a move that changes nothing is always legal.","type":"object"}},"type":"object"},"content.transitionIn":{"properties":{"doctype":{"description":"DocType is the content type to act on, from the path.","type":"string"},"name":{"description":"Name is the document to act on, from the path.","type":"string"},"scheduleAt":{"description":"ScheduleAt is an ISO-8601 go-live time handed to the channel's own scheduler;\n\"\" distributes now.","type":"string"},"to":{"description":"To is the lifecycle state to move to. Required, and the move must be a legal\nedge from the item's current state.","type":"string"}},"type":"object"},"cookieAck":{"properties":{"result":{"type":"boolean"}},"type":"object"},"crawl.crawlDocument":{"properties":{"markdown":{"description":"Markdown is the page's content, extracted and rendered to markdown. This is\nthe field to read.","type":"string"},"metadata":{"description":"Metadata is whatever the document said about itself — description, og:*,\nlanguage — plus the response status, the final URL and the content type. It\nis an OPEN key space, so it is carried as raw JSON: `map[string]any`\npublishes `additionalProperties:{\"type\":\"object\"}`, which the integer\n`status` inside it refutes, while raw JSON publishes `{}` — \"any JSON\",\nwhich is true. The bytes are identical either way (encoding/json writes a\nmap's keys sorted, and this IS that marshalling)."},"title":{"description":"Title is the document's title, when it carried one.","type":"string"},"url":{"description":"URL is the address actually read, after redirects.","type":"string"}},"type":"object"},"crawl.crawlRequest":{"properties":{"url":{"description":"URL is the page to read, absolute and http or https — no other scheme is\ndialled. It is resolved from inside the cluster, so an address that turns out\nto be loopback, link-local, private or multicast is refused at the dialer,\nredirects included. Empty is not an error status: the answer comes back with\nsuccess false and the reason in error.","type":"string"}},"type":"object"},"crawl.crawlResult":{"properties":{"data":{"$ref":"#/components/schemas/crawl.crawlDocument","description":"Data is the page, present exactly when Success."},"error":{"description":"Error says what stopped the fetch: the host was refused, unreachable, or\nserved something that is not a document.","type":"string"},"success":{"description":"Success is whether the page was fetched and read. FALSE with an Error is a\ncomplete answer, not a fault — check this before reading Data.","type":"boolean"}},"type":"object"},"dataroom.dataroomAddDocument":{"properties":{"documentId":{"description":"DocumentId is the document to attach. Required, and it must already exist\nin the caller's own store — this route attaches, it never uploads."},"id":{"description":"ID is the room to add to. It is the path segment: the URL is the addressing\nauthority, and the org it is resolved in comes from the caller's principal,\nso an id from another tenant is simply not found.","type":"string"},"orderIndex":{"description":"OrderIndex fixes the document's place in the viewer's list. Optional; a\nnumber or a numeric string is accepted, and anything that is not a number\nleaves the document unordered, which sorts it last."}},"type":"object"},"dataroom.dataroomCreate":{"properties":{"description":{"description":"Description is the room's description. Optional; any JSON scalar is\naccepted and stored as its text, and omitting it leaves the room with none."},"name":{"description":"Name is the room's display name. Required, and a room without one is\nrefused with the data room's own validation error."}},"type":"object"},"dataroom.dataroomDocument":{"properties":{"contentType":{"description":"ContentType is the mime type recorded at upload, null when none was sent.","type":"string"},"createdAt":{"description":"CreatedAt is when the document was uploaded, in unix milliseconds.","format":"int64","type":"integer"},"fileKey":{"description":"FileKey is the opaque object-storage key the bytes are stored under. It is\nscoped to the tenant's own key prefix and is not a URL.","type":"string"},"fileSize":{"description":"FileSize is the stored byte count, null when it was not recorded.","format":"int64","type":"integer"},"id":{"description":"ID is the document id.","type":"string"},"name":{"description":"Name is the document's display name.","type":"string"},"numPages":{"description":"NumPages is the page count, null when it was not supplied at upload.","format":"int64","type":"integer"},"type":{"description":"Type is the document's kind, null when it was not recorded.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the document row last changed, in unix milliseconds.","format":"int64","type":"integer"}},"type":"object"},"dataroom.dataroomDocumentOne":{"properties":{"document":{"$ref":"#/components/schemas/dataroom.dataroomDocument","description":"Document is the requested document's METADATA. Its bytes are a separate\nread, GET /v1/dataroom/documents/{id}/file."}},"type":"object"},"dataroom.dataroomDocuments":{"properties":{"documents":{"description":"Documents is every document in the caller's own store, newest first.","items":{"$ref":"#/components/schemas/dataroom.dataroomDocument"},"type":"array"}},"type":"object"},"dataroom.dataroomLink":{"properties":{"allowDownload":{"description":"AllowDownload is whether a visitor may download, rather than only view.","type":"boolean"},"allowList":{"description":"AllowList narrows which addresses pass the email gate. An entry may be a\nfull address, an \"@domain.com\" suffix, or a bare \"domain.com\". An EMPTY\nlist admits everyone.","items":{"type":"string"},"type":"array"},"createdAt":{"description":"CreatedAt is when the link was minted, in unix milliseconds.","format":"int64","type":"integer"},"dataroomId":{"description":"DataroomId is the room the link opens, null for a single-document link.","type":"string"},"denyList":{"description":"DenyList rejects addresses, in the same three forms as the allow list, and\nis checked BEFORE it — so deny always wins.","items":{"type":"string"},"type":"array"},"documentId":{"description":"DocumentId is the document the link opens, null for a room link.","type":"string"},"emailProtected":{"description":"EmailProtected is whether a visitor must state an address to enter.","type":"boolean"},"expiresAt":{"description":"ExpiresAt is when the link closes, in unix milliseconds; null never expires.","format":"int64","type":"integer"},"hasPassword":{"description":"HasPassword reports THAT a password is set. The stored form is a bcrypt\nhash and no route returns it.","type":"boolean"},"id":{"description":"ID is the link id — the public token a visitor opens the room with.","type":"string"},"isArchived":{"description":"IsArchived is whether the link has been retired.","type":"boolean"},"linkType":{"description":"LinkType is DATAROOM_LINK or DOCUMENT_LINK.","type":"string"},"name":{"description":"Name is the link's label, null when none was given.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the link last changed, in unix milliseconds.","format":"int64","type":"integer"}},"type":"object"},"dataroom.dataroomLinkCreate":{"properties":{"allowDownload":{"description":"AllowDownload permits downloading rather than viewing only. Optional and\nOFF by default; any truthy JSON value turns it on."},"allowList":{"description":"AllowList narrows which addresses pass the email gate. Optional; an entry\nmay be a full address (\"ada@example.com\"), an \"@domain.com\" suffix, or a\nbare \"domain.com\". An omitted or EMPTY list admits everyone, so a link with\nno list enforces the email gate alone.","items":{},"type":"array"},"dataroomId":{"description":"DataroomId is the room to share. One of dataroomId or documentId is\nrequired, and the target must exist in the caller's own store."},"denyList":{"description":"DenyList rejects addresses, in the same three forms as the allow list.\nOptional. It is checked BEFORE the allow list, so deny always wins.","items":{},"type":"array"},"documentId":{"description":"DocumentId shares a SINGLE document instead of a room. One of dataroomId or\ndocumentId is required."},"emailProtected":{"description":"EmailProtected makes a visitor state an address before entering. Optional\nand ON by default: it is disabled only by the JSON literal false, so any\nother value — including the string \"false\" — leaves the gate on."},"expiresAt":{"description":"ExpiresAt closes the link, in unix milliseconds. Optional; a number or a\nnumeric string is accepted, and omitting it means the link never expires."},"name":{"description":"Name labels the link. Optional; any JSON scalar is stored as its text."},"password":{"description":"Password gates the link. Optional; it is hashed with bcrypt before storage\nand is never readable back through any route."}},"type":"object"},"dataroom.dataroomLinkOne":{"properties":{"link":{"$ref":"#/components/schemas/dataroom.dataroomLink","description":"Link is the link itself, including the id a visitor opens it with."}},"type":"object"},"dataroom.dataroomLinkStats":{"properties":{"linkId":{"description":"LinkId is the link these counts are for.","type":"string"},"pages":{"description":"Pages is the per-page breakdown, in page order.","items":{"$ref":"#/components/schemas/dataroom.dataroomPageStat"},"type":"array"},"totalPageViews":{"description":"TotalPageViews is how many page views the link received.","format":"int64","type":"integer"},"totalViews":{"description":"TotalViews is how many viewing sessions the link opened.","format":"int64","type":"integer"}},"type":"object"},"dataroom.dataroomLinks":{"properties":{"links":{"description":"Links is every non-archived link, newest first.","items":{"$ref":"#/components/schemas/dataroom.dataroomLink"},"type":"array"}},"type":"object"},"dataroom.dataroomLiveness":{"properties":{"service":{"description":"Service names the subsystem answering, so a probe response is attributable\nwhen several are collected together.","type":"string"},"status":{"description":"Status is `ok`. This probe has no degraded answer by design: it reports\nprocess liveness and nothing that could be false while the process serves.","type":"string"}},"type":"object"},"dataroom.dataroomMember":{"properties":{"contentType":{"description":"ContentType is the mime type recorded at upload, null when none was sent.","type":"string"},"createdAt":{"description":"CreatedAt is when the document was uploaded, in unix milliseconds.","format":"int64","type":"integer"},"dataroomDocumentId":{"description":"DataroomDocumentId is the membership id — this document's place in THIS\nroom, distinct from the document id.","type":"string"},"fileKey":{"description":"FileKey is the opaque object-storage key the bytes are stored under.","type":"string"},"fileSize":{"description":"FileSize is the stored byte count, null when it was not recorded.","format":"int64","type":"integer"},"id":{"description":"ID is the document id.","type":"string"},"name":{"description":"Name is the document's display name.","type":"string"},"numPages":{"description":"NumPages is the page count, null when it was not supplied at upload.","format":"int64","type":"integer"},"orderIndex":{"description":"OrderIndex is the document's place in the viewer's list, null when it was\nadded without one. Unordered documents sort last.","format":"int64","type":"integer"},"type":{"description":"Type is the document's kind, null when it was not recorded.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the document row last changed, in unix milliseconds.","format":"int64","type":"integer"}},"type":"object"},"dataroom.dataroomMembership":{"properties":{"dataroomDocumentId":{"description":"DataroomDocumentId is the new membership id.","type":"string"},"dataroomId":{"description":"DataroomId is the room the document was added to.","type":"string"},"documentId":{"description":"DocumentId is the document that was added.","type":"string"}},"type":"object"},"dataroom.dataroomPageStat":{"properties":{"avgDuration":{"description":"AvgDuration is totalDuration divided by views, rounded; 0 when unviewed.","format":"int64","type":"integer"},"pageNumber":{"description":"PageNumber is the page these counts are for.","format":"int64","type":"integer"},"totalDuration":{"description":"TotalDuration is the summed dwell measure reported for the page.","format":"int64","type":"integer"},"views":{"description":"Views is how many times the page was viewed.","format":"int64","type":"integer"}},"type":"object"},"dataroom.dataroomRoom":{"properties":{"createdAt":{"description":"CreatedAt is when the room was created, in unix milliseconds.","format":"int64","type":"integer"},"description":{"description":"Description is the room's description, null when none was given.","type":"string"},"id":{"description":"ID is the room id, which is what other dataroom calls address it by.","type":"string"},"name":{"description":"Name is the room's display name.","type":"string"},"pId":{"description":"PId is the room's short public identifier, unique within the tenant.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the room last changed, in unix milliseconds.","format":"int64","type":"integer"}},"type":"object"},"dataroom.dataroomRoomDetail":{"properties":{"createdAt":{"description":"CreatedAt is when the room was created, in unix milliseconds.","format":"int64","type":"integer"},"description":{"description":"Description is the room's description, null when none was given.","type":"string"},"documents":{"description":"Documents is every document in the room, in the order a visitor sees them.","items":{"$ref":"#/components/schemas/dataroom.dataroomMember"},"type":"array"},"id":{"description":"ID is the room id.","type":"string"},"name":{"description":"Name is the room's display name.","type":"string"},"pId":{"description":"PId is the room's short public identifier.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the room last changed, in unix milliseconds.","format":"int64","type":"integer"}},"type":"object"},"dataroom.dataroomRoomDetailOne":{"properties":{"dataroom":{"$ref":"#/components/schemas/dataroom.dataroomRoomDetail","description":"Dataroom is the room and its contents."}},"type":"object"},"dataroom.dataroomRoomOne":{"properties":{"dataroom":{"$ref":"#/components/schemas/dataroom.dataroomRoom","description":"Dataroom is the room itself."}},"type":"object"},"dataroom.dataroomRooms":{"properties":{"datarooms":{"description":"Datarooms is every data room in the caller's own store, newest first.","items":{"$ref":"#/components/schemas/dataroom.dataroomRoom"},"type":"array"}},"type":"object"},"dataroom.dataroomStats":{"properties":{"dataroomId":{"description":"DataroomId is the room these counts are for.","type":"string"},"links":{"description":"Links is the same per-page breakdown for each link into the room.","items":{"$ref":"#/components/schemas/dataroom.dataroomLinkStats"},"type":"array"},"totalPageViews":{"description":"TotalPageViews is the room's page views across every link.","format":"int64","type":"integer"},"totalViews":{"description":"TotalViews is the room's viewing sessions across every link.","format":"int64","type":"integer"}},"type":"object"},"dataroom.trustAsk":{"properties":{"accept":{"description":"Accept must be true when the centre states an NDA. The text accepted is\nrecorded verbatim on the request, so a later edit to the NDA cannot rewrite\nwhat this party agreed to.","type":"boolean"},"email":{"description":"Email is where the grant will be sent, and the ONLY address the resulting\nlink admits. Required.","type":"string"},"item":{"description":"Item names one published item to ask for. Optional; omitting it asks for\neverything released on request.","type":"string"},"party":{"description":"Party is the company the asker is from. Optional, and recorded as stated.","type":"string"},"reason":{"description":"Reason is why they want it. Optional, and recorded as stated — it is what the\nperson deciding reads.","type":"string"},"slug":{"description":"Slug is the centre's public address, taken from the path.","type":"string"}},"type":"object"},"dataroom.trustAskView":{"properties":{"createdAt":{"description":"CreatedAt is when the ask arrived, in unix milliseconds.","format":"int64","type":"integer"},"decidedAt":{"description":"DecidedAt is when it was answered, in unix milliseconds; 0 while open.","format":"int64","type":"integer"},"decidedBy":{"description":"DecidedBy is who answered it.","type":"string"},"email":{"description":"Email is the address that asked, as stated and UNVERIFIED — it names a party\nand proves nothing, which is why the grant is addressed to it rather than\ntrusting it.","type":"string"},"expiresAt":{"description":"ExpiresAt is when a granted ask closes, in unix milliseconds.","format":"int64","type":"integer"},"id":{"description":"ID is the request's id.","type":"string"},"item":{"description":"Item is the item asked for, empty when the whole released tier was asked for.","type":"string"},"link":{"description":"Link is the share link a granted ask became.","type":"string"},"nda":{"description":"Nda is the text this party accepted, verbatim as it stood when they accepted.","type":"string"},"note":{"description":"Note is what the decider wrote when refusing.","type":"string"},"party":{"description":"Party is the company the asker stated.","type":"string"},"reason":{"description":"Reason is why they said they want it.","type":"string"},"state":{"description":"State is open, granted or refused.","type":"string"}},"type":"object"},"dataroom.trustAsked":{"properties":{"id":{"description":"ID is the request's id, so the asker can be told about it later.","type":"string"},"state":{"description":"State is always \"open\": recording an ask decides nothing.","type":"string"}},"type":"object"},"dataroom.trustDecision":{"properties":{"days":{"description":"Days is how long the grant stays open, from now. Optional; 14 by default and\n365 at most — a longer release is describing a customer relationship rather\nthan a document.","format":"int64","type":"integer"},"id":{"description":"ID is the request to answer, taken from the path.","type":"string"},"note":{"description":"Note is why. Recorded on the request either way, and it is what the record\nshows a year later.","type":"string"}},"type":"object"},"dataroom.trustDesk":{"properties":{"grants":{"description":"Grants is every grant that has been made, newest first.","items":{"$ref":"#/components/schemas/dataroom.trustGrantView"},"type":"array"},"items":{"description":"Items is everything the org holds, both tiers, retired included.","items":{"$ref":"#/components/schemas/dataroom.trustItemView"},"type":"array"},"name":{"description":"Name is the centre's display name.","type":"string"},"nda":{"description":"Nda is the text a party must accept before asking.","type":"string"},"published":{"description":"Published is whether the centre answers at its public address.","type":"boolean"},"requests":{"description":"Requests is every ask, newest first, open ones included.","items":{"$ref":"#/components/schemas/dataroom.trustAskView"},"type":"array"},"slug":{"description":"Slug is the public address, empty until the centre is published.","type":"string"}},"type":"object"},"dataroom.trustEdit":{"properties":{"body":{"description":"Body replaces the item's content.","type":"string"},"document":{"description":"Document replaces the file the item points at — this is how a report is\nsuperseded by its next edition. The new document must already exist in the\ncaller org's own store.","type":"string"},"framework":{"description":"Framework replaces the standard it speaks to.","type":"string"},"id":{"description":"ID is the item to change, taken from the path.","type":"string"},"name":{"description":"Name replaces its title.","type":"string"},"retired":{"description":"Retired withdraws the item, or true→false restores it. A retired item leaves\nthe public centre at once and can no longer be granted; grants already made\nover it stand, because they are part of the record.","type":"boolean"},"summary":{"description":"Summary replaces the line about it.","type":"string"},"tier":{"description":"Tier moves it between public and gated. Moving an auditor-signed item to\npublic is refused.","type":"string"}},"type":"object"},"dataroom.trustGrantView":{"properties":{"email":{"description":"Email is the one address the link admits.","type":"string"},"expiresAt":{"description":"ExpiresAt is when the grant closes, in unix milliseconds.","format":"int64","type":"integer"},"item":{"description":"Item is the item granted, empty when the whole released tier was granted.","type":"string"},"link":{"description":"Link is the share link's id — the token the party opens. Reading it here does\nnot widen it: the link admits only Email whoever holds the id.","type":"string"},"live":{"description":"Live is whether the grant is still open at the time of reading.","type":"boolean"}},"type":"object"},"dataroom.trustGranted":{"properties":{"delivery":{"description":"Delivery is empty when the asker was mailed, and otherwise says what happened\ninstead — so an approver is never left believing a mail went out that did not.","type":"string"},"expiresAt":{"description":"ExpiresAt is when the grant closes, in unix milliseconds.","format":"int64","type":"integer"},"link":{"description":"Link is the share link's id. The link admits only the address that asked.","type":"string"},"state":{"description":"State is \"granted\".","type":"string"}},"type":"object"},"dataroom.trustItem":{"properties":{"available":{"description":"Available is \"now\" when the item can be read immediately, or \"on request\"\nwhen it is released only to a party who asks and is answered. It is the one\nfield a page renders the difference from.","type":"string"},"body":{"description":"Body is the item's content, for the kinds that are text rather than a file —\nan article, a subprocessor entry, a note. Empty for anything released on\nrequest: a summary of a document is still the document.","type":"string"},"framework":{"description":"Framework is the standard the item speaks to, when it speaks to one.","type":"string"},"id":{"description":"ID addresses the item — for reading it if it is available now, or for naming\nit in a request if it is not.","type":"string"},"kind":{"description":"Kind is what the item is: report, letter, policy, questionnaire,\nsubprocessor, article or update.","type":"string"},"name":{"description":"Name is the item's title.","type":"string"},"signed":{"description":"Signed is \"self\" when the org states it itself and \"auditor\" when an\nindependent auditor put their name to it. It is the reason an item is\navailable now or on request, so a reader can see the rule rather than infer it.","type":"string"},"summary":{"description":"Summary is a line about the item.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the item last changed, in unix milliseconds.","format":"int64","type":"integer"}},"type":"object"},"dataroom.trustItemView":{"properties":{"attester":{"description":"Attester is who vouched for it: self or auditor.","type":"string"},"body":{"description":"Body is the item's content for the kinds that are text rather than a file.","type":"string"},"createdAt":{"description":"CreatedAt is when it was published, in unix milliseconds.","format":"int64","type":"integer"},"document":{"description":"Document is the data-room document holding its bytes, empty when it has none.","type":"string"},"framework":{"description":"Framework is the standard it speaks to, when it speaks to one.","type":"string"},"id":{"description":"ID addresses the item.","type":"string"},"kind":{"description":"Kind is one of report, letter, policy, questionnaire, subprocessor, article\nor update — the closed set the public centre knows how to draw.","type":"string"},"name":{"description":"Name is the label the centre lists it under.","type":"string"},"retired":{"description":"Retired is whether it has been withdrawn. A retired item is absent from the\npublic centre and cannot be granted; it is kept because a grant already made\nover it is part of the record.","type":"boolean"},"summary":{"description":"Summary is a line about it.","type":"string"},"tier":{"description":"Tier is public or gated. Gated is the default and an auditor-signed item can\nonly ever be gated.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it last changed, in unix milliseconds.","format":"int64","type":"integer"}},"type":"object"},"dataroom.trustPage":{"properties":{"items":{"description":"Items is everything the centre publishes: what can be read now, and what\nexists and is released on request.","items":{"$ref":"#/components/schemas/dataroom.trustItem"},"type":"array"},"name":{"description":"Name is the org's display name for its centre.","type":"string"},"nda":{"description":"Nda is the text a party must accept to ask for the gated items, verbatim.\nEmpty when the org asks for none.","type":"string"},"slug":{"description":"Slug is the centre's public address.","type":"string"}},"type":"object"},"dataroom.trustPublish":{"properties":{"attester":{"description":"Attester is who vouched for it: \"self\" for anything the org states itself, or\n\"auditor\" for anything an independent auditor put their name to. REQUIRED, and\nanything other than \"self\" is read as \"auditor\" — the safe direction, since an\nauditor-signed item can only ever be released on request.","type":"string"},"body":{"description":"Body is the item's content for the kinds that are text rather than a file: an\narticle, a subprocessor entry, a dated note.","type":"string"},"document":{"description":"Document is a data-room document holding the item's bytes, uploaded first\nthrough POST /v1/dataroom/documents. Optional: an item can be content with no\nfile. The document must already exist in the caller org's own store.","type":"string"},"framework":{"description":"Framework is the standard it speaks to. Optional and free text — the value is\nthe org's own, not a list this API keeps.","type":"string"},"kind":{"description":"Kind is what the item is: report, letter, policy, questionnaire, subprocessor,\narticle or update. Required.","type":"string"},"name":{"description":"Name is the item's title. Required.","type":"string"},"summary":{"description":"Summary is a line about it. Optional.","type":"string"},"tier":{"description":"Tier is who may read it: \"public\" or \"gated\". It DEFAULTS TO GATED and\nanything that is not exactly \"public\" is gated, so an item published by a\ncaller that says nothing is private and someone has to release it on purpose.\n\"public\" is refused for an auditor-signed item.","type":"string"}},"type":"object"},"dataroom.trustRefused":{"properties":{"state":{"description":"State is \"refused\".","type":"string"}},"type":"object"},"dataroom.trustSettings":{"properties":{"name":{"description":"Name is the centre's display name. Required to publish.","type":"string"},"nda":{"description":"Nda is the text a party must accept before asking for a document. Optional;\nempty asks for no acceptance. The text in force is copied onto each request as\nit is accepted, so editing it never changes what anyone already agreed to.","type":"string"},"publish":{"description":"Publish makes the centre answer at its public address. False withdraws it: the\naddress stops answering while every item, grant and record stays exactly as it\nwas, so withdrawing is reversible and loses nothing.","type":"boolean"},"slug":{"description":"Slug is the public address to answer at — a lowercase label of letters,\ndigits and hyphens. Required to publish, unique across the deployment, and one\norg holds one: publishing under a new address MOVES the centre rather than\nleaving the old one answering.","type":"string"}},"type":"object"},"dataset.riskDataset":{"properties":{"at":{"description":"At is when this version last changed state, RFC 3339 UTC.","type":"string"},"by":{"description":"By is who moved it there: the validated user, or the org itself when the\ncaller is a machine with no user behind it.","type":"string"},"counts":{"$ref":"#/components/schemas/dataset.riskSplitCounts","description":"Counts is how the rows fall across the splits."},"digest":{"description":"Digest fingerprints the SPEC and the ROWS together. Two materialisations of\none spec agree on it or the plane says they do not.","type":"string"},"name":{"description":"Name identifies the dataset across all of its versions.","type":"string"},"oversize":{"description":"Oversize is how many of the window's subjects this version could NOT carry\nbecause their subject identity exceeds the plane's per-subject byte bound.\n\nIt is on the wire, not only in a log, because it is the one degradation a\ncaller cannot otherwise detect: the rows that are here look complete, and a\ndataset silently missing a population is a model silently blind to it.\nNon-zero does not make a version invalid — it makes it a version whose\ncoverage is STATED. Zero is the normal case and omits.","format":"int64","type":"integer"},"refusal":{"description":"Refusal names why there are no bytes, when there are none.","type":"string"},"running":{"description":"Running is true while THIS process is materialising the version. A version\nthat is `materializing` and not running was started by a process that is\ngone — two states the register cannot tell apart, because a register cannot\nknow which processes are alive.","type":"boolean"},"share":{"description":"Share is the fraction of the window's subjects admitted, in thousandths.\n1000 means the whole window fitted under the cap; anything less means the\nversion is a reproducible sample and says by how much.","format":"int64","type":"integer"},"spec":{"$ref":"#/components/schemas/dataset.riskDatasetSpec","description":"Spec is the bound query this version was built from, exactly as recorded."},"status":{"description":"Status is declared, materializing, ready or refused. Only `ready` has bytes,\nand `ready` is terminal: a published version is never rewritten.","type":"string"},"truncated":{"description":"Truncated is true when the row cap bound before the window ran out. The\ntrailing subject is dropped whole when that happens, because half a subject\non one side of a split is exactly the leak the grouping prevents.","type":"boolean"},"version":{"description":"Version is which version this is, from 1 and monotone within the dataset.\nA number is never reused — not even after a disposal, where the next declare\ncontinues the count — so \"signups v3\" means one thing forever, which is what\nmakes a model's citation of it checkable.","format":"int64","type":"integer"}},"type":"object"},"dataset.riskDatasetDisposal":{"properties":{"dataset":{"description":"Dataset is the dataset that was disposed of. The NAME survives: declaring it\nagain continues the version count rather than starting over at 1.","type":"string"},"rows":{"description":"Rows is how many rows they held between them, as the REGISTER recorded them\nwhen each was materialised — not a count of what the drop deleted, which is\ngone by the time this answers.","format":"int64","type":"integer"},"versions":{"description":"Versions is how many versions went.","format":"int64","type":"integer"}},"type":"object"},"dataset.riskDatasetList":{"properties":{"items":{"description":"Items is one entry per dataset, carrying its newest version. Never null: an\norg that has declared nothing gets an empty array.","items":{"$ref":"#/components/schemas/dataset.riskDataset"},"type":"array"}},"type":"object"},"dataset.riskDatasetRow":{"properties":{"at":{"description":"At is the row's instant.","type":"string"},"id":{"description":"ID names the row forever. It is DERIVED from the row's own subject and\ninstant, not allocated, so two materialisations of the same fact agree on it\nwithout coordinating.","type":"string"},"kind":{"description":"Kind is the subject kind: person, session or account.","type":"string"},"point":{"description":"Point is the coordinates, in the order the version's spec names its dims.","items":{"format":"double","type":"number"},"type":"array"},"split":{"description":"Split is train, val or test.","type":"string"},"subject":{"description":"Subject is the identity within that kind — whose row this is. Every row of\none subject is in ONE split, decided by that subject's earliest instant, so\na subject is never on both sides of a cut.","type":"string"}},"type":"object"},"dataset.riskDatasetRows":{"properties":{"dataset":{"description":"Dataset is the dataset the page was read from.","type":"string"},"digest":{"description":"Digest is the version's fingerprint. An exported page that did not carry it\nwould be bytes with no way to say which dataset they are.","type":"string"},"dims":{"description":"Dims names what each coordinate of Point means, in Point's own order.","items":{"type":"string"},"type":"array"},"limit":{"description":"Limit is the page size actually served: the one asked for, clamped to the\nplane's own bound of 5000. Fewer rows than Limit means the version ended.","format":"int64","type":"integer"},"offset":{"description":"Offset is where this page starts in the version's own row order, which is by\nrow id and therefore stable forever.","format":"int64","type":"integer"},"rows":{"description":"Rows is the page. Never null.","items":{"$ref":"#/components/schemas/dataset.riskDatasetRow"},"type":"array"},"version":{"description":"Version is which published version it was read from — the one asked for, or\nthe newest published one when the request named none.","format":"int64","type":"integer"}},"type":"object"},"dataset.riskDatasetSpec":{"properties":{"cuts":{"description":"Cuts are the two RFC 3339 instants dividing train | val | test. Omit them to\ntake 70% and 85% of the window by time. Splitting is TEMPORAL and then\ngrouped by subject — a random split puts one device on both sides of the\nline and the model memorises the entity instead of the behaviour.","items":{"type":"string"},"type":"array"},"dims":{"description":"Dims are the coordinates to carry, by published name. Empty takes the whole\nsurface. They are stored in the plane's own order, never the order given, so\ntwo requests naming the same dims produce identical rows.","items":{"type":"string"},"type":"array"},"from":{"description":"From is where the event window opens, RFC 3339, INCLUSIVE. The window may\nnot be longer than the source's own retention: past that, its older half is\nalready gone and the dataset would silently be shorter than it says.","type":"string"},"horizon":{"description":"Horizon is how many days a row must have aged before it may be admitted. It\nis what keeps a fact that was not yet knowable at scoring time out of a\ntraining set: a chargeback lands 30 to 120 days after the transaction it\ncondemns, so 120 for the payment lane and 14 for signup abuse. Zero admits\nthe whole window and is honest only where the outcome is immediate.","format":"int64","type":"integer"},"kind":{"description":"Kind narrows to one subject kind — person, session or account. Empty takes\nevery kind.","type":"string"},"name":{"description":"Name identifies the dataset across its versions: lower-case letters, digits\nand hyphens, starting with a letter.","type":"string"},"rows":{"description":"Rows caps the materialisation. Zero takes the plane's own bound.","format":"int64","type":"integer"},"seed":{"description":"Seed decides WHICH subjects are admitted when the window holds more rows\nthan the cap allows. It is recorded on the version, so a capped dataset is\nreproducible rather than being whichever rows the store returned first.\nOmit it to seed from the dataset's name.","type":"string"},"to":{"description":"To is where the window ends, EXCLUSIVE, so two datasets meeting at one\ninstant share no row. A materialisation reads less than this — the end is\npulled back by Horizon, and the lineage reports the window it actually read.","type":"string"}},"type":"object"},"dataset.riskDatasetVersions":{"properties":{"items":{"description":"Items is every version of it, newest first — including the disposed ones,\nwhose record outlives their rows. Never null.","items":{"$ref":"#/components/schemas/dataset.riskDataset"},"type":"array"},"name":{"description":"Name is the dataset these versions belong to, as the register holds it.","type":"string"}},"type":"object"},"dataset.riskLineage":{"properties":{"dataset":{"description":"Dataset is the dataset traced.","type":"string"},"digest":{"description":"Digest is the version's fingerprint, repeated here so a lineage answer is\nself-contained.","type":"string"},"from":{"description":"From is where the window actually read opens, RFC 3339. Same as the spec's.","type":"string"},"holds":{"description":"Holds is what the source holds for the same window NOW. The difference\nbetween it and Rows is the whole of the reproducibility claim.","format":"int64","type":"integer"},"oversize":{"description":"Oversize is how many subjects the window held that were too large to\nrepresent when this version was built. It is part of the fingerprint, so it\nis part of what \"reproducible\" is measured over.","format":"int64","type":"integer"},"refusal":{"description":"Refusal says which way it failed — the window expired, or the source now\nholds a different count. Absent when Reproducible is true.","type":"string"},"reproducible":{"description":"Reproducible is true when the source still holds what this version was built\nfrom — measured by asking it again, not recalled. False is ordinary: the\nsource is fed by a rollup that runs behind the events, so \"it holds more\nnow\" is the common case and it means re-running the spec would not produce\nthis version.","type":"boolean"},"retention":{"description":"Retention is the source's own expiry rule as the store reports it, read at\nmaterialisation time rather than assumed. A source whose retention is\nshorter than this window cannot re-derive it.","type":"string"},"rows":{"description":"Rows is how many rows the source held for that window at materialisation\ntime. Holds is the same question asked now, and the difference between them\nis the whole of the reproducibility claim.","format":"int64","type":"integer"},"share":{"description":"Share is the fraction of subjects admitted, in thousandths.","format":"int64","type":"integer"},"source":{"description":"Source is the plane the rows were derived from.","type":"string"},"subjects":{"description":"Subjects is how many distinct subjects those rows belonged to. It is the\nreal sample size — the row count flatters it whenever a subject is active.","format":"int64","type":"integer"},"to":{"description":"To is where it ends: the spec's own end pulled BACK by the maturity horizon,\nso it is usually earlier than the spec says. This is the window a\nreproduction has to ask for — asking the spec's would not return these rows.","type":"string"},"version":{"description":"Version is the version traced — the one asked for, or the newest published\none when the request named none.","format":"int64","type":"integer"}},"type":"object"},"dataset.riskSplitCounts":{"properties":{"judged":{"description":"Judged is how many rows carry a disposition. It is zero until a label plane\nwrites one, and reporting it plainly is what lets a model plane refuse to\nrank rather than name a winner it cannot justify.","format":"int64","type":"integer"},"productive":{"description":"Productive is how many judged rows carry the one disposition.","format":"int64","type":"integer"},"rows":{"description":"Rows is how many rows the version holds across every split. It is the size\nof the version, not of the source window — the horizon, the cuts and the row\ncap all bind before this number.","format":"int64","type":"integer"},"subjects":{"description":"Subjects is how many distinct subjects the rows belong to. Every row of one\nsubject is in ONE split, so this is the real sample size — the row count\nflatters it whenever a subject is active.","format":"int64","type":"integer"},"test":{"description":"Test is how many fall after the second cut — the LATEST slice, and the only\none a score is honest about, since the split is temporal.","format":"int64","type":"integer"},"train":{"description":"Train is how many rows fall before the first cut — the EARLIEST slice of the\nwindow, which is what a model is fitted on.","format":"int64","type":"integer"},"unproductive":{"description":"Unproductive is how many carry the other. With Productive it accounts for\nJudged, so the class imbalance is visible before anyone trains on it; both\nstay 0 while Judged is 0.","format":"int64","type":"integer"},"val":{"description":"Val is how many fall between the two cuts, held out for tuning.","format":"int64","type":"integer"}},"type":"object"},"deckOut":{"properties":{"documentId":{"type":"string"}},"type":"object"},"declareEnv":{"properties":{"name":{"type":"string"},"public":{"type":"boolean"},"value":{"type":"string"}},"type":"object"},"declareReq":{"properties":{"build":{"type":"boolean"},"dockerfile":{"type":"string"},"env":{"items":{"$ref":"#/components/schemas/declareEnv"},"type":"array"},"host":{"type":"string"},"mode":{"type":"string"},"name":{"type":"string"},"org":{"type":"string"},"partOf":{"type":"string"},"port":{"type":"integer"},"ref":{"type":"string"},"replicas":{"type":"integer"},"repo":{"type":"string"},"tag":{"type":"string"}},"type":"object"},"declareResp":{"properties":{"app":{"$ref":"#/components/schemas/Declaration"},"build":{"$ref":"#/components/schemas/buildRef"},"declaration":{"$ref":"#/components/schemas/declareResult"},"notice":{"type":"string"}},"type":"object"},"declareResult":{"properties":{"changed":{"type":"boolean"},"commit":{"type":"string"},"created":{"type":"boolean"},"declaration":{"$ref":"#/components/schemas/Declaration"},"live":{"type":"boolean"},"mode":{"type":"string"},"ref":{"type":"string"},"review":{"type":"string"}},"type":"object"},"deploy.argoApp":{"properties":{"apiVersion":{"description":"APIVersion is the constant \"argoproj.io/v1alpha1\" — the shape, not the source.\nThese are projections of operator App CRs and Hanzo CD Applications; no\nargoproj.io object is stored anywhere behind this plane.","type":"string"},"kind":{"description":"Kind is the constant \"Application\".","type":"string"},"metadata":{"$ref":"#/components/schemas/deploy.argoMeta","description":"Metadata is the projected object's identity."},"spec":{"$ref":"#/components/schemas/deploy.argoSpec","description":"Spec is the desired state: where it comes from, where it lands, what project\nit belongs to."},"status":{"$ref":"#/components/schemas/deploy.argoStatus","description":"Status is what was observed: the sync verdict, the health, and the owned\nobjects when this is a detail read."}},"type":"object"},"deploy.argoAppList":{"properties":{"apiVersion":{"description":"APIVersion is the constant \"argoproj.io/v1alpha1\".","type":"string"},"items":{"description":"Items is one entry per operator App CR the caller may see — its own org's, or\nevery platform namespace's for a SuperAdmin — followed, for a SuperAdmin\nonly, by every Hanzo CD Application in the cluster. Empty (never null) rather\nthan absent when the caller owns nothing.","items":{"$ref":"#/components/schemas/deploy.argoApp"},"type":"array"},"kind":{"description":"Kind is the constant \"ApplicationList\".","type":"string"},"metadata":{"$ref":"#/components/schemas/deploy.argoListMeta","description":"Metadata is the list envelope the SPA expects; it carries no resume point."}},"type":"object"},"deploy.argoCluster":{"properties":{"connectionState":{"$ref":"#/components/schemas/deploy.argoConnectionState","description":"ConnectionState is whether the destination is reachable."},"info":{"$ref":"#/components/schemas/deploy.argoClusterInfo","description":"Info is the connection state again plus the count of applications targeting\nthis destination."},"name":{"description":"Name is what the Destination column shows: \"in-cluster\" for this cluster,\notherwise whatever spec.destination.name declares, falling back to the server\nURL when it declares none.","type":"string"},"server":{"description":"Server is the destination's API URL, and the key the list is deduplicated by.\nhttps://kubernetes.default.svc is this cluster.","type":"string"}},"type":"object"},"deploy.argoClusterInfo":{"properties":{"applicationsCount":{"description":"ApplicationsCount is how many of THE CALLER'S applications reconcile into\nthis cluster, so a tenant sees its own count and a SuperAdmin the fleet's. It\nis zero for the in-cluster destination when the caller owns nothing, since\nthat destination is listed whether or not anything targets it.","format":"int64","type":"integer"},"connectionState":{"$ref":"#/components/schemas/deploy.argoConnectionState","description":"ConnectionState repeats the cluster's own connection state, which is where\nArgoCD's UI reads it from on this object."},"serverVersion":{"description":"ServerVersion is the kubernetes version of the destination. Always absent:\nnothing here queries the API server for it.","type":"string"}},"type":"object"},"deploy.argoClusterList":{"properties":{"items":{"description":"Items is one entry per distinct destination server, in first-seen order with\nthe in-cluster destination first. Never empty: an empty fleet still has the\none cluster it would deploy into.","items":{"$ref":"#/components/schemas/deploy.argoCluster"},"type":"array"},"metadata":{"$ref":"#/components/schemas/deploy.argoListMeta","description":"Metadata is the list envelope the SPA expects; it carries no resume point."}},"type":"object"},"deploy.argoConnectionState":{"properties":{"attemptedAt":{"description":"AttemptedAt is when the connection was last probed. Always absent: nothing is\nprobed, and a fabricated timestamp would claim a check that never ran.","type":"string"},"message":{"description":"Message is why a connection failed. Always absent, since none does.","type":"string"},"status":{"description":"Status is ArgoCD's ConnectionStatus — Successful, Failed or Unknown. Always\nSuccessful here: the destination is the cluster this process is already\nrunning in, so it is reachable by construction and there is no credential to\nprobe.","type":"string"}},"type":"object"},"deploy.argoDestination":{"properties":{"name":{"description":"ArgoCD allows a destination by cluster name; omitted for the in-cluster projection.","type":"string"},"namespace":{"description":"Namespace is where in that cluster the workload lands. \"*\" on a project's\ndestination fence means any namespace.","type":"string"},"server":{"description":"Server is the cluster API URL the application reconciles into. Everything\nthis plane projects lands in the cluster it runs in, so it is\nhttps://kubernetes.default.svc — except on a project's destination fence,\nwhere \"*\" means any cluster.","type":"string"}},"type":"object"},"deploy.argoGroupKind":{"properties":{"group":{"description":"Group is the API group a project admits, \"*\" for any. Empty names the core\ngroup.","type":"string"},"kind":{"description":"Kind is the kind it admits, \"*\" for any.","type":"string"}},"type":"object"},"deploy.argoHealth":{"properties":{"message":{"description":"Message is why the status is what it is — \"Running: no replicas ready\",\n\"iam: CrashLoopBackOff\". A Healthy object carries one too (\"Running: all\nreplicas ready\"), so this is not a failure signal. Always absent on a CD row,\nwhich reports no health message.","type":"string"},"status":{"description":"Status is the ArgoCD health vocabulary, Capitalized: Healthy, Progressing,\nDegraded, Suspended, Missing or Unknown. For an App CR it is derived per\nobject from what the operator reconciled (a workload with every replica ready\nis Healthy, one scaled to zero is Suspended, a crash-looping pod is\nDegraded); for a CD row it is the verdict CD wrote.","type":"string"}},"type":"object"},"deploy.argoInfoItem":{"properties":{"name":{"description":"Name is the chip's label. The only one this projection produces is\n\"Image Tag\".","type":"string"},"value":{"description":"Value is the chip's value — for \"Image Tag\", the tag the node runs.","type":"string"}},"type":"object"},"deploy.argoListMeta":{"properties":{"resourceVersion":{"description":"ResourceVersion is the k8s list version a watch would resume from. Always\nempty: every list on this plane is COMPUTED per request rather than read from\none etcd revision, so there is no point to resume from. The live view is the\nSSE stream, not a resumed watch.","type":"string"}},"type":"object"},"deploy.argoMeta":{"properties":{"creationTimestamp":{"description":"CreationTimestamp is when the source object was created, RFC 3339 to the\nsecond. Empty for a synthesized project.","type":"string"},"labels":{"additionalProperties":{"type":"string"},"description":"Labels are the labels this projection puts on the row, not the source\nobject's full label set. An application projected from an App CR carries\nhanzo.ai/instance (its name), hanzo.ai/env (main, test or dev, from the\nnamespace it was read from) and hanzo.ai/org when the CR declares a tenant. A\nHanzo CD Application carries the CR's own labels verbatim. A project\nreflected from IAM carries hanzo.ai/org alone.","type":"object"},"name":{"description":"Name is the projected object's name: the App CR's metadata.name for an\napplication, the CD Application's name for a CD row, and the IAM project name\nfor a project.","type":"string"},"namespace":{"description":"Namespace is the namespace the source object was read from — the tenant or\nplatform namespace for an App CR, CD's controller namespace for a CD row.\nEmpty for a project synthesized here, which lives in no namespace.","type":"string"},"uid":{"description":"UID is the k8s metadata.uid of the source object, which is what the SPA keys\na row on across refreshes. Empty for a synthesized project — there is no\nobject to take one from.","type":"string"}},"type":"object"},"deploy.argoNode":{"properties":{"createdAt":{"description":"CreatedAt is the object's creationTimestamp, RFC 3339 UTC to the second.\nAbsent when the object carries none.","type":"string"},"group":{"description":"Group is the object's API group: empty for the core group (Pod, Service,\nConfigMap), otherwise apps, networking.k8s.io, autoscaling or policy — and\nhanzo.ai for the App CR at the root.","type":"string"},"health":{"$ref":"#/components/schemas/deploy.argoHealth","description":"Health is the node's own derived health. Always present on a node of this\ntree; a kind with no health signal of its own reports Healthy, since a\nConfigMap existing IS its healthy state."},"images":{"description":"Images are the container images running on this node. Always absent — the tag\ntravels as the \"Image Tag\" chip in Info instead, which is where the SPA reads\nit on a node.","items":{"type":"string"},"type":"array"},"info":{"description":"Info are the chips shown on the node. At most one: the image tag — the\nRUNNING tag on a Deployment, ReplicaSet or Pod, and the DECLARED tag on the\nApp CR at the root. Absent on a node that carries no image at all.","items":{"$ref":"#/components/schemas/deploy.argoInfoItem"},"type":"array"},"kind":{"description":"Kind is the object kind. The root is the App CR; below it come Deployment,\nReplicaSet, Pod, Service, Ingress, HorizontalPodAutoscaler,\nPodDisruptionBudget and ConfigMap. Never Secret — the walk does not visit\nthem, so no materialized environment can reach the tree.","type":"string"},"name":{"description":"Name is the object's metadata.name.","type":"string"},"namespace":{"description":"Namespace is the namespace the walk ran in, the same for every node of one\ntree.","type":"string"},"parentRefs":{"description":"ParentRefs are the node's edges UPWARD, which is how the SPA draws the DAG\nfrom this flat list. Exactly one entry where present: a depth-1 object points\nat the App CR, a ReplicaSet at its Deployment, a Pod at its ReplicaSet (or at\nthe Deployment whose selector matches it, when the ReplicaSet is gone).\nAbsent on the root.","items":{"$ref":"#/components/schemas/deploy.argoResourceRef"},"type":"array"},"resourceVersion":{"description":"ResourceVersion is the k8s version a watch would resume from. Always empty:\nthe tree is rebuilt from live reads on every request, including on every\nframe of the SSE stream, so there is no revision to resume from.","type":"string"},"uid":{"description":"UID is the object's metadata.uid. Absent on a PARENT reference, which\naddresses its target by kind and name rather than by identity.","type":"string"},"version":{"description":"Version is the object's API version as the live object reports it: v1 for\nevery kind the walk reaches except the HorizontalPodAutoscaler, which is\nautoscaling/v2.","type":"string"}},"type":"object"},"deploy.argoProject":{"properties":{"apiVersion":{"description":"APIVersion is the constant \"argoproj.io/v1alpha1\". A project here is an IAM\nresource wearing that shape; no argoproj.io object is stored behind it.","type":"string"},"kind":{"description":"Kind is the constant \"AppProject\".","type":"string"},"metadata":{"$ref":"#/components/schemas/deploy.argoMeta","description":"Metadata is the project's identity: its name is the key an application's\nspec.project matches, and is the same string an App CR carries in its\napp.kubernetes.io/part-of label."},"spec":{"$ref":"#/components/schemas/deploy.argoProjectSpec","description":"Spec is the fence the SPA displays — repos, destinations, admitted kinds."},"status":{"$ref":"#/components/schemas/deploy.argoProjectStat","description":"Status is always the empty object. A project has no reconciled state here;\nthe field exists because the SPA reads it."}},"type":"object"},"deploy.argoProjectList":{"properties":{"items":{"description":"Items is the projects visible to the caller — its own organization's, or\nevery organization's for a SuperAdmin. A project named \"default\" is always\npresent and is prepended when IAM does not carry one, because that is what an\napplication with no project label groups under.","items":{"$ref":"#/components/schemas/deploy.argoProject"},"type":"array"},"metadata":{"$ref":"#/components/schemas/deploy.argoListMeta","description":"Metadata is the list envelope the SPA expects; it carries no resume point."}},"type":"object"},"deploy.argoProjectSpec":{"properties":{"clusterResourceWhitelist":{"description":"ClusterResourceWhitelist are the cluster-scoped kinds it may create —\n[{group:\"*\", kind:\"*\"}] on a synthesized project.","items":{"$ref":"#/components/schemas/deploy.argoGroupKind"},"type":"array"},"description":{"description":"Description is the project's human label: the IAM project's display name, or\nits description when it has no display name. Absent when IAM carries neither.","type":"string"},"destinations":{"description":"Destinations are the cluster/namespace pairs it may write to — a single\n{server:\"*\", namespace:\"*\"} on a synthesized project, for the same reason.","items":{"$ref":"#/components/schemas/deploy.argoDestination"},"type":"array"},"sourceRepos":{"description":"SourceRepos are the git repos applications in this project may pull from.\n[\"*\"] for every project this plane synthesizes or reflects from IAM: the\nboundary that actually holds on this platform is the IAM org, resolved before\na row is ever projected, so the projected fence is deliberately permissive\nand is NOT an authorization statement.","items":{"type":"string"},"type":"array"}},"type":"object"},"deploy.argoProjectStat":{"properties":{},"type":"object"},"deploy.argoResourceRef":{"properties":{"group":{"description":"Group is the object's API group: empty for the core group (Pod, Service,\nConfigMap), otherwise apps, networking.k8s.io, autoscaling or policy — and\nhanzo.ai for the App CR at the root.","type":"string"},"kind":{"description":"Kind is the object kind. The root is the App CR; below it come Deployment,\nReplicaSet, Pod, Service, Ingress, HorizontalPodAutoscaler,\nPodDisruptionBudget and ConfigMap. Never Secret — the walk does not visit\nthem, so no materialized environment can reach the tree.","type":"string"},"name":{"description":"Name is the object's metadata.name.","type":"string"},"namespace":{"description":"Namespace is the namespace the walk ran in, the same for every node of one\ntree.","type":"string"},"uid":{"description":"UID is the object's metadata.uid. Absent on a PARENT reference, which\naddresses its target by kind and name rather than by identity.","type":"string"},"version":{"description":"Version is the object's API version as the live object reports it: v1 for\nevery kind the walk reaches except the HorizontalPodAutoscaler, which is\nautoscaling/v2.","type":"string"}},"type":"object"},"deploy.argoResourceStatus":{"properties":{"group":{"description":"Group is the object's API group: empty for the core group (Pod, Service,\nConfigMap), otherwise apps, networking.k8s.io, autoscaling or policy — and\nhanzo.ai for the App CR itself.","type":"string"},"health":{"$ref":"#/components/schemas/deploy.argoHealth","description":"Health is this object's own health, derived from its live state by the same\nrule the resource tree uses."},"kind":{"description":"Kind is the object kind — App, Deployment, ReplicaSet, Pod, Service, Ingress,\nHorizontalPodAutoscaler, PodDisruptionBudget, ConfigMap. Never Secret: the\nwalk that produces these does not visit them.","type":"string"},"name":{"description":"Name is the object's metadata.name.","type":"string"},"namespace":{"description":"Namespace is the namespace the object was found in — the same one for every\nentry of an application, since the walk is confined to it.","type":"string"},"status":{"description":"Status is the APPLICATION's sync verdict repeated on every row, not a\nper-object one. The operator owns these children, so no child has a desired\nstate of its own to compare against.","type":"string"},"version":{"description":"Version is the object's API version as the live object reports it: v1 for\nevery kind here except the HorizontalPodAutoscaler, which is autoscaling/v2.","type":"string"}},"type":"object"},"deploy.argoRevisionMetadata":{"properties":{"author":{"description":"Author is the commit author. Always absent: an App CR pins an IMAGE, so this\nprocess has no commit to read one from and will not invent one.","type":"string"},"date":{"description":"Date is when the App CR was created, RFC 3339 UTC — the only real timestamp\nthere is here. It is NOT the date of the revision asked for.","type":"string"},"message":{"description":"Message is the revision asked for, echoed back — not a commit message. The\nempty revision and \"HEAD\" resolve to the image tag the CR declares\n(spec.image.tag), and anything longer than 256 characters is truncated to it.","type":"string"},"signatureInfo":{"description":"SignatureInfo is the GPG verification result for the revision. Always absent:\nnothing here verifies a signature, and an empty field says so rather than\nimplying an unsigned commit.","type":"string"},"tags":{"description":"Tags are the git tags pointing at the revision. Always absent, for the same\nreason as Author.","items":{"type":"string"},"type":"array"}},"type":"object"},"deploy.argoSource":{"properties":{"path":{"description":"Path is the directory within RepoURL. Display-only alongside a display-only\nRepoURL; CD's own value for a CD row.","type":"string"},"repoURL":{"description":"RepoURL is the git repository the desired state comes from. For an\napplication projected from an App CR it is the fleet manifest repo and is\nDISPLAY ONLY — an App CR pins an image, and nothing is rendered from this\nrepo to produce it. For a CD row it is the repo CD actually polls.","type":"string"},"targetRevision":{"description":"TargetRevision is the git ref tracked there — a branch such as \"main\".\nDisplay-only for a projected App CR; the ref CD tracks for a CD row.","type":"string"}},"type":"object"},"deploy.argoSpec":{"properties":{"destination":{"$ref":"#/components/schemas/deploy.argoDestination","description":"Destination is which cluster and namespace it lands in. Zero-valued on a CD\nrow: this projection reports CD's source, not its destination."},"project":{"description":"Project is the AppProject this application is grouped and filtered under. For\nan App CR it is the app.kubernetes.io/part-of label — the IAM project name —\nfalling back to \"default\" when the CR carries no such label.","type":"string"},"source":{"$ref":"#/components/schemas/deploy.argoSource","description":"Source is where the desired state is declared."}},"type":"object"},"deploy.argoStatus":{"properties":{"health":{"$ref":"#/components/schemas/deploy.argoHealth","description":"Health is the application's reconciled health."},"reconciledAt":{"description":"ReconciledAt is when the desired state was last compared against the cluster,\nRFC 3339. Empty for an App CR — the projection derives its verdict at read\ntime and nothing records a comparison — and CD's own status.reconciledAt for\na CD row.","type":"string"},"resources":{"description":"Resources are the objects the application owns. EMPTY on the list — filling\nit would walk the cluster once per row — and populated only by the read of\nONE application, which is what makes that the detail view.","items":{"$ref":"#/components/schemas/deploy.argoResourceStatus"},"type":"array"},"summary":{"$ref":"#/components/schemas/deploy.argoSummary","description":"Summary is the small aggregate the list column renders: the images."},"sync":{"$ref":"#/components/schemas/deploy.argoSyncStatus","description":"Sync is the declared-versus-running verdict and what it was reached against."}},"type":"object"},"deploy.argoSummary":{"properties":{"images":{"description":"Images are the container images the application runs. One entry for an App\nCR, built from its spec.image as \"repository:tag\" — the bare repository when\nit declares no tag, and absent when it declares neither. Absent on a CD row,\nwhich tracks commits rather than images.","items":{"type":"string"},"type":"array"}},"type":"object"},"deploy.argoSyncStatus":{"properties":{"revision":{"description":"Revision is what Status was reached against. For an App CR that is the\ndeclared IMAGE TAG, not a commit — the CR is image-pinned. For a CD row it is\nthe commit CD last applied.","type":"string"},"status":{"description":"Status is the ArgoCD sync vocabulary, Capitalized: Synced, OutOfSync or\nUnknown. For an App CR it compares the tag the CR DECLARES against the tag\nthe cluster's Deployment is RUNNING — equal is Synced, both known and\ndifferent is OutOfSync, either unknown is Unknown. For a CD row it is CD's\nown git-versus-cluster verdict.","type":"string"}},"type":"object"},"deploy.argoSyncWindows":{"properties":{"activeWindows":{"description":"ActiveWindows are the sync windows in force right now. Always null: this\nplatform declares none, so nothing is ever in force.","items":{},"type":"array"},"assignedWindows":{"description":"AssignedWindows are the windows configured for this application at all,\nwhether or not currently in force. Always null, for the same reason.","items":{},"type":"array"},"canSync":{"description":"CanSync is whether a sync would be permitted at this moment. Always true —\nwith no windows there is nothing to deny it. A caller must not read this as\n\"a sync will succeed\"; it only means no window is blocking one.","type":"boolean"}},"type":"object"},"deploy.argoTree":{"properties":{"hosts":{"description":"Hosts is ArgoCD's per-node machine inventory. Always empty: this plane\nprojects applications and serves no cluster-node view.","items":{},"type":"array"},"nodes":{"description":"Nodes is the FLAT node list, root first: the App CR, then the objects the\noperator owns, then their ReplicaSets and Pods. The hierarchy is in\nParentRefs, not in the ordering.","items":{"$ref":"#/components/schemas/deploy.argoNode"},"type":"array"},"orphanedNodes":{"description":"OrphanedNodes are objects in the namespace belonging to no application.\nAlways empty: this walk reaches an object only THROUGH ownership from the App\nCR, so it can never hold one that is orphaned.","items":{"$ref":"#/components/schemas/deploy.argoNode"},"type":"array"}},"type":"object"},"deploy.deployHealth":{"properties":{"crd":{"description":"CRD reports whether the App custom resource is served and listable. Absent\nwhen the apiserver was unreachable, because then it is unknown rather than\nfalse.","type":"boolean"},"k8s":{"description":"K8s reports whether the Kubernetes API is reachable. Absent when the probe\ndid not get far enough to find out.","type":"boolean"},"service":{"description":"Service names the subsystem answering, so a probe response is attributable\nwhen several are collected together.","type":"string"},"status":{"description":"Status is `ok` when this deployment can serve the delivery plane, and\n`degraded` otherwise. It agrees with the HTTP status by construction — see\nStatusCode.","type":"string"}},"type":"object"},"deploy.sessionEnded":{"properties":{"loggedIn":{"description":"LoggedIn is always false — this is the answer to having just signed out, so\nit states the resulting session state rather than reporting the request's\noutcome. It is not omitempty: false is the whole answer.","type":"boolean"},"loginUrl":{"description":"LoginURL is where to sign in again. Always present, because a caller that\nhas just signed out is exactly the caller who needs it.","type":"string"}},"type":"object"},"deploy.sessionUser":{"properties":{"groups":{"description":"Groups is the caller's group list, always empty here: this console\nauthorizes on the platform SuperAdmin fact alone, not on argocd RBAC groups.\nAbsent for an anonymous caller.","items":{"type":"string"},"type":"array"},"iss":{"description":"Iss is the token issuer as the SPA expects to see it — the literal \"argocd\",\nso the UI never triggers an SSO redirect of its own. Absent for an anonymous\ncaller.","type":"string"},"loggedIn":{"description":"LoggedIn reports whether this browser holds a session this console accepts.","type":"boolean"},"loginUrl":{"description":"LoginURL is where an anonymous caller signs in. Absent once signed in.","type":"string"},"logoutUrl":{"description":"LogoutURL is where a signed-in caller ends the session. Absent when anonymous.","type":"string"},"username":{"description":"Username is the validated principal's user ID — the opaque gateway id, which\nis what argocd's UI renders as the signed-in user here — or \"admin\" when the\nprincipal carries none. Absent when anonymous.","type":"string"}},"type":"object"},"destination.DestinationField":{"properties":{"example":{"description":"a sample value of the right shape (\"G-XXXXXXX\"), when one helps","type":"string"},"key":{"description":"the camelCase key on both the connect body and the stored config","type":"string"},"label":{"description":"human label for the console card's input","type":"string"},"required":{"description":"when true, a connect that leaves it empty is refused 400","type":"boolean"}},"type":"object"},"destination.DestinationStatus":{"properties":{"account":{"description":"Account is the operator's own label for the connected account, as supplied on\nconnect. Absent when unset.","type":"string"},"category":{"description":"groups the card: Analytics | Advertising","type":"string"},"config":{"additionalProperties":{"type":"string"},"description":"Config is the org's stored NON-SECRET configuration — the measurement/pixel\nids keyed by DestinationField.Key. A secret is never in here; secrets live in\nKMS and only their names are published, in Secrets.","type":"object"},"connected":{"description":"Connected is true when this org has a stored row for the platform — it has\nbeen configured here at least once. It says nothing about whether a\ncredential still resolves; that is Live.","type":"boolean"},"enabled":{"description":"Enabled is whether the fan-out forwards to this destination. False on a\ndestination that is connected but paused, and on one never connected.","type":"boolean"},"fields":{"description":"Fields are the non-secret inputs this platform needs, which the console card\nrenders and the connect body fills.","items":{"$ref":"#/components/schemas/destination.DestinationField"},"type":"array"},"live":{"description":"Live is whether a credential resolves RIGHT NOW: a KMS-sealed secret for this\norg, else the integrations connection named by the platform's Fallback, else\nno credential needed at all (a public-ingest sink like Analytics). False on a\nconnected destination whose secret has gone missing — Connected \u0026\u0026 !Live is\nexactly the \"reconnect me\" state.","type":"boolean"},"name":{"description":"the platform's display name (\"Google Analytics 4\")","type":"string"},"pixel":{"description":"Pixel is whether the hosted tag can inject a browser pixel for this platform,\nso a console offers a per-SITE pixel input for exactly these. False means the\nplatform receives conversions server-side only, and an input would promise an\ninjection that never happens. Derived from the tag's own map (event.BrowserTags),\nnever restated — a second list is how a console offers a pixel nothing fires.","type":"boolean"},"platform":{"description":"the platform slug, and the path segment every route addresses it by","type":"string"},"secrets":{"description":"Secrets are the KMS secret NAMES this platform custodies for the org — names\nonly, never values. The connect body accepts each under its camelCase form.","items":{"type":"string"},"type":"array"}},"type":"object"},"destination.destinationDisconnected":{"properties":{"disconnected":{"description":"Disconnected is true when the credentials and the row are gone.","type":"boolean"}},"type":"object"},"destination.destinationList":{"properties":{"destinations":{"description":"Destinations is one card per registered platform, in slug order.","items":{"$ref":"#/components/schemas/destination.DestinationStatus"},"type":"array"}},"type":"object"},"destination.destinationTest":{"properties":{"error":{"description":"Error is the platform's rejection, present only on a failed send.","type":"string"},"message":{"description":"Message is the platform's own note about the send, present only on success.","type":"string"},"ok":{"description":"OK is true when the platform accepted the synthetic event.","type":"boolean"},"sent":{"description":"Sent is how many events the platform accepted, present only on success.","format":"int64","type":"integer"}},"type":"object"},"domain.Contacts":{"properties":{"admin":{"$ref":"#/components/schemas/domain.Registrant","description":"who administers it"},"billing":{"$ref":"#/components/schemas/domain.Registrant","description":"who is reached about payment"},"registrant":{"$ref":"#/components/schemas/domain.Registrant","description":"who owns the domain"},"tech":{"$ref":"#/components/schemas/domain.Registrant","description":"who is reached about technical matters"}},"type":"object"},"domain.Holding":{"properties":{"costCents":{"description":"wholesale cost","format":"int64","type":"integer"},"domain":{"description":"the name owned","type":"string"},"expiresAt":{"description":"when the registration lapses, RFC3339","type":"string"},"nameservers":{"description":"the authoritative nameservers the name points at","items":{"type":"string"},"type":"array"},"order":{"description":"registrar order id","format":"int64","type":"integer"},"org":{"description":"the org that owns the domain","type":"string"},"priceCents":{"description":"what the customer paid (sell)","format":"int64","type":"integer"},"registeredAt":{"description":"unix seconds","format":"int64","type":"integer"}},"type":"object"},"domain.Offer":{"properties":{"available":{"description":"whether it can be bought right now","type":"boolean"},"currency":{"description":"the currency both prices are in","type":"string"},"domain":{"description":"the name this quote prices","type":"string"},"premium":{"description":"whether the registry prices it above the standard rate","type":"boolean"},"priceCents":{"description":"sell (first-term registration)","format":"int64","type":"integer"},"renewalPriceCents":{"description":"sell (renewal)","format":"int64","type":"integer"},"tld":{"description":"the top-level domain the name sits under","type":"string"}},"type":"object"},"domain.RegisterResult":{"properties":{"quote":{"$ref":"#/components/schemas/domain.Offer","description":"the price it was bought at"},"record":{"$ref":"#/components/schemas/domain.Holding","description":"the ownership row this purchase issued"}},"type":"object"},"domain.Registrant":{"properties":{"address1":{"description":"street address","type":"string"},"address2":{"description":"second address line","type":"string"},"city":{"description":"city or locality","type":"string"},"companyName":{"description":"the organisation the contact acts for","type":"string"},"country":{"description":"ISO-3166 alpha-2, e.g. \"US\"","type":"string"},"email":{"description":"where WHOIS correspondence is sent","type":"string"},"fax":{"description":"fax number, in the same form as phone","type":"string"},"firstName":{"description":"the contact's given name","type":"string"},"lastName":{"description":"the contact's family name","type":"string"},"phone":{"description":"+NN.NNNNNNN","type":"string"},"state":{"description":"state, province or region","type":"string"},"zip":{"description":"postal code","type":"string"}},"type":"object"},"domain.RenewResult":{"properties":{"paidCents":{"description":"what this renewal cost, in cents","format":"int64","type":"integer"},"record":{"$ref":"#/components/schemas/domain.Holding","description":"the ownership row with its new expiry"}},"type":"object"},"domain.holdings":{"properties":{"domains":{"description":"Domains is the caller org's domains, newest registration first.","items":{"$ref":"#/components/schemas/domain.Holding"},"type":"array"}},"type":"object"},"domain.order":{"properties":{"contacts":{"$ref":"#/components/schemas/domain.Contacts","description":"Contacts is the WHOIS contact set. Omit it and the registrar uses the\nreseller account's default contacts."},"domain":{"description":"Domain is the name to buy. It is required.","type":"string"},"years":{"description":"Years is the term to buy, defaulting to 1.","format":"int64","type":"integer"}},"required":["domain"],"type":"object"},"domain.quoteList":{"properties":{"results":{"description":"Results is one quote per name, priced RETAIL — this deployment's markup is\nalready applied and the wholesale cost is never on the wire.","items":{"$ref":"#/components/schemas/domain.Offer"},"type":"array"}},"type":"object"},"domain.reachability":{"properties":{"configured":{"description":"Configured is whether the wholesale credentials are present at all.","type":"boolean"},"env":{"description":"Env is the registrar environment. It is the fact that decides whether money\nmoves: only \"prod\" reaches the live, billable registrar — anything else,\nincluding unset, is the sandbox.","type":"string"},"error":{"description":"Error is the blocker, so an operator reads it instead of guessing at it.","type":"string"},"reachable":{"description":"Reachable is whether the registrar accepted those credentials on a live call\nmade while the caller waited.","type":"boolean"},"registrar":{"description":"Registrar names the wholesale registrar behind it.","type":"string"},"service":{"description":"Service names the subsystem answering.","type":"string"},"status":{"description":"Status is \"ok\" when a live call succeeded, else \"degraded\".","type":"string"}},"type":"object"},"domain.renewReq":{"properties":{"domain":{"description":"Domain is the name to extend. It is required, and the caller's org must hold it.","type":"string"},"years":{"description":"Years is how much longer to hold it, defaulting to 1.","format":"int64","type":"integer"}},"required":["domain"],"type":"object"},"domain.transferReq":{"properties":{"authCode":{"description":"AuthCode is the transfer authorization the losing registrar issued. It is\nrequired.","type":"string"},"domain":{"description":"Domain is the name to move in. It is required.","type":"string"},"years":{"description":"Years is the term to buy on transfer, defaulting to 1.","format":"int64","type":"integer"}},"required":["domain","authCode"],"type":"object"},"email.ClassificationCheck":{"properties":{"disposable":{"description":"Disposable reports whether the domain belongs to a temporary or throwaway provider.","type":"boolean"},"free":{"description":"Free reports whether the domain belongs to a free consumer webmail provider.","type":"boolean"},"reason":{"description":"Reason describes the failure or skip reason when Status is not pass.","type":"string"},"role":{"description":"Role reports whether the address is a generic role or distribution account.","type":"boolean"},"status":{"description":"Status reports the check outcome: pass, fail, unknown, or skipped.","type":"string"}},"type":"object"},"email.Dispatch":{"properties":{"messages":{"description":"Messages is one message per recipient that was sent, each with its own\nunsubscribe link; a message the provider refused is here with status failed.","items":{"$ref":"#/components/schemas/email.MessageRecord"},"type":"array"},"refused":{"description":"Refused is every recipient the suppression check refused. Nothing was sent\nto them.","items":{"$ref":"#/components/schemas/email.Refused"},"type":"array"}},"type":"object"},"email.DomainCheck":{"properties":{"reason":{"description":"Reason describes the failure or skip reason when Status is not pass.","type":"string"},"status":{"description":"Status reports the check outcome: pass, fail, unknown, or skipped.","type":"string"}},"type":"object"},"email.ListMessagesResult":{"properties":{"messages":{"description":"Messages lists the stored transactional emails.","items":{"$ref":"#/components/schemas/email.MessageRecord"},"type":"array"},"total":{"description":"Total is the count of returned messages.","format":"int64","type":"integer"}},"type":"object"},"email.MXCheck":{"properties":{"reason":{"description":"Reason describes the failure or skip reason when Status is not pass.","type":"string"},"records":{"description":"Records lists the discovered mail exchanger hostnames.","items":{"type":"string"},"type":"array"},"status":{"description":"Status reports the check outcome: pass, fail, unknown, or skipped.","type":"string"}},"type":"object"},"email.MessageRecord":{"properties":{"created_at":{"description":"CreatedAt is the timestamp when the message was accepted for delivery.","format":"date-time","type":"string"},"error":{"description":"Error carries the failure details when Status is failed.","type":"string"},"from":{"description":"From is the sender email address used for delivery.","type":"string"},"html":{"description":"HTML is the HTML body.","type":"string"},"id":{"description":"ID is the unique message identifier minted by the delivery service.","type":"string"},"idempotency_key":{"description":"IdempotencyKey records the key used to deduplicate dispatch retries.","type":"string"},"org":{"description":"Org is the organization owning this message.","type":"string"},"provider":{"description":"Provider is the delivery provider name that executed the dispatch.","type":"string"},"provider_id":{"description":"ProviderID is the provider's own id for the message, which its delivery\nevents name it by; empty for a provider that answers none.","type":"string"},"status":{"description":"Status reports delivery status: queued, sent, delivered, or failed.","type":"string"},"subject":{"description":"Subject is the message subject line.","type":"string"},"text":{"description":"Text is the plain text body.","type":"string"},"to":{"description":"To lists recipient destination addresses.","items":{"type":"string"},"type":"array"}},"type":"object"},"email.Refused":{"properties":{"address":{"description":"Address is the recipient.","type":"string"},"reason":{"description":"Reason is why: unsubscribed, company unsubscribed (the address's domain\nopted out of the org's mail) or blocklisted (the platform's list).","type":"string"},"status":{"description":"Status is 422: the address may not be mailed.","format":"int64","type":"integer"}},"type":"object"},"email.SESDNSRecord":{"properties":{"host":{"description":"Host is the DNS record host or subdomain name.","type":"string"},"priority":{"description":"Priority is the MX priority when Type is MX.","format":"int64","type":"integer"},"purpose":{"description":"Purpose describes the role of the DNS record (e.g. DKIM, MAIL FROM MX, MAIL FROM SPF, DMARC).","type":"string"},"type":{"description":"Type is the DNS record type (CNAME, MX, TXT).","type":"string"},"value":{"description":"Value is the DNS record target or text value.","type":"string"},"verified":{"description":"Verified reports whether the DNS record is verified for the sending identity.","type":"boolean"}},"type":"object"},"email.SESStatusResult":{"properties":{"active_provider":{"description":"ActiveProvider names the active primary email provider resolved for the organization.","type":"string"},"configuration_set":{"description":"ConfigurationSet is the Amazon SES v2 Configuration Set name used for open/click/bounce tracking.","type":"string"},"configured":{"description":"Configured reports whether Amazon SES credentials are configured for the organization.","type":"boolean"},"dns_records":{"description":"DNSRecords lists the Easy DKIM, SPF, MX, and DMARC records for the sending domain.","items":{"$ref":"#/components/schemas/email.SESDNSRecord"},"type":"array"},"domain":{"description":"Domain is the sending domain inspected.","type":"string"},"from_email":{"description":"FromEmail is the default verified sender address.","type":"string"},"from_name":{"description":"FromName is the default sender display name.","type":"string"},"mail_from_domain":{"description":"MailFromDomain is the custom MAIL FROM subdomain (bounce.\u003cdomain\u003e).","type":"string"},"max_24_hour_send":{"description":"Max24HourSend is the 24-hour sending quota for the SES account.","format":"int64","type":"integer"},"max_send_rate":{"description":"MaxSendRate is the maximum messages per second allowed by SES.","format":"int64","type":"integer"},"org":{"description":"Org is the organization identifier.","type":"string"},"region":{"description":"Region is the configured Amazon SES AWS region (defaults to us-east-1).","type":"string"},"sandbox":{"description":"Sandbox reports whether the account is in SES sandbox mode.","type":"boolean"},"sent_last_24_hours":{"description":"SentLast24Hours is the count of messages dispatched in the trailing 24 hours.","format":"int64","type":"integer"}},"type":"object"},"email.SMTPCheck":{"properties":{"catch_all":{"description":"CatchAll reports whether the host accepts all recipient addresses.","type":"boolean"},"deliverable":{"description":"Deliverable reports whether the mailbox accepted the test recipient address.","type":"boolean"},"disabled":{"description":"Disabled reports whether the recipient mailbox is disabled or inactive.","type":"boolean"},"full_inbox":{"description":"FullInbox reports whether the recipient mailbox is over quota.","type":"boolean"},"host_exists":{"description":"HostExists reports whether the destination mail server host exists and responded.","type":"boolean"},"reason":{"description":"Reason describes the failure or skip reason when Status is not pass.","type":"string"},"status":{"description":"Status reports the check outcome: pass, fail, unknown, or skipped.","type":"string"}},"type":"object"},"email.SendGridStatusResult":{"properties":{"active_provider":{"description":"ActiveProvider is the highest-priority email provider currently configured for this organization.","type":"string"},"asm_group_id":{"description":"ASMGroupID is the optional SendGrid suppression group ID.","type":"string"},"configured":{"description":"Configured reports whether SendGrid outreach credentials are set in KMS for this organization.","type":"boolean"},"dns_records":{"description":"DNSRecords lists the required SendGrid Domain Authentication CNAME, Link Branding, SPF, and DMARC DNS records.","items":{"$ref":"#/components/schemas/email.SESDNSRecord"},"type":"array"},"domain":{"description":"Domain is the sending domain used for SendGrid Domain Authentication and DMARC.","type":"string"},"from_email":{"description":"FromEmail is the configured SendGrid outreach sender email address.","type":"string"},"from_name":{"description":"FromName is the configured SendGrid outreach sender display name.","type":"string"},"ip_pool":{"description":"IPPool is the dedicated SendGrid IP pool name used to isolate cold outreach reputation.","type":"string"},"org":{"description":"Org is the organization identifier.","type":"string"},"reply_to":{"description":"ReplyTo is the configured Reply-To address for outreach replies.","type":"string"},"sent_last_24_hours":{"description":"SentLast24Hours is the count of emails sent by this organization in the past 24 hours.","format":"int64","type":"integer"},"separate_from_twilio_notify":{"description":"SeparateFromTwilioNotify confirms that SendGrid outreach uses its own dedicated API key, sender identity, and IP pool distinct from standard Twilio transactional notifications.","type":"boolean"}},"type":"object"},"email.SendMessageInput":{"properties":{"body":{"description":"Body is an alias for Text for backward compatibility.","type":"string"},"from":{"description":"From is the sender address. If empty, the org's provider default is used.","type":"string"},"headers":{"additionalProperties":{"type":"string"},"description":"Headers provides optional custom MIME headers.","type":"object"},"html":{"description":"HTML is the HTML body.","type":"string"},"idempotency_key":{"description":"IdempotencyKey prevents duplicate message dispatches on network retries.","type":"string"},"provider":{"description":"Provider optionally pins a provider (e.g. \"mail\", \"twilio_email\").","type":"string"},"subject":{"description":"Subject is the message subject.","type":"string"},"sync":{"description":"Sync is accepted for backwards compatibility with notify sends.","type":"string"},"template_id":{"description":"TemplateID optionally references a built-in template.","type":"string"},"template_vars":{"description":"TemplateVars carries variables for template rendering."},"text":{"description":"Text is the plain text body.","type":"string"},"to":{"description":"To lists destination recipient addresses.","items":{"type":"string"},"type":"array"}},"type":"object"},"email.Suggestion":{"properties":{"email":{"description":"Email is the suggested alternative address.","type":"string"},"reason":{"description":"Reason describes why the suggestion was made (e.g. domain_typo).","type":"string"}},"type":"object"},"email.SyntaxCheck":{"properties":{"domain":{"description":"Domain is the domain-part of the email address.","type":"string"},"reason":{"description":"Reason describes the failure or skip reason when Status is not pass.","type":"string"},"status":{"description":"Status reports the check outcome: pass, fail, unknown, or skipped.","type":"string"},"username":{"description":"Username is the local-part of the email address.","type":"string"}},"type":"object"},"email.VerificationChecks":{"properties":{"classification":{"$ref":"#/components/schemas/email.ClassificationCheck","description":"Classification details account attributes (disposable, free, role)."},"domain":{"$ref":"#/components/schemas/email.DomainCheck","description":"Domain details DNS domain host resolution."},"mx":{"$ref":"#/components/schemas/email.MXCheck","description":"MX details DNS mail exchanger lookup."},"smtp":{"$ref":"#/components/schemas/email.SMTPCheck","description":"SMTP details explicit mailbox probing."},"syntax":{"$ref":"#/components/schemas/email.SyntaxCheck","description":"Syntax details RFC 5322 structure verification."}},"type":"object"},"email.VerificationInput":{"properties":{"checks":{"description":"Checks explicitly selects which checks to run.\nDefaults to [\"syntax\", \"domain\", \"mx\", \"classification\"].","items":{"type":"string"},"type":"array"},"email":{"description":"Email is the address to evaluate.","type":"string"},"from_email":{"description":"FromEmail sets sender used in MAIL FROM for SMTP probe when explicitly enabled.","type":"string"},"hello_name":{"description":"HelloName sets domain used in EHLO for SMTP probe when explicitly enabled.","type":"string"},"proxy_uri":{"description":"ProxyURI sets optional proxy for network lookups.","type":"string"},"suggestions":{"description":"Suggestions requests domain typo suggestions without altering the original email.","type":"boolean"}},"type":"object"},"email.VerificationResult":{"properties":{"checks":{"$ref":"#/components/schemas/email.VerificationChecks","description":"Checks contains the outcomes of all requested checks."},"email":{"description":"Email is the original submitted email address.","type":"string"},"suggestions":{"description":"Suggestions lists potential corrections when requested.","items":{"$ref":"#/components/schemas/email.Suggestion"},"type":"array"}},"type":"object"},"engine.engineStatus":{"properties":{"reachable":{"description":"Reachable is true when the engine answered its health probe.","type":"boolean"},"revision":{"description":"Revision is the engine build's git revision, present only when\nreachable (the server's own build identity — it publishes no semver).","type":"string"}},"type":"object"},"entitlement.entitlementsView":{"properties":{"enabled":{"description":"Enabled is the org's turned-on product ids, sorted. Always an array, never null.","items":{"type":"string"},"type":"array"}},"type":"object"},"entitlement.mutateReq":{"properties":{"add":{"description":"Add is the product ids to turn ON. Each must already be an ACTIVE entitlement\nof the org's plan, unless the caller is a platform super admin.","items":{"type":"string"},"type":"array"},"remove":{"description":"Remove is the product ids to turn OFF. Disabling is never gated.","items":{"type":"string"},"type":"array"}},"type":"object"},"entitlement.projectionView":{"properties":{"apps":{"additionalProperties":{"type":"boolean"},"description":"Apps says, per console app, whether the org may open it. The SAME six keys are\nalways present (studio, bot, world, platform, team, admin), so a client maps\nover it unconditionally; a key is false both when the plan does not grant the\napp and when commerce could not be reached, because a read that decides what to\nSHOW fails to LOCKED rather than to an error.","type":"object"},"tier":{"description":"Tier is the plan slug commerce resolved for the org, or \"\" when the org has no\nactive licensing subscription — which the console treats as its free default.","type":"string"}},"type":"object"},"environment.Environment":{"properties":{"install":{"description":"Install is the shell a run executes in its fresh checkout before the agent\nstarts, from the repository root. Empty installs nothing.","type":"string"},"proposal":{"$ref":"#/components/schemas/environment.Proposal","description":"Proposal is what the last setup run found, until it is saved or replaced."},"repo":{"description":"Repo is the codebase: a repository's name in the caller's org.","type":"string"},"secrets":{"description":"Secrets are the names set on this codebase, each exported to the run's\ncommands under that name. Values are never answered.","items":{"type":"string"},"type":"array"},"session":{"description":"Session is the setup run that produced the proposal, when there is one.","type":"string"},"start":{"description":"Start is the one command a run leaves running in the background once the\ninstall has finished — a dev server, a database. Empty starts nothing.","type":"string"},"state":{"description":"State is `none` when nothing is saved or proposed, `proposed` when a setup\nrun's answer is waiting to be reviewed, and `ready` otherwise.","type":"string"},"updatedAt":{"description":"UpdatedAt is when this environment last changed, RFC 3339. Absent for none.","type":"string"}},"type":"object"},"environment.Proposal":{"properties":{"install":{"description":"Install is the install script the agent checked.","type":"string"},"note":{"description":"Note is what the agent found and checked, in its own words.","type":"string"},"secrets":{"description":"Secrets are the environment variables the agent found the codebase reads.\nSome may not be set yet; setting them is a person's act, not the agent's.","items":{"type":"string"},"type":"array"},"start":{"description":"Start is the start command the agent checked, or empty.","type":"string"}},"type":"object"},"environment.envList":{"properties":{"data":{"description":"Data is one entry per codebase that has an environment, by name.","items":{"$ref":"#/components/schemas/environment.Environment"},"type":"array"}},"type":"object"},"environment.envSave":{"properties":{"install":{"description":"Install is run in every fresh checkout before the agent starts, from the\nrepository root, and must be non-interactive. Empty installs nothing.","type":"string"},"repo":{"description":"Repo is the repository's name in the caller's org.","type":"string"},"start":{"description":"Start is left running in the background after the install. Empty starts\nnothing.","type":"string"}},"type":"object"},"environment.envSecret":{"properties":{"name":{"description":"Name is the environment variable the run exports the value under.","type":"string"},"repo":{"description":"Repo is the repository's name in the caller's org.","type":"string"},"value":{"description":"Value is sealed in KMS and never answered, logged or echoed. It is never\nread from a query string, because a URL is logged in more places than a\nbody is.","type":"string"}},"type":"object"},"esign.esignCompletion":{"properties":{"documentStatus":{"description":"DocumentStatus is COMPLETED when this was the last signature and the document\nsealed here, PENDING while others have still to sign.","type":"string"},"recipientId":{"description":"RecipientID is the recipient who finished.","type":"string"},"sealed":{"description":"Sealed is whether the document sealed on this call — the field values\nrendered onto the PDF and a real x509 PKCS#7 signature applied.","type":"boolean"}},"type":"object"},"esign.esignDocument":{"properties":{"completedAt":{"description":"CompletedAt is when the document sealed, in unix milliseconds; null until it\ndoes.","format":"int64","type":"integer"},"createdAt":{"description":"CreatedAt is when the document was uploaded, in unix milliseconds.","format":"int64","type":"integer"},"externalId":{"description":"ExternalID is the caller's own identifier for this document, echoed back as\nit was given; null when none was.","type":"string"},"fields":{"description":"Fields is every field on the document, ordered by page and then by when it\nwas placed.","items":{"$ref":"#/components/schemas/esign.esignField"},"type":"array"},"id":{"description":"ID is the document id.","type":"string"},"message":{"description":"Message is the covering message stored with the document; null when none was\ngiven. Nothing in this surface sends it.","type":"string"},"recipients":{"description":"Recipients is everyone on the document, ordered by signing order and then by\nwhen they were added — which is also the order a SEQUENTIAL document enforces.","items":{"$ref":"#/components/schemas/esign.esignRecipient"},"type":"array"},"signingOrder":{"description":"SigningOrder is PARALLEL or SEQUENTIAL, fixed when the document was created.","type":"string"},"source":{"description":"Source is how the document came to exist. It is DOCUMENT for everything this\nsurface creates.","type":"string"},"status":{"description":"Status is DRAFT while recipients and fields may still be added, PENDING once\nit has gone out, then COMPLETED when every signer has finished or REJECTED if\nany one of them declined.","type":"string"},"subject":{"description":"Subject is the covering subject line stored with the document; null when none\nwas given.","type":"string"},"title":{"description":"Title is the document's name, and the stem of the download filename.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the document last changed, in unix milliseconds.","format":"int64","type":"integer"}},"type":"object"},"esign.esignDocuments":{"properties":{"documents":{"description":"Documents is the caller org's documents, newest first, capped at 200. There\nis no paging, so read it as the recent window rather than a complete export.","items":{"$ref":"#/components/schemas/esign.esignDocument"},"type":"array"}},"type":"object"},"esign.esignEvent":{"properties":{"createdAt":{"description":"CreatedAt is when it happened, in unix milliseconds.","format":"int64","type":"integer"},"data":{"description":"Data is the event's own detail, whose shape depends on the type — the field\nand recipient a signature was inserted for, the reason a document was\nrejected. Null when the event carried none."},"email":{"description":"Email is the email of whoever caused it, null for an event with no actor —\nthe sender's own calls are recorded without one.","type":"string"},"id":{"description":"ID is the entry id.","type":"string"},"name":{"description":"Name is the name of whoever caused it, null when it was not recorded.","type":"string"},"type":{"description":"Type is what happened: DOCUMENT_CREATED, RECIPIENT_CREATED, FIELD_CREATED,\nDOCUMENT_SENT, DOCUMENT_OPENED, DOCUMENT_FIELD_INSERTED,\nDOCUMENT_RECIPIENT_COMPLETED, DOCUMENT_RECIPIENT_REJECTED or\nDOCUMENT_COMPLETED.","type":"string"}},"type":"object"},"esign.esignField":{"properties":{"customText":{"description":"CustomText is the value a non-signature field was filled with, empty until it\nis. A signature's value is not here: it is stored separately and rendered\nonto the page at sealing.","type":"string"},"fieldMeta":{"description":"FieldMeta is the caller's own metadata for this field, stored verbatim at\nplacement and never interpreted. Null when none was supplied."},"height":{"description":"Height is the field's height, -1 when the renderer is to choose one.","format":"double","type":"number"},"id":{"description":"ID is the field id.","type":"string"},"inserted":{"description":"Inserted is whether this field has been filled in.","type":"boolean"},"page":{"description":"Page is the 1-based page the field sits on.","format":"double","type":"number"},"positionX":{"description":"PositionX is the field's horizontal position on that page.","format":"double","type":"number"},"positionY":{"description":"PositionY is the field's vertical position on that page.","format":"double","type":"number"},"recipientId":{"description":"RecipientID is who must fill this field. It is absent on a signer's own view\nof a document, where every field returned is already theirs.","type":"string"},"type":{"description":"Type is what the field collects — SIGNATURE, DATE, NAME, EMAIL, TEXT and the\nrest.","type":"string"},"width":{"description":"Width is the field's width, -1 when the renderer is to choose one.","format":"double","type":"number"}},"type":"object"},"esign.esignFieldIn":{"properties":{"fieldMeta":{"description":"FieldMeta is your own metadata for this field — a label, a placeholder, a\nrequired flag — stored verbatim and handed back on every read of the\ndocument. Any JSON, and esign never interprets it."},"height":{"description":"Height is the field's height, defaulting to -1, which means the renderer\nchooses one when the document is sealed."},"page":{"description":"Page is the 1-based page the field sits on, defaulting to 1."},"positionX":{"description":"PositionX is the field's horizontal position on that page, defaulting to 0."},"positionY":{"description":"PositionY is the field's vertical position on that page, defaulting to 0."},"recipientId":{"description":"RecipientID is who must fill this field. Required, and it must belong to this\ndocument — a recipient from elsewhere is refused rather than silently\naccepted."},"type":{"description":"Type is what the field collects: SIGNATURE, FREE_SIGNATURE, INITIALS, NAME,\nEMAIL, DATE, TEXT, NUMBER, RADIO, CHECKBOX or DROPDOWN. Required, and\nanything else is refused."},"width":{"description":"Width is the field's width, defaulting to -1, which means the renderer\nchooses one when the document is sealed."}},"type":"object"},"esign.esignHealth":{"properties":{"service":{"description":"Service names the subsystem that answered, so a probe reading several looks\nthe same on each.","type":"string"},"status":{"description":"Status is ok whenever the subsystem is mounted. It is never anything else:\nthis route is registered before the document host is built, so it is\nreachability and not a promise that documents can be stored.","type":"string"}},"type":"object"},"esign.esignInsertion":{"properties":{"fieldId":{"description":"FieldID is the field that was filled.","type":"string"},"inserted":{"description":"Inserted is true — the field now holds a value. Filling every field still\nleaves the document pending until the completion call.","type":"boolean"}},"type":"object"},"esign.esignInvite":{"properties":{"email":{"description":"Email is the address the invitation is for, lower-cased.","type":"string"},"id":{"description":"ID is the new recipient's id, which is what a field is placed against.","type":"string"},"name":{"description":"Name is the recipient's display name, empty when none was given.","type":"string"},"role":{"description":"Role is the role they were recorded with — SIGNER unless another was asked\nfor.","type":"string"},"token":{"description":"Token is the crypto-random signing capability for this recipient. It is the\nentire credential their signing endpoint accepts, so treat it as a secret\nand hand it only to them: the signing link is built from it.","type":"string"}},"type":"object"},"esign.esignLink":{"properties":{"email":{"description":"Email is the address this link is meant for.","type":"string"},"recipientId":{"description":"RecipientID is the recipient the link identifies.","type":"string"},"role":{"description":"Role is their role — only a SIGNER or an APPROVER gets a link, because only\nthey are asked to act.","type":"string"},"signingPath":{"description":"SigningPath is the tail of the address to send them, relative to wherever the\nsigning page is served.","type":"string"},"token":{"description":"Token is the crypto-random signing capability. It is the entire credential,\nso treat it as a secret and give each one only to the recipient it names.","type":"string"}},"type":"object"},"esign.esignLinks":{"properties":{"id":{"description":"ID is the document that went out.","type":"string"},"recipients":{"description":"Recipients is one link per signing recipient. Nothing is emailed by this\ncall; delivering the links is the caller's.","items":{"$ref":"#/components/schemas/esign.esignLink"},"type":"array"},"status":{"description":"Status is PENDING — the state a sent document is in until every signer has\nfinished.","type":"string"}},"type":"object"},"esign.esignPDF":{"properties":{"filename":{"description":"Filename is the name to save it under, built from the title and marked\n_signed once it is sealed.","type":"string"},"id":{"description":"ID is the document this PDF was rendered from.","type":"string"},"pdfBase64":{"description":"PdfBase64 is the PDF itself, base64-encoded. There is one field either way,\nso Sealed is what tells you which artifact you are holding.","type":"string"},"sealed":{"description":"Sealed is whether this is the SEALED artifact — the field values rendered\nonto the page and a real x509 PKCS#7 signature applied — rather than the\noriginal upload.","type":"boolean"},"status":{"description":"Status is the document's state at the moment it was read.","type":"string"}},"type":"object"},"esign.esignPlacement":{"properties":{"id":{"description":"ID is the new field's id.","type":"string"},"page":{"description":"Page is the page it was placed on.","format":"double","type":"number"},"recipientId":{"description":"RecipientID is who must fill it.","type":"string"},"type":{"description":"Type is what it collects.","type":"string"}},"type":"object"},"esign.esignRecipient":{"properties":{"email":{"description":"Email is where this recipient's signing link is meant to go, lower-cased.","type":"string"},"id":{"description":"ID is the recipient id, which is what a field is placed against.","type":"string"},"name":{"description":"Name is the recipient's display name, empty when none was given.","type":"string"},"readStatus":{"description":"ReadStatus is NOT_OPENED until they first open their link, then OPENED.","type":"string"},"rejectionReason":{"description":"RejectionReason is why they declined, null unless they did.","type":"string"},"role":{"description":"Role is SIGNER, CC, VIEWER, APPROVER or ASSISTANT. A document waits only for\nits SIGNERs and APPROVERs before it can seal.","type":"string"},"sendStatus":{"description":"SendStatus is NOT_SENT until the document goes out, then SENT. A CC recipient\nis SENT from the moment they are added.","type":"string"},"signedAt":{"description":"SignedAt is when they finished or declined, in unix milliseconds; null while\nneither has happened.","format":"int64","type":"integer"},"signingOrder":{"description":"SigningOrder is their position in a SEQUENTIAL document, null when they were\nadded without one. A PARALLEL document ignores it.","format":"double","type":"number"},"signingStatus":{"description":"SigningStatus is NOT_SIGNED, SIGNED or REJECTED. A CC recipient is SIGNED\nfrom the moment they are added, because they are never asked.","type":"string"}},"type":"object"},"esign.esignRecipientIn":{"properties":{"email":{"description":"Email is where the signing link is meant to go, lower-cased on the way in.\nRequired."},"name":{"description":"Name is the recipient's display name, also the fallback a NAME field is\nfilled with when they leave it blank. Optional."},"role":{"description":"Role is SIGNER (the default), CC, VIEWER, APPROVER or ASSISTANT; anything\nelse reads as SIGNER. A CC recipient is recorded as already complete, because\nthey are never asked to sign. SIGNER and APPROVER are the roles a document\nwaits for before it can seal."},"signingOrder":{"description":"SigningOrder is this recipient's position when the document is SEQUENTIAL —\nlower signs first, and ties fall back to the order they were added. Ignored\nby a PARALLEL document. Optional."}},"type":"object"},"esign.esignRejectIn":{"properties":{"reason":{"description":"Reason is why the signer is declining. Optional, stored, and written onto the\naudit trail with the rejection — it is what the sender sees."}},"type":"object"},"esign.esignRejection":{"properties":{"recipientId":{"description":"RecipientID is the recipient who declined.","type":"string"},"status":{"description":"Status is REJECTED — one declining signer ends the document for everyone, and\nthere is no route back.","type":"string"}},"type":"object"},"esign.esignSession":{"properties":{"document":{"$ref":"#/components/schemas/esign.esignState","description":"Document is what is being signed."},"fields":{"description":"Fields is only the fields this recipient must fill — never another party's,\nso the layout a signer sees cannot reveal what anyone else was asked for.","items":{"$ref":"#/components/schemas/esign.esignField"},"type":"array"},"pdfBase64":{"description":"PdfBase64 is the PDF to display, base64-encoded. Null when the document's\nstored bytes are missing.","type":"string"},"recipient":{"$ref":"#/components/schemas/esign.esignSigner","description":"Recipient is who the token says you are."}},"type":"object"},"esign.esignSigner":{"properties":{"email":{"description":"Email is the address the link was issued to.","type":"string"},"id":{"description":"ID is the recipient id.","type":"string"},"name":{"description":"Name is the display name recorded for them, empty when none was given.","type":"string"},"role":{"description":"Role is the role they were added with.","type":"string"},"signingStatus":{"description":"SigningStatus is NOT_SIGNED until they finish or decline.","type":"string"}},"type":"object"},"esign.esignState":{"properties":{"id":{"description":"ID is the document id.","type":"string"},"status":{"description":"Status is PENDING while it is out for signature.","type":"string"},"title":{"description":"Title is the document's name.","type":"string"}},"type":"object"},"esign.esignTrail":{"properties":{"documentId":{"description":"DocumentID is the document the trail belongs to.","type":"string"},"entries":{"description":"Entries is every recorded event in order, oldest first. It is append-only:\nnothing in this surface edits or removes an entry.","items":{"$ref":"#/components/schemas/esign.esignEvent"},"type":"array"}},"type":"object"},"esign.esignUploadIn":{"properties":{"externalId":{"description":"ExternalID is your own identifier for this document, stored and echoed back\nso a document here can be matched to a record in your system. Optional."},"message":{"description":"Message is the covering message carried with the document. Optional, and like\nthe subject it is stored rather than sent."},"pdfBase64":{"description":"PdfBase64 is the document itself, base64-encoded; a `data:` URL prefix is\naccepted and stripped. Required. The bytes go to object storage rather than\ninto the tenant database, and this ORIGINAL is kept under its own key so it\nsurvives sealing untouched."},"signingOrder":{"description":"SigningOrder chooses PARALLEL — the default, where everyone may sign at once\n— or SEQUENTIAL, where each signer waits for the ones ahead of them. Anything\nelse reads as PARALLEL, and the choice is fixed for the document's life."},"subject":{"description":"Subject is the covering subject line carried with the document. Optional, and\nnothing in this surface emails it — delivering the signing links is the\ncaller's."},"title":{"description":"Title is the document's name, shown to every recipient and used to build the\ndownload filename. Required — a request without one is refused and nothing is\nstored."}},"type":"object"},"esign.esignValueIn":{"properties":{"isBase64":{"description":"IsBase64 marks Value as drawn signature image bytes rather than a typed\nsignature. Only a signature field reads it, and a `data:` URL prefix is\nstripped."},"value":{"description":"Value is what goes in the field. A signature takes the drawn image bytes or a\ntyped name; a DATE, NAME or EMAIL field falls back to today, the recipient's\nname or their email when this is omitted; every other type requires it."}},"type":"object"},"eval.Board":{"properties":{"byModel":{"description":"the top models by spend","items":{"$ref":"#/components/schemas/eval.ModelStat"},"type":"array"},"latency":{"$ref":"#/components/schemas/eval.LatencyStat","description":"overall latency percentiles from the GenAI spans"},"other":{"$ref":"#/components/schemas/eval.ModelStat","description":"the long tail beyond the top models, folded into one row"},"range":{"$ref":"#/components/schemas/eval.BoardRange","description":"the window they were computed over, echoed back"},"scope":{"$ref":"#/components/schemas/eval.BoardScope","description":"whose numbers these are"},"series":{"description":"one gap-filled bucket per interval, so a chart never breaks","items":{"$ref":"#/components/schemas/eval.BoardPoint"},"type":"array"},"totals":{"$ref":"#/components/schemas/eval.BoardTotals","description":"the window's headline numbers"}},"type":"object"},"eval.BoardPoint":{"properties":{"costCents":{"description":"what this bucket cost, in cents","format":"int64","type":"integer"},"errors":{"description":"calls in this bucket that did not succeed","format":"int64","type":"integer"},"generations":{"description":"model calls in this bucket","format":"int64","type":"integer"},"t":{"description":"RFC3339 (UTC) bucket start","type":"string"},"totalTokens":{"description":"tokens in this bucket","format":"int64","type":"integer"}},"type":"object"},"eval.BoardRange":{"properties":{"end":{"description":"RFC3339 (UTC)","type":"string"},"interval":{"description":"hour | day","type":"string"},"range":{"description":"echoed label (24h | 7d | 30d | custom)","type":"string"},"start":{"description":"RFC3339 (UTC)","type":"string"}},"type":"object"},"eval.BoardScope":{"properties":{"allOrgs":{"description":"true when a platform admin is seeing every org at once","type":"boolean"},"org":{"description":"the org the board covers; \"\" when it covers all of them","type":"string"},"project":{"description":"the sub-scope within the org; \"\" is the whole org","type":"string"}},"type":"object"},"eval.BoardTotals":{"properties":{"completionTokens":{"description":"tokens the models answered with","format":"int64","type":"integer"},"costCents":{"description":"what the window cost, in cents","format":"int64","type":"integer"},"errors":{"description":"calls that did not succeed","format":"int64","type":"integer"},"generations":{"description":"how many model calls the window holds","format":"int64","type":"integer"},"models":{"description":"how many distinct models were called","format":"int64","type":"integer"},"promptTokens":{"description":"tokens sent to the models","format":"int64","type":"integer"},"successRate":{"description":"share of calls that succeeded, 0..1","format":"double","type":"number"},"totalTokens":{"description":"prompt plus completion","format":"int64","type":"integer"},"users":{"description":"how many distinct users called them","format":"int64","type":"integer"}},"type":"object"},"eval.LatencyStat":{"properties":{"available":{"description":"false when no GenAI spans carry timing; the percentiles are then null","type":"boolean"},"p50Ms":{"description":"median latency over the window","format":"double","type":"number"},"p95Ms":{"description":"95th-percentile latency","format":"double","type":"number"},"p99Ms":{"description":"99th-percentile latency","format":"double","type":"number"}},"type":"object"},"eval.ModelStat":{"properties":{"completionTokens":{"description":"tokens it answered with","format":"int64","type":"integer"},"costCents":{"description":"what this model cost, in cents","format":"int64","type":"integer"},"costPct":{"description":"share of total spend, 0..100","format":"double","type":"number"},"errorRate":{"description":"share of its calls that failed, 0..1","format":"double","type":"number"},"errors":{"description":"calls to it that did not succeed","format":"int64","type":"integer"},"model":{"description":"the model this row is about, or \"other\" for the fold","type":"string"},"modelCount":{"description":"\u003e0 only on the \"other\" fold","format":"int64","type":"integer"},"p50Ms":{"description":"median latency, null when no spans carry it","format":"double","type":"number"},"p95Ms":{"description":"95th-percentile latency, null when unknown","format":"double","type":"number"},"p99Ms":{"description":"99th-percentile latency, null when unknown","format":"double","type":"number"},"promptTokens":{"description":"tokens sent to it","format":"int64","type":"integer"},"provider":{"description":"who serves it","type":"string"},"requests":{"description":"calls to this model in the window","format":"int64","type":"integer"},"totalTokens":{"description":"prompt plus completion","format":"int64","type":"integer"}},"type":"object"},"eval.datasetList":{"properties":{"data":{"description":"Data is the caller org's datasets, newest first, bounded by limit.","items":{"$ref":"#/components/schemas/eval.datasetView"},"type":"array"}},"type":"object"},"eval.datasetReq":{"properties":{"description":{"description":"Description is free text about what this set measures; over 64 KiB is refused.","type":"string"},"metadata":{"additionalProperties":{},"description":"Metadata is a free-form object stored with the set and echoed back verbatim.","type":"object"},"name":{"description":"Name is the dataset's org-unique handle and the segment that will address\nit, so it must match ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$.","type":"string"}},"required":["name"],"type":"object"},"eval.datasetView":{"properties":{"createdAt":{"description":"CreatedAt is when the name was first written, kept across later edits.","type":"string"},"description":{"description":"Description is free text the org wrote about what this set measures.","type":"string"},"items":{"description":"Items is how many examples the set holds. It is filled only by the single\nread — a listing does not count, so it is absent there rather than zero.","format":"int64","type":"integer"},"metadata":{"additionalProperties":{},"description":"Metadata is the free-form object stored with the set, echoed back verbatim.","type":"object"},"name":{"description":"Name is the dataset's org-unique handle and the segment that addresses it.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the description or metadata last changed.","type":"string"}},"type":"object"},"eval.evaluatorList":{"properties":{"data":{"description":"Data is the caller org's judges, bounded by limit.","items":{"$ref":"#/components/schemas/eval.evaluatorView"},"type":"array"}},"type":"object"},"eval.evaluatorReq":{"properties":{"criteria":{"description":"Criteria is the written standard the judge applies; over 64 KiB is refused.","type":"string"},"model":{"description":"Model is the model that will do the grading.","type":"string"},"name":{"description":"Name is the judge's org-unique handle, matching\n^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$. Re-posting a name edits that judge\nrather than adding a second one.","type":"string"},"scoreName":{"description":"ScoreName is the name the resulting scores are filed under. It defaults to\nthe judge's own name and must match the same pattern.","type":"string"}},"required":["name"],"type":"object"},"eval.evaluatorView":{"properties":{"createdAt":{"description":"CreatedAt is when the judge was first defined.","type":"string"},"criteria":{"description":"Criteria is the written standard the judge applies.","type":"string"},"model":{"description":"Model is the model that does the grading.","type":"string"},"name":{"description":"Name is the judge's org-unique handle.","type":"string"},"scoreName":{"description":"ScoreName is the name the resulting scores are filed under.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it last changed.","type":"string"}},"type":"object"},"eval.itemList":{"properties":{"data":{"description":"Data is the examples of the one dataset named in the path, archived ones\nincluded, so the caller sees the whole set rather than what a run would use.","items":{"$ref":"#/components/schemas/eval.itemView"},"type":"array"}},"type":"object"},"eval.itemReq":{"properties":{"expectedOutput":{"description":"Expected is the answer a correct model produces, which the judge grades\nagainst, stored as raw JSON exactly as sent, up to 64 KiB."},"id":{"description":"ID makes the write idempotent — re-posting the same id replaces that example\nin place. Omit it and one is generated. An id that already exists in a\nDIFFERENT dataset is 409 rather than a move.","type":"string"},"input":{"description":"Input is what the model under test will be given, stored as raw JSON exactly\nas sent, up to 64 KiB."},"metadata":{"additionalProperties":{},"description":"Metadata is a free-form object stored with the example.","type":"object"},"status":{"description":"Status is ACTIVE (the default) or ARCHIVED. Only ACTIVE examples are fed to\na run, which is how an example is retired without being deleted.","type":"string"}},"type":"object"},"eval.itemResult":{"properties":{"error":{"description":"Error is why this example produced no score — the model, the judge, or the\nrun's deadline. A result carrying one is not counted in Scored.","type":"string"},"itemId":{"description":"ItemID is the example that was scored.","type":"string"},"output":{"description":"Output is what the model under test answered, truncated at 2000 characters.","type":"string"},"score":{"description":"Score is the judge's grade.","format":"double","type":"number"},"traceId":{"description":"TraceID is the model call this result came from.","type":"string"}},"type":"object"},"eval.itemView":{"properties":{"createdAt":{"description":"CreatedAt is when the example was first written.","type":"string"},"datasetName":{"description":"Dataset is the set this example belongs to.","type":"string"},"expectedOutput":{"description":"Expected is the answer a correct model produces, which the judge grades against."},"id":{"description":"ID is the example's handle, unique within the caller's org.","type":"string"},"input":{"description":"Input is what the model under test is given, as it was written."},"metadata":{"additionalProperties":{},"description":"Metadata is the free-form object stored with the example.","type":"object"},"status":{"description":"Status is ACTIVE or ARCHIVED. Only ACTIVE examples are fed to a run, which\nis how one is retired without being deleted.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it last changed.","type":"string"}},"type":"object"},"eval.judgeSpec":{"properties":{"criteria":{"description":"Criteria is the standard the judge applies, defaulting to a correctness\ncriterion.","type":"string"},"model":{"description":"Model is the model that grades. It defaults to the model under test, so a\nrun with no judge named has the model grade itself.","type":"string"},"name":{"description":"Name is the score name the judge's grades are filed under, \"llm-judge\" by\ndefault. A name that is not a legal handle falls back to that default\nrather than being stored as sent.","type":"string"}},"type":"object"},"eval.runRecord":{"properties":{"avgScore":{"description":"AvgScore is the mean over the scored examples.","format":"double","type":"number"},"createdAt":{"description":"CreatedAt is when the run first landed.","type":"string"},"dataset":{"description":"Dataset is the set that was scored.","type":"string"},"items":{"description":"Items is how many examples were attempted.","format":"int64","type":"integer"},"judgeModel":{"description":"JudgeModel is the model that graded.","type":"string"},"model":{"description":"Model is the model under test.","type":"string"},"runName":{"description":"RunName is the run's label.","type":"string"},"scored":{"description":"Scored is how many produced a real score.","format":"int64","type":"integer"},"updatedAt":{"description":"UpdatedAt is when the record last changed.","type":"string"}},"type":"object"},"eval.runRequest":{"properties":{"dataset":{"description":"Dataset is the set to score, which must belong to the caller's org and hold\nat least one ACTIVE example.","type":"string"},"judge":{"$ref":"#/components/schemas/eval.judgeSpec","description":"Judge is the judge to grade with. Omitted, the model under test grades\nitself against a default correctness criterion under the score name\n\"llm-judge\"."},"limit":{"description":"Limit caps how many examples this run scores. It defaults to 20, and\nanything above 100 falls back to that default.","format":"int64","type":"integer"},"model":{"description":"Model is the model under test.","type":"string"},"runName":{"description":"RunName labels the run and is generated from the clock when omitted. It\nmust match ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$.","type":"string"}},"required":["dataset","model"],"type":"object"},"eval.runSummary":{"properties":{"avgScore":{"description":"AvgScore is the mean over the scored examples, 0 when none scored.","format":"double","type":"number"},"dataset":{"description":"Dataset is the set that was scored.","type":"string"},"items":{"description":"Items is how many examples the run attempted.","format":"int64","type":"integer"},"judgeModel":{"description":"JudgeModel is the model that graded.","type":"string"},"model":{"description":"Model is the model under test.","type":"string"},"results":{"description":"Results is one row per attempted example.","items":{"$ref":"#/components/schemas/eval.itemResult"},"type":"array"},"runName":{"description":"RunName is the run's label, which scores and traces are filed under.","type":"string"},"scored":{"description":"Scored is how many produced a real score. It counts successes only, so a\npartial run is honest about what it achieved.","format":"int64","type":"integer"}},"type":"object"},"eval.runs":{"properties":{"data":{"description":"Data is the caller org's runs, bounded by limit.","items":{"$ref":"#/components/schemas/eval.runRecord"},"type":"array"}},"type":"object"},"eval.scoreConfigList":{"properties":{"data":{"description":"Data is the caller org's rubrics, bounded by limit.","items":{"$ref":"#/components/schemas/eval.scoreConfigView"},"type":"array"}},"type":"object"},"eval.scoreConfigReq":{"properties":{"categories":{"description":"Categories is the closed set of labels a CATEGORICAL score may carry. A\nCATEGORICAL rubric with none is refused.","items":{"type":"string"},"type":"array"},"dataType":{"description":"DataType is NUMERIC (the default), CATEGORICAL or BOOLEAN.","type":"string"},"maxValue":{"description":"MaxValue is the inclusive ceiling a NUMERIC score must stay under, finite.","format":"double","type":"number"},"minValue":{"description":"MinValue is the inclusive floor a NUMERIC score must clear. It must be\nfinite and must not exceed MaxValue.","format":"double","type":"number"},"name":{"description":"Name is the score name this rubric governs, matching\n^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$. The name is the key, so re-posting one\nreplaces its rules.","type":"string"}},"required":["name"],"type":"object"},"eval.scoreConfigView":{"properties":{"categories":{"description":"Categories is the closed set of labels a CATEGORICAL score may carry.","items":{"type":"string"},"type":"array"},"createdAt":{"description":"CreatedAt is when the rubric was first declared.","type":"string"},"dataType":{"description":"DataType is NUMERIC, CATEGORICAL or BOOLEAN, and is authoritative — a\nscore recorded under this name cannot claim a different one.","type":"string"},"maxValue":{"description":"MaxValue is the inclusive ceiling a NUMERIC score must stay under, absent when unbounded.","format":"double","type":"number"},"minValue":{"description":"MinValue is the inclusive floor a NUMERIC score must clear, absent when unbounded.","format":"double","type":"number"},"name":{"description":"Name is the score name this rubric governs.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it last changed.","type":"string"}},"type":"object"},"eval.scoreList":{"properties":{"data":{"description":"Data is the caller org's score events matching the filters, bounded by limit.","items":{"$ref":"#/components/schemas/eval.scoreView"},"type":"array"}},"type":"object"},"eval.scoreReq":{"properties":{"comment":{"description":"Comment is the grader's reasoning, truncated at 2000 characters.","type":"string"},"dataType":{"description":"DataType is NUMERIC, CATEGORICAL or BOOLEAN. A declared rubric overrides it\n— a caller cannot claim a type the org's rubric contradicts.","type":"string"},"datasetItemId":{"description":"ItemID attaches the score to one graded example.","type":"string"},"datasetName":{"description":"Dataset attaches the score to one dataset.","type":"string"},"name":{"description":"Name is the score name. A rubric of the same name, if the org has declared\none, decides this score's type and the values it may take.","type":"string"},"runName":{"description":"RunName attaches the score to one run.","type":"string"},"stringValue":{"description":"StringValue is the label of a CATEGORICAL score, which must be one the\nrubric allows.","type":"string"},"traceId":{"description":"TraceID attaches the score to one model call.","type":"string"},"value":{"description":"Value is the numeric score, which must be finite: NaN and Inf are refused.\nA BOOLEAN score takes 0 or 1.","format":"double","type":"number"}},"required":["name"],"type":"object"},"eval.scoreView":{"properties":{"comment":{"description":"Comment is the grader's reasoning, truncated at 2000 characters.","type":"string"},"dataType":{"description":"DataType is NUMERIC, CATEGORICAL or BOOLEAN.","type":"string"},"id":{"description":"ID is the score event's handle.","type":"string"},"name":{"description":"Name is the score name, which a rubric of the same name governs.","type":"string"},"runName":{"description":"RunName is the run this score was recorded under, when it came from one.","type":"string"},"stringValue":{"description":"StringValue is the label of a CATEGORICAL score.","type":"string"},"timestamp":{"description":"Timestamp is when the score was recorded.","type":"string"},"traceId":{"description":"TraceID is the model call this score grades, when it grades one.","type":"string"},"value":{"description":"Value is the numeric score; for BOOLEAN it is 0 or 1.","format":"double","type":"number"}},"type":"object"},"eval.traceList":{"properties":{"data":{"description":"Data is the caller org's traces matching the filters, bounded by limit.","items":{"$ref":"#/components/schemas/eval.traceView"},"type":"array"}},"type":"object"},"eval.traceView":{"properties":{"apiKeyHash":{"description":"APIKeyHash is the non-reversible credential ref (never a plaintext key), so\na trace correlates to the key that drove it without the store holding a secret.","type":"string"},"datasetItemId":{"description":"ItemID is the example the call answered.","type":"string"},"datasetName":{"description":"Dataset is the set the graded example came from.","type":"string"},"endTime":{"description":"EndTime is when it returned.","type":"string"},"id":{"description":"ID is the trace's handle, the value a score points at.","type":"string"},"input":{"description":"Input is what the model was given."},"latencyMs":{"description":"LatencyMs is EndTime-StartTime in milliseconds, nil when the trace carries\nno timing (so the console renders \"—\", never a fabricated 0).","format":"double","type":"number"},"model":{"description":"Model is the model that answered.","type":"string"},"name":{"description":"Name is the trace's label, \"eval:\u003crun\u003e\" for a call a run made.","type":"string"},"output":{"description":"Output is what it answered.","type":"string"},"projectId":{"description":"ProjectID is the sub-scope within the org the call was made under.","type":"string"},"runName":{"description":"RunName is the run the call belongs to.","type":"string"},"sessionId":{"description":"SessionID groups the calls of one run.","type":"string"},"startTime":{"description":"StartTime is when the call began.","type":"string"},"timestamp":{"description":"Timestamp is the trace's own clock, equal to StartTime for a timed call.","type":"string"}},"type":"object"},"event.Breakdown":{"properties":{"available":{"description":"Available is false when the product-event table could not be read.","type":"boolean"},"items":{"description":"Items is the ranked buckets, most pageviews first. Empty rather than absent.","items":{"$ref":"#/components/schemas/event.BreakdownRow"},"type":"array"},"reason":{"description":"Reason says why the lens is unavailable. Omitted when it is available.","type":"string"},"source":{"description":"Source is the warehouse table the lens read.","type":"string"}},"type":"object"},"event.BreakdownRow":{"properties":{"key":{"description":"Key is the bucket: a requested path, a referrer domain (\"(direct)\" for none or\na same-origin one), or a utm_source (\"(none)\" when absent).","type":"string"},"pageviews":{"description":"Pageviews is how many $pageview events fell in this bucket.","format":"int64","type":"integer"},"pct":{"description":"Pct is this bucket's share of ALL in-window pageviews, 0..100, one decimal —\nnot of the returned rows, so a top-N shows the long tail honestly.","format":"double","type":"number"},"visitors":{"description":"Visitors is how many distinct people they came from.","format":"int64","type":"integer"}},"type":"object"},"event.CommerceOverview":{"properties":{"aov":{"description":"AOV is average order value — Revenue/Orders, rounded to two places. Zero when\nthere were no orders.","format":"double","type":"number"},"available":{"description":"Available is false when the product-event table could not be read — the lens is\nreported missing rather than as zeros that look like no sales.","type":"boolean"},"orders":{"description":"Orders is how many order_completed events landed in the window.","format":"int64","type":"integer"},"reason":{"description":"Reason says why the lens is unavailable. Omitted when it is available.","type":"string"},"revenue":{"description":"Revenue is the total those orders carried, in the events' own currency unit.","format":"double","type":"number"},"source":{"description":"Source is the warehouse table the lens read.","type":"string"}},"type":"object"},"event.EconomicDispute":{"properties":{"at":{"description":"At is when the dispute was filed, unix seconds.","format":"int64","type":"integer"},"by":{"description":"By is the org that disputes it: one of the event's two parties.","type":"string"},"event":{"description":"Event is the id of the event disputed.","type":"string"},"reason":{"description":"Reason is what the party says is wrong.","type":"string"}},"type":"object"},"event.EconomicEvent":{"properties":{"agent":{"description":"Agent is the principal that acted for the buyer, as IAM names it. Only the\nbuyer's copy carries it: it may name a person, and who inside the buyer\nacted is none of the seller's records.","type":"string"},"at":{"description":"At is when the payment was made, unix seconds, as the rail recorded it.","format":"int64","type":"integer"},"buyer":{"description":"Buyer is the org that paid.","type":"string"},"category":{"description":"Category is what the payment was for — service, goods, transfer, refund or\nroyalty — as the rail recorded the parties agreeing it. Empty on an event\nstated before version 2, and on a rail that records no purpose.","type":"string"},"chain":{"description":"Chain is the CAIP-2 network an on-chain payment moved on.","type":"string"},"corrects":{"description":"Corrects is the id of the event this one restates, when it is a correction.","type":"string"},"currency":{"description":"Currency is what the amounts are in: an ISO 4217 code or an asset symbol.","type":"string"},"fee":{"description":"Fee is what the rail kept of Gross, an exact decimal in Currency.","type":"string"},"fmv":{"description":"FMV is Gross's fair market value in U.S. dollars when it was paid, an exact\ndecimal.","type":"string"},"gross":{"description":"Gross is what the buyer paid, an exact decimal in Currency.","type":"string"},"id":{"description":"ID is the event's identity, derived from its rail and proof.","type":"string"},"jurisdictions":{"description":"Jurisdictions are the ISO 3166 codes the payment is subject to, when the\nrail knows them.","items":{"type":"string"},"type":"array"},"parent":{"description":"Parent is the agent that spawned Agent, when one did. Only the buyer's copy\ncarries it, for Agent's reason.","type":"string"},"proof":{"description":"Proof is the rail's own reference for the payment: a settlement id, a chain\ntransaction hash or a processor reference.","type":"string"},"rail":{"description":"Rail is how the money moved: x402, ledger, chain, ach, wire, card, network\nor other.","type":"string"},"seller":{"description":"Seller is the org that was paid.","type":"string"},"service":{"description":"Service is what was bought, in the rail's own words.","type":"string"},"tax":{"description":"Tax is the tax collected within Gross, an exact decimal in Currency.","type":"string"},"tx":{"description":"Tx is the on-chain transaction hash of an on-chain payment.","type":"string"},"v":{"description":"V is the schema version the event was stated in.","format":"int64","type":"integer"}},"type":"object"},"event.Economics":{"properties":{"disputes":{"description":"Disputes are what either party has disputed about the events in Rows. A\ndispute changes nothing about the event it names.","items":{"$ref":"#/components/schemas/event.EconomicDispute"},"type":"array"},"next":{"description":"Next continues the read; empty on the last page.","type":"string"},"rows":{"description":"Rows are the events.","items":{"$ref":"#/components/schemas/event.EconomicEvent"},"type":"array"},"superseded":{"description":"Superseded are the ids in Rows that a correction restates.","items":{"type":"string"},"type":"array"}},"type":"object"},"event.LLMOverview":{"properties":{"available":{"description":"Available is true whenever the ledger answered — including with no usage in the\nwindow, which is honest zeros rather than a missing lens.","type":"boolean"},"completionTokens":{"description":"CompletionTokens is the output half of Tokens.","format":"int64","type":"integer"},"errorRate":{"description":"ErrorRate is Errors/Requests, 0..1, rounded to three places. Zero when there\nwere no requests.","format":"double","type":"number"},"errors":{"description":"Errors is how many of Requests failed.","format":"int64","type":"integer"},"models":{"description":"Models is how many distinct models the org called.","format":"int64","type":"integer"},"promptTokens":{"description":"PromptTokens is the input half of Tokens.","format":"int64","type":"integer"},"providers":{"description":"Providers is how many distinct providers served them.","format":"int64","type":"integer"},"requests":{"description":"Requests is how many LLM calls the org made in the window.","format":"int64","type":"integer"},"source":{"description":"Source is the warehouse table the lens read.","type":"string"},"spendCents":{"description":"SpendCents is what those calls cost, in cents.","format":"int64","type":"integer"},"tokens":{"description":"Tokens is prompt plus completion tokens over those calls.","format":"int64","type":"integer"}},"type":"object"},"event.ModelRow":{"properties":{"model":{"description":"Model is the model id, e.g. zen5-coder.","type":"string"},"pct":{"description":"Pct is this model's share of the window's returned spend, 0..100, one decimal.","format":"double","type":"number"},"provider":{"description":"Provider is who served it.","type":"string"},"requests":{"description":"Requests is how many calls went to this model.","format":"int64","type":"integer"},"spendCents":{"description":"SpendCents is what they cost, in cents.","format":"int64","type":"integer"},"tokens":{"description":"Tokens is prompt plus completion tokens over those calls.","format":"int64","type":"integer"}},"type":"object"},"event.Overview":{"properties":{"commerce":{"$ref":"#/components/schemas/event.CommerceOverview","description":"Commerce is the orders/revenue lens over product events."},"end":{"description":"End is the window's exclusive upper bound, RFC3339 UTC.","type":"string"},"impersonated":{"description":"Impersonated is which events web and commerce counted against the mark a\nplatform operator leaves acting as someone else: exclude (the tenant's own\ntraffic), include, or only. LLM reads the usage ledger, which carries no mark.","type":"string"},"interval":{"description":"Interval is the bucket width the window implies: hour or day.","type":"string"},"llm":{"$ref":"#/components/schemas/event.LLMOverview","description":"LLM is the LLM usage lens — real per-org data."},"range":{"description":"Range is the window that was actually applied: 24h, 7d, 30d or custom.","type":"string"},"scope":{"$ref":"#/components/schemas/event.Scope","description":"Scope names the tenant these numbers belong to."},"start":{"description":"Start is the window's inclusive lower bound, RFC3339 UTC.","type":"string"},"web":{"$ref":"#/components/schemas/event.WebOverview","description":"Web is the web-traffic lens over product events."}},"type":"object"},"event.ProductRow":{"properties":{"orders":{"description":"Orders is how many order_completed events carried it.","format":"int64","type":"integer"},"productId":{"description":"ProductID is the product the order events named.","type":"string"},"revenue":{"description":"Revenue is the total they carried, in the events' own currency unit.","format":"double","type":"number"},"units":{"description":"Units is the summed quantity sold.","format":"int64","type":"integer"}},"type":"object"},"event.Scope":{"properties":{"org":{"description":"Org is the IAM org slug the rows were read under: the validated principal's,\nresolved server-side.","type":"string"}},"type":"object"},"event.Timeseries":{"properties":{"end":{"description":"End is the window's exclusive upper bound, RFC3339 UTC.","type":"string"},"interval":{"description":"Interval is the bucket width: hour or day.","type":"string"},"range":{"description":"Range is the window that was actually applied: 24h, 7d, 30d or custom.","type":"string"},"scope":{"$ref":"#/components/schemas/event.Scope","description":"Scope names the tenant these numbers belong to."},"series":{"description":"Series is one point per bucket, oldest first, with empty buckets zero-filled.","items":{"$ref":"#/components/schemas/event.UsagePoint"},"type":"array"},"source":{"description":"Source is the warehouse table the series read.","type":"string"},"start":{"description":"Start is the window's inclusive lower bound, RFC3339 UTC.","type":"string"}},"type":"object"},"event.Top":{"properties":{"end":{"description":"End is the window's exclusive upper bound, RFC3339 UTC.","type":"string"},"impersonated":{"description":"Impersonated is which events products, topPages, topReferrers and topSources\ncounted against the mark a platform operator leaves acting as someone else:\nexclude (the tenant's own traffic), include, or only. Models reads the usage\nledger, which carries no mark.","type":"string"},"models":{"$ref":"#/components/schemas/event.TopModels","description":"Models ranks the window's LLM models by spend — real per-org data."},"products":{"$ref":"#/components/schemas/event.TopProducts","description":"Products ranks the window's products by revenue."},"range":{"description":"Range is the window that was actually applied: 24h, 7d, 30d or custom.","type":"string"},"scope":{"$ref":"#/components/schemas/event.Scope","description":"Scope names the tenant these rankings belong to."},"start":{"description":"Start is the window's inclusive lower bound, RFC3339 UTC.","type":"string"},"topPages":{"$ref":"#/components/schemas/event.Breakdown","description":"Pages ranks the paths visitors requested, by pageviews."},"topReferrers":{"$ref":"#/components/schemas/event.Breakdown","description":"Referrers ranks the external domains visitors arrived from, by pageviews."},"topSources":{"$ref":"#/components/schemas/event.Breakdown","description":"Sources ranks the utm_source campaigns visitors arrived on, by pageviews."}},"type":"object"},"event.TopModels":{"properties":{"available":{"description":"Available is true whenever the ledger answered, including with no rows.","type":"boolean"},"items":{"description":"Items is the ranked models, highest spend first.","items":{"$ref":"#/components/schemas/event.ModelRow"},"type":"array"},"source":{"description":"Source is the warehouse table the lens read.","type":"string"}},"type":"object"},"event.TopProducts":{"properties":{"available":{"description":"Available is false when the product-event table could not be read.","type":"boolean"},"items":{"description":"Items is the ranked products, highest revenue first. Empty rather than absent.","items":{"$ref":"#/components/schemas/event.ProductRow"},"type":"array"},"reason":{"description":"Reason says why the lens is unavailable. Omitted when it is available.","type":"string"},"source":{"description":"Source is the warehouse table the lens read.","type":"string"}},"type":"object"},"event.UsagePoint":{"properties":{"requests":{"description":"Requests is how many LLM calls fell in this bucket.","format":"int64","type":"integer"},"spendCents":{"description":"SpendCents is what they cost, in cents.","format":"int64","type":"integer"},"t":{"description":"T is the bucket's start, RFC3339 UTC, aligned to the interval.","type":"string"},"tokens":{"description":"Tokens is prompt plus completion tokens over those calls.","format":"int64","type":"integer"}},"type":"object"},"event.WebOverview":{"properties":{"available":{"description":"Available is false when the product-event table could not be read — the lens is\nreported missing rather than as zeros that look like real traffic.","type":"boolean"},"pageviews":{"description":"Pageviews is how many $pageview events landed in the window.","format":"int64","type":"integer"},"reason":{"description":"Reason says why the lens is unavailable. Omitted when it is available.","type":"string"},"sessions":{"description":"Sessions is how many distinct visits they span.","format":"int64","type":"integer"},"source":{"description":"Source is the warehouse table the lens read.","type":"string"},"visitors":{"description":"Visitors is how many distinct people those pageviews came from.","format":"int64","type":"integer"}},"type":"object"},"event.capturedError":{"properties":{"distinctId":{"description":"DistinctID is the person/visitor the error is attributed to. Omitted when the\nrow carries none.","type":"string"},"event":{"description":"Event is the event name the error was stored under, e.g. $error.","type":"string"},"exception":{"description":"Exception is the captured error itself — the {type, message, stack, handled}\nobject, already redacted at the fold point. Omitted when the row has none."},"id":{"description":"ID is the row's stable event id — the client's own idempotency id when it sent\none, else the server-minted one.","type":"string"},"library":{"description":"Library is the client SDK that reported the error. Omitted when absent.","type":"string"},"libraryVersion":{"description":"LibraryVer is that SDK's version. Omitted when absent.","type":"string"},"path":{"description":"Path is the URL's path component. Omitted when absent.","type":"string"},"product":{"description":"Product is the surface that emitted the error. Omitted when absent.","type":"string"},"properties":{"description":"Properties is the row's whole property bag, returned verbatim as stored — any\nJSON object, $exception included. Omitted when the row carries none or it did\nnot parse."},"sessionId":{"description":"SessionID groups the events of one visit. Omitted when the client sent none.","type":"string"},"timestamp":{"description":"Timestamp is when the error was captured, RFC3339 UTC.","type":"string"},"url":{"description":"URL is the full page address the error fired on. Omitted when absent.","type":"string"}},"type":"object"},"event.disputeIn":{"properties":{"event":{"description":"Event is the id of the economic event disputed.","type":"string"},"reason":{"description":"Reason is what the caller's org says is wrong, at most 1024 characters.","type":"string"}},"required":["event","reason"],"type":"object"},"event.errorList":{"properties":{"data":{"description":"Data is the errors, newest first. Empty rather than absent when there are none.","items":{"$ref":"#/components/schemas/event.capturedError"},"type":"array"}},"type":"object"},"event.eventList":{"properties":{"data":{"description":"Data is the events, newest first. Empty rather than absent when there are none.","items":{"$ref":"#/components/schemas/event.productEvent"},"type":"array"}},"type":"object"},"event.healthLens":{"properties":{"available":{"description":"Available reports whether that table exists in the warehouse right now.","type":"boolean"},"table":{"description":"Table is the fully-qualified warehouse table the lens reads.","type":"string"}},"type":"object"},"event.healthLenses":{"properties":{"events":{"$ref":"#/components/schemas/event.healthLens","description":"Events is the web/commerce lens (event.fact, signal='act'), honest-empty until the\ncollector emits."},"llm":{"$ref":"#/components/schemas/event.healthLens","description":"LLM is the live per-org usage ledger lens (hanzo.cloud_usage)."}},"type":"object"},"event.healthPlane":{"properties":{"bus":{"description":"Bus is the address this process reaches the plane at.","type":"string"},"ready":{"description":"Ready reports whether an ingest would succeed right now. False is a 503.","type":"boolean"},"reason":{"description":"Reason is the plane's own failure text, present only when Ready is false.","type":"string"},"stream":{"description":"Stream is the JetStream stream every signal lands on.","type":"string"}},"type":"object"},"event.healthReport":{"properties":{"datastore":{"description":"Datastore reports whether the shared warehouse client has a live connection.\nIt is load-bearing for the READ path: false is one of the two ways this\nanswers 503.","type":"boolean"},"lenses":{"$ref":"#/components/schemas/event.healthLenses","description":"Lenses is per-lens table availability, probed only when connected — so it is\nabsent from a degraded report, which has nothing to say about tables it could\nnot reach."},"lost":{"$ref":"#/components/schemas/event.loss","description":"Lost is the count of facts the sink irrecoverably dropped since boot\n(warehouse.go). It is reported on the DEGRADED report too, and deliberately: a\nwarehouse that is unreachable is exactly when facts start failing their\ndeliveries, so suppressing the number here would hide it precisely when it\nmoves. ANY NON-ZERO VALUE IS AN ALARM — it counts data the endpoint already\nanswered 200 for."},"plane":{"$ref":"#/components/schemas/event.healthPlane","description":"Plane reports the event plane — the bus and the stream every accepted event is\npublished to BEFORE any of it reaches the warehouse. It is load-bearing for the\nWRITE path: warehouse connectivity alone says nothing about whether a publish\ncan land, so the probe reports the write path from the write path itself."},"reason":{"description":"Reason is the human-readable cause, present only on a degraded report.","type":"string"},"service":{"description":"Service names the subsystem answering, so a probe aggregating several health\nendpoints can attribute a degraded one.","type":"string"},"status":{"description":"Status is ok or degraded. Degraded is the 503 and means EITHER load-bearing\ndependency is down — the warehouse this subsystem reads, or the event plane it\nwrites. It is not moved by a missing lens table, which is honest-empty.","type":"string"},"warehouse":{"description":"Warehouse names the datastore database every lens reads.","type":"string"}},"type":"object"},"event.insightsStatus":{"properties":{"engine":{"description":"Engine names the engine serving the surface: hanzo-analytics.","type":"string"},"ok":{"description":"OK is always true — reaching this route is the liveness fact it reports.","type":"boolean"},"surface":{"description":"Surface is the path prefix this status covers: /v1/event/insights.","type":"string"}},"type":"object"},"event.loss":{"properties":{"exhausted":{"description":"Exhausted counts facts the bus abandoned after maxDeliver failed inserts.","format":"int64","type":"integer"},"undecodable":{"description":"Undecodable counts messages acked without landing because they did not parse.","format":"int64","type":"integer"}},"type":"object"},"event.productEvent":{"properties":{"distinctId":{"description":"DistinctID is the person/visitor the event is attributed to.","type":"string"},"event":{"description":"Event is the event name, e.g. page_viewed or signup_completed.","type":"string"},"id":{"description":"ID is the row's stable event id — the client's own idempotency id when it sent\none, else the server-minted one.","type":"string"},"path":{"description":"Path is the URL's path component, the key the topPages lens groups by.","type":"string"},"product":{"description":"Product is the surface that emitted the event. Omitted when absent.","type":"string"},"properties":{"description":"Properties is the row's attributes map as a JSON object (string values — the\nplane stores Map(String,String), so a nested value the caller sent is a\nJSON-encoded string). Omitted when the row carries none."},"sessionId":{"description":"SessionID groups the events of one visit. Omitted when the client sent none.","type":"string"},"timestamp":{"description":"Timestamp is when the event happened, RFC3339 UTC.","type":"string"},"type":{"description":"Type is the row's kind — the plane's discriminator: page, track, identify or\ngroup. (Errors are not here at all: they land on event.error and are read at\n/v1/event/errors.)","type":"string"},"url":{"description":"URL is the full page address the event fired on. Omitted when absent.","type":"string"}},"type":"object"},"exec.CodeFile":{"properties":{"id":{"description":"ID is the file's path RELATIVE to its session's artifact directory, which is\nalso how it is fetched: GET /v1/exec/download/{session}/{id}.","type":"string"},"name":{"description":"Name is the display name. On an ANSWER it carries the `{session}/{id}`\nidentifier whole, because the client matches on that prefix.","type":"string"},"session_id":{"description":"SessionID is the other accepted spelling of the same fact on the way IN. Both\nare read; whichever is set wins.","type":"string"},"storage_session_id":{"description":"StorageSessionID names the session holding the bytes, and is the spelling the\nanswer always uses.","type":"string"}},"type":"object"},"exec.CodeResult":{"properties":{"files":{"description":"Files are what this run CREATED OR CHANGED, decided by mtime against a marker\ntaken before the program started — so it is the run's output, not a listing of\nthe directory. Fetch each from GET /v1/exec/download/{session}/{id}.","items":{"$ref":"#/components/schemas/exec.CodeFile"},"type":"array"},"session_id":{"description":"SessionID is the sandbox this run used — the one that was passed in, or the\nfresh one that was leased. Pass it to the next run to keep the filesystem.","type":"string"},"stderr":{"description":"Stderr is what the program wrote to standard error, INCLUDING a compiler's\ndiagnostics and the trace of a program that exited non-zero. Its presence is\nnot a failed call.","type":"string"},"stdout":{"description":"Stdout is what the program wrote to standard output.","type":"string"}},"type":"object"},"exec.CodeRun":{"properties":{"args":{"description":"Args become the PROGRAM's argv, never the compiler's. For the compiled\nlanguages the toolchain builds first and these are passed to the binary it\nproduced.","items":{"type":"string"},"type":"array"},"code":{"description":"Code is the WHOLE program, not a fragment: it is written to a single file and\nthat file is what runs, so a compiled language needs its entry point and an\ninterpreted one runs top to bottom.","type":"string"},"files":{"description":"Files are inputs the host already put in some session. Each names the session\nits bytes live in, which is usually — and ideally — the session this run wants.","items":{"$ref":"#/components/schemas/exec.CodeFile"},"type":"array"},"lang":{"description":"Lang selects the toolchain, and with it the filename the code is written to\nand the line that runs it: py, js, ts, bash, r, php, go, rs, c, cpp, java, d,\nf90. Anything else is refused rather than guessed at — a run in the wrong\nlanguage fails somewhere deep in a compiler, which reads as an outage.","type":"string"},"runtime_session_hint":{"description":"RuntimeSessionHint is the stateful-session hint. It is carried so a client\nthat sends it is not silently misread, and it selects nothing here: every\nsession in this implementation is already a warm sandbox, so there is no\nsecond kind of runtime for a hint to choose between.","type":"string"},"session_id":{"description":"SessionID continues an EXISTING sandbox, which is what makes runs stateful:\nthe same filesystem, so one run's output file is the next run's input. Empty\nleases a fresh sandbox and the id it got comes back on the result.","type":"string"},"user_id":{"description":"UserID attributes the run inside the caller's org. It is a label, never a\ntenant: the org is resolved from the validated principal and a value here\ncannot widen what the run may reach.","type":"string"}},"required":["lang","code"],"type":"object"},"exec.listing":{"properties":{"lastModified":{"description":"LastModified is when the BYTES last changed, as RFC 3339 in UTC to the\nsecond — `2026-01-02T03:04:05Z`, the sandbox's own `date -u -r` on the file.\nIt is an mtime and not a creation time, so a file a later run overwrote\ncarries that run's clock. Never empty: a row exists only because `find`\nstat-ed the file.","type":"string"},"name":{"description":"Name is the file's IDENTIFIER, `{session_id}/{fileId}` whole — never the bare\nfilename, and never URL-escaped. It is exactly what GET /v1/exec/download\ntakes after its prefix, and hanzo.chat matches it as a PREFIX\n(`name.startsWith(session + \"/\")`) to decide which rows belong to a session\nit is holding. `fileId` is the path RELATIVE to the session's artifact\ndirectory, so it carries `/` for anything the run wrote in a sub-directory.","type":"string"}},"type":"object"},"experiment.Analysis":{"properties":{"alpha":{"description":"the two-tailed threshold significance was judged at","format":"double","type":"number"},"experiment":{"description":"the experiment that was analysed","type":"string"},"exposedTotal":{"description":"subjects enrolled across every arm","format":"int64","type":"integer"},"metric":{"description":"the event a conversion is counted from","type":"string"},"results":{"description":"one row per declared arm, control first","items":{"$ref":"#/components/schemas/experiment.Outcome"},"type":"array"},"winner":{"description":"ADVISORY: the significant, control-beating arm with the highest rate, else empty","type":"string"}},"type":"object"},"experiment.Arm":{"properties":{"control":{"description":"true on the baseline arm every other arm is compared to","type":"boolean"},"key":{"description":"the arm's slug, unique within the experiment","type":"string"},"payload":{"description":"opaque JSON the arm carries, which the consumer interprets"},"weight":{"description":"its share of the rollout; the arms sum to 100","format":"double","type":"number"}},"type":"object"},"experiment.Outcome":{"properties":{"control":{"description":"true on the baseline arm; its own lift and stats are zero","type":"boolean"},"converted":{"description":"of those, how many fired the metric event","format":"int64","type":"integer"},"exposed":{"description":"subjects the arm enrolled — the denominator","format":"int64","type":"integer"},"lift":{"description":"relative to control: (rate-ctrl)/ctrl","format":"double","type":"number"},"pValue":{"description":"two-tailed p vs control","format":"double","type":"number"},"rate":{"description":"converted over exposed","format":"double","type":"number"},"significant":{"description":"pValue \u003c alpha","type":"boolean"},"variant":{"description":"the arm this row measures","type":"string"},"z":{"description":"two-proportion z vs control","format":"double","type":"number"}},"type":"object"},"experiment.Trial":{"properties":{"createdAt":{"description":"when it started assigning","type":"string"},"createdBy":{"description":"the credential that registered it","type":"string"},"decidedAt":{"description":"when the promotion took effect","type":"string"},"decidedBy":{"description":"the credential that promoted the winner","type":"string"},"exposureEvent":{"description":"the event that enrols a subject — the analysis denominator","type":"string"},"flagKey":{"description":"the assignment flag this experiment drives","type":"string"},"id":{"description":"the experiment's slug, unique within the project","type":"string"},"metricEvent":{"description":"the event that counts as a conversion — the numerator","type":"string"},"name":{"description":"free text for a reader","type":"string"},"project":{"description":"the sub-scope within the org, stamped from the principal","type":"string"},"status":{"description":"running while it assigns and measures, decided once a winner is promoted","type":"string"},"subjectKind":{"description":"the unit assigned and measured: user, org, session or audience","type":"string"},"variants":{"description":"the arms, weighted, one of them the control","items":{"$ref":"#/components/schemas/experiment.Arm"},"type":"array"},"winner":{"description":"the arm promoted to the whole rollout","type":"string"}},"type":"object"},"experiment.analyzeQuery":{"properties":{"alpha":{"description":"Alpha overrides the 0.05 two-tailed significance threshold when it lies\nstrictly between 0 and 1; anything else leaves the default in place.","format":"double","type":"number"},"days":{"description":"Days is how far back to read when no start is given: 1 to 365, 30 by\ndefault. A value outside that range leaves the default in place.","format":"int64","type":"integer"},"end":{"description":"End is the window's exclusive end in RFC3339, defaulting to now.","type":"string"},"id":{"description":"ID is the experiment the URL names.","type":"string"},"start":{"description":"Start is the window's inclusive start in RFC3339. Given, it wins over days.","type":"string"}},"type":"object"},"experiment.assignment":{"properties":{"experiment":{"description":"Trial is the experiment that was evaluated.","type":"string"},"on":{"description":"On is false when the flag returned nothing for this subject, which means the\nsubject is not enrolled — not an error.","type":"boolean"},"payload":{"description":"Payload is the opaque JSON the winning arm carries, which the caller\ninterprets: a feature config, an ad-creative id, a subject line, a model id."},"subject":{"description":"Subject is the unit that was bucketed.","type":"string"},"variant":{"description":"Arm is the arm the subject falls in, empty when the flag enrolled it in\nnone.","type":"string"}},"type":"object"},"experiment.createBody":{"properties":{"exposureEvent":{"description":"ExposureEvent is the event that marks a subject as enrolled — the analysis\ndenominator — defaulting to the SDK's $feature_flag_called marker.","type":"string"},"flagKey":{"description":"FlagKey names the assignment flag this experiment writes, defaulting to\nexp_\u003cid\u003e. It must be a slug.","type":"string"},"id":{"description":"ID is the experiment's slug, claimed once per project. It must match\n[A-Za-z0-9][A-Za-z0-9._-]{0,127}.","type":"string"},"metricEvent":{"description":"MetricEvent is the event that counts as a conversion — the analysis\nnumerator.","type":"string"},"name":{"description":"Name is free text for a reader; the id is what addresses the experiment.","type":"string"},"subjectKind":{"description":"SubjectKind is the unit assigned and measured: user (the default), org,\nsession or audience.","type":"string"},"variants":{"description":"Arms are the arms, at least two. Weights that are all zero become an\neven split; otherwise they must sum to 100, and at most one arm may be\nflagged control.","items":{"$ref":"#/components/schemas/experiment.Arm"},"type":"array"}},"required":["id","metricEvent","variants"],"type":"object"},"experiment.decideBody":{"properties":{"winner":{"description":"Winner is the variant to promote. It must name one of this experiment's own\narms.","type":"string"}},"required":["winner"],"type":"object"},"experiment.experimentList":{"properties":{"data":{"description":"Data is the org's experiments, ordered by project then id.","items":{"$ref":"#/components/schemas/experiment.Trial"},"type":"array"},"total":{"description":"Total is how many rows Data holds.","format":"int64","type":"integer"}},"type":"object"},"experiment.health":{"properties":{"ok":{"description":"OK is true whenever this route answers at all: reaching the handler IS the\nproof that the routes are registered and dispatching.","type":"boolean"},"subsystem":{"description":"Subsystem names what answered, so a health response read out of context still\nsays which surface it came from.","type":"string"}},"type":"object"},"explorer.indexerView":{"properties":{"chain":{"description":"Chain is the chain this indexer indexes, as the indexer names it.","type":"string"},"height":{"description":"Height is the latest INDEXED block height, as a decimal string. Absent when\nnothing has been indexed yet.","type":"string"},"id":{"description":"ID identifies the indexer: its chain name, else its chain id, else the brand.","type":"string"},"lag":{"description":"Lag is how far behind the chain HEAD this indexer is. The indexer REST does not\nexpose the head, so it is always absent rather than a fabricated zero.","type":"string"},"network":{"description":"Network is the deployment's network tier: mainnet, testnet or devnet.","type":"string"},"status":{"description":"Status is \"degraded\" when /health explicitly reports unhealthy, else \"active\".","type":"string"},"updatedAt":{"description":"UpdatedAt is the latest indexed block's timestamp, RFC 3339 UTC.","type":"string"}},"type":"object"},"explorer.indexersOut":{"properties":{"indexers":{"description":"Indexers is one row per reachable chain indexer, or an empty list when the\nindexer is unreachable — never a fabricated row.","items":{"$ref":"#/components/schemas/explorer.indexerView"},"type":"array"}},"type":"object"},"explorer.oracleView":{"properties":{"feed":{"description":"Feed is the trading pair this feed prices.","type":"string"},"id":{"description":"ID is the feed's own id, else its trading pair.","type":"string"},"name":{"description":"Name is the feed's display name — the trading pair, e.g. \"LUX/USD\".","type":"string"},"source":{"description":"Source is the oracle network the feed originates from; \"O-Chain\" by default.","type":"string"},"status":{"description":"Status is \"active\" for a listed feed.","type":"string"},"updatedAt":{"description":"UpdatedAt is the feed's own timestamp, RFC 3339 UTC.","type":"string"},"value":{"description":"Value is the feed's price, verbatim as the registry carries it.","type":"string"}},"type":"object"},"explorer.oraclesOut":{"properties":{"oracles":{"description":"Oracles is one row per on-chain price feed, or an empty list when the graph is\nunreachable or carries none — never a fabricated feed.","items":{"$ref":"#/components/schemas/explorer.oracleView"},"type":"array"}},"type":"object"},"flag.ActivityRow":{"properties":{"action":{"description":"Action is one of created, updated, deleted.","type":"string"},"actor":{"description":"Actor is the email of the principal who made the change. Empty for a write\nby an in-process composer; a project key can never appear here, because\nevaluating flags is all a key may do.","type":"string"},"at":{"description":"At is when the change was made, RFC 3339 UTC.","type":"string"},"detail":{"description":"Detail is free-form context about the change. Nothing writes it today, so\nit is absent from every row the store serves.","type":"string"},"id":{"description":"ID is the log's own sequence number, rising with each entry. The log is\nserved newest-first, which is this descending.","format":"int64","type":"integer"},"key":{"description":"Key is the flag that changed. It survives a delete, so the log still names\nflags the definition store no longer holds.","type":"string"}},"type":"object"},"flag.DefRow":{"properties":{"definition":{"description":"Definition is the flag-definition document the evaluator consumes, kept\nBYTE-FOR-BYTE as it was written. It is the engine's format rather than this\npackage's, so it carries fields no Go type here names — targeting groups,\nrollout percentages, variants, payloads — and a caller must round-trip it\nwhole rather than rebuilding it from the parts it recognizes."},"key":{"description":"Key is the flag's primary key in the caller's (org, project) store, and the\nname evaluation looks it up by. On a write it is taken from the URL, never\nfrom the body: the stored document's own \"key\" is forced to match.","type":"string"},"updated_at":{"description":"UpdatedAt is when the definition was last written, RFC 3339 UTC.","type":"string"},"updated_by":{"description":"UpdatedBy is the email of the principal who last wrote it. Empty when the\nwrite came from an in-process composer (an experiment registering its own\nassignment flag) rather than from a signed-in person.","type":"string"},"version":{"description":"Version is 1 when the key was created and rises by one on every overwrite.\nIt counts writes, not content changes: re-storing an identical document\nbumps it.","format":"int64","type":"integer"}},"type":"object"},"flag.activityOut":{"properties":{"data":{"description":"Data is the change log newest-first: who created, updated or deleted which key, when.","items":{"$ref":"#/components/schemas/flag.ActivityRow"},"type":"array"}},"type":"object"},"flag.defsOut":{"properties":{"data":{"description":"Data is every definition in the caller's (org, project) store, by key.","items":{"$ref":"#/components/schemas/flag.DefRow"},"type":"array"}},"type":"object"},"flag.deletedOut":{"properties":{"deleted":{"description":"Deleted is the key that no longer exists.","type":"string"}},"type":"object"},"flag.evaluateIn":{"properties":{"distinct_id":{"description":"DistinctID is the identity the flags are evaluated for. Required.","type":"string"},"groups":{"description":"Groups are the group-level properties, keyed by group type index."},"person_properties":{"description":"PersonProperties are the person-level properties conditions match against."}},"type":"object"},"flag.healthOut":{"properties":{"engine":{"description":"Engine names the evaluator this deployment runs.","type":"string"},"ok":{"description":"OK is true whenever the flag engine is serving.","type":"boolean"}},"type":"object"},"flag.optinIn":{"properties":{"on":{"description":"On opts the caller in to every public beta, current and future, when true,\nand out when false.","type":"boolean"}},"type":"object"},"flag.optinOut":{"properties":{"blocked":{"description":"Blocked is true when the org the caller acts in turned the opt-in off for\nits members. Their own choice is kept and applies again once unblocked.","type":"boolean"},"on":{"description":"On is true when the caller opted in: every public beta, and each one\npromoted later, is on for them unless Blocked.","type":"boolean"},"public":{"description":"Public is the id of every beta anyone may opt in to (beta.\u003cid\u003e). The rest are\nprivate: a SuperAdmin grants them, person by person.","items":{"type":"string"},"type":"array"}},"type":"object"},"flag.orgOptinIn":{"properties":{"blocked":{"description":"Blocked turns the opt-in off for every member of the org when true, and back\non when false. It never turns a beta on for anyone.","type":"boolean"}},"type":"object"},"flag.orgOptinOut":{"properties":{"blocked":{"description":"Blocked is true when the org's members do not get public betas by opting in.","type":"boolean"}},"type":"object"},"flag.platformOut":{"properties":{"flags":{"additionalProperties":{"type":"boolean"},"description":"Flags maps each principal switch's key to whether it is on for the caller:\n`beta` is whether the caller sees products and catalog items that are not\nyet generally available, and beta.\u003cid\u003e whether they see that one app in\nbeta in the Hanzo app.","type":"object"}},"type":"object"},"flow.flowCreate":{"properties":{"data":{"description":"Data is the workflow graph (the product's nodes/edges document),\nverbatim. Omit it to create an empty workflow."},"description":{"description":"Description says what the workflow does.","type":"string"},"name":{"description":"Name is the workflow's display name, unique within the org's project\n(the product de-duplicates by suffixing).","type":"string"}},"type":"object"},"flow.flowRun":{"properties":{"input":{"description":"Input is the run's chat input value, handed to the graph's input node.","type":"string"},"session":{"description":"Session groups runs into one conversation; the product mints one when\nabsent and returns it in the response.","type":"string"},"tweaks":{"description":"Tweaks override component fields for this run only (the product's\ntweaks document), verbatim."},"workflow":{"description":"Workflow is the UUID of the workflow to run.","type":"string"}},"type":"object"},"flow.flowStatus":{"properties":{"reachable":{"description":"Reachable is true when the flow service answered its health probe.","type":"boolean"},"version":{"description":"Version is the flow service's own version, present only when reachable.","type":"string"}},"type":"object"},"flow.flowUpdate":{"properties":{"data":{"description":"Data replaces the workflow graph when present, verbatim."},"description":{"description":"Description replaces the description when present.","type":"string"},"locked":{"description":"Locked freezes or unfreezes the workflow against edits when present.","type":"boolean"},"name":{"description":"Name renames the workflow when present.","type":"string"},"workflow":{"description":"Workflow is the workflow's UUID, taken from the path.","type":"string"}},"type":"object"},"forgeJob":{"properties":{"action":{"type":"string"},"repository":{"properties":{"name":{"type":"string"},"owner":{"properties":{"login":{"type":"string"},"username":{"type":"string"}},"type":"object"}},"type":"object"},"workflow_job":{"properties":{"id":{"type":"integer"},"labels":{"items":{"type":"string"},"type":"array"},"name":{"type":"string"},"run_id":{"type":"integer"}},"type":"object"}},"type":"object"},"forgeLaunched":{"properties":{"job":{"type":"integer"},"org":{"type":"string"},"repo":{"type":"string"},"runner":{"type":"string"}},"type":"object"},"framework.DocField":{"properties":{"default":{"type":"string"},"fetchFrom":{"type":"string"},"fieldname":{"type":"string"},"fieldtype":{"type":"string"},"hidden":{"type":"boolean"},"inListView":{"type":"boolean"},"label":{"type":"string"},"options":{"type":"string"},"readOnly":{"type":"boolean"},"reqd":{"type":"boolean"},"unique":{"type":"boolean"}},"type":"object"},"framework.DocPerm":{"properties":{"cancel":{"type":"boolean"},"create":{"type":"boolean"},"delete":{"type":"boolean"},"read":{"type":"boolean"},"role":{"type":"string"},"submit":{"type":"boolean"},"write":{"type":"boolean"}},"type":"object"},"framework.DocType":{"properties":{"autoname":{"type":"string"},"createdAt":{"format":"int64","type":"integer"},"fields":{"items":{"$ref":"#/components/schemas/framework.DocField"},"type":"array"},"immutable":{"type":"boolean"},"isSingle":{"type":"boolean"},"isSubmittable":{"type":"boolean"},"module":{"type":"string"},"name":{"type":"string"},"permissions":{"items":{"$ref":"#/components/schemas/framework.DocPerm"},"type":"array"},"titleField":{"type":"string"},"updatedAt":{"format":"int64","type":"integer"}},"type":"object"},"framework.Install":{"properties":{"created":{"items":{"type":"string"},"type":"array"},"existing":{"items":{"type":"string"},"type":"array"},"grown":{"description":"Grown names the existing DocTypes that gained the fields the module now\ndeclares and the org's stored definition lacked.","items":{"type":"string"},"type":"array"},"module":{"type":"string"}},"type":"object"},"framework.ModuleState":{"properties":{"doctypes":{"items":{"type":"string"},"type":"array"},"installed":{"items":{"type":"string"},"type":"array"},"module":{"type":"string"}},"type":"object"},"framework.docTypeList":{"properties":{"data":{"description":"Data is every DocType defined in the caller's org.","items":{"$ref":"#/components/schemas/framework.DocType"},"type":"array"}},"type":"object"},"framework.documentList":{"properties":{"data":{"description":"Data is the matching documents, newest-updated first unless order_by said\notherwise, each projected to the requested fields plus the envelope keys.","items":{"additionalProperties":{},"type":"object"},"type":"array"}},"type":"object"},"framework.module":{"properties":{"doctypes":{"items":{"type":"string"},"type":"array"},"enabled":{"description":"Enabled is whether this org has turned the module on. A module that is off\nanswers 404 on every DocType it owns (elective.go).","type":"boolean"},"module":{"type":"string"}},"type":"object"},"framework.moduleList":{"properties":{"data":{"description":"Data is every module compiled into this binary, with the DocTypes it installs\nand whether the caller's org has turned it on.","items":{"$ref":"#/components/schemas/framework.module"},"type":"array"}},"type":"object"},"framework.summaryView":{"properties":{"doctypes":{"description":"DocTypes is how many DocTypes the org has defined.","format":"int64","type":"integer"},"documents":{"description":"Documents is how many documents exist across them.","format":"int64","type":"integer"}},"type":"object"},"function.costLine":{"properties":{"key":{"description":"the function the line is about","type":"string"},"points":{"description":"one point per bucket, oldest first","items":{"$ref":"#/components/schemas/function.pointView"},"type":"array"}},"type":"object"},"function.definition":{"properties":{"code":{"description":"Code is the source to run, capped so one function cannot amplify the store.","type":"string"},"envNames":{"description":"EnvNames are the secret NAMES to mount. Values live in the secret store and\nare never carried here.","items":{"type":"string"},"type":"array"},"environment":{"description":"Environment is a second spelling of runtime, accepted so a console that says\n\"environment\" needs no translation.","type":"string"},"handler":{"description":"Handler is the entry point within the code.","type":"string"},"image":{"description":"Image names a prebuilt image to run instead of source.","type":"string"},"memoryLimit":{"description":"MemoryLimit is the memory the function runs with, defaulting to 256Mi. It is\nalso the multiplier on the GB-seconds compute charge.","type":"string"},"name":{"description":"Name is the function's org-unique handle and the segment that addresses it,\nmatching ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$. The names that would shadow a\ncollection route are reserved.","type":"string"},"namespace":{"description":"Namespace groups functions for display. It is cosmetic — the org is the\nisolation key — and is normalised to a DNS-safe label.","type":"string"},"runtime":{"description":"Runtime is the language the code runs under: node, python or deno.","type":"string"},"target":{"description":"Target is where the function runs: sandbox (the default) or fleet, the org's\nown GPU fleet. fleet supports runtime=python only.","type":"string"},"timeoutSec":{"description":"TimeoutSec is the per-invocation deadline, defaulting to 30 and clamped at\n900 — a larger value is capped rather than reset to the default.","format":"int64","type":"integer"}},"required":["name"],"type":"object"},"function.fnList":{"properties":{"functions":{"description":"Functions is one row per published function.","items":{"$ref":"#/components/schemas/function.functionView"},"type":"array"}},"type":"object"},"function.functionDetail":{"properties":{"avgDurationMs":{"description":"mean wall-clock of those runs","format":"double","type":"number"},"createdAt":{"description":"when it was first published","type":"string"},"endpoint":{"description":"the path that invokes it","type":"string"},"envCount":{"description":"how many secret NAMES it mounts; values are never carried","format":"int64","type":"integer"},"environment":{"description":"the language it runs under","type":"string"},"errors7d":{"description":"how many of those runs failed","format":"int64","type":"integer"},"image":{"description":"the prebuilt image it runs, when it runs one instead of source","type":"string"},"invocations7d":{"description":"runs in the last 7 days; ABSENT, never 0, when it has not run","format":"int64","type":"integer"},"lastDeployedAt":{"description":"when its code last changed","type":"string"},"memoryLimit":{"description":"the memory it runs with, and the multiplier on its compute charge","type":"string"},"name":{"description":"the function's org-unique handle","type":"string"},"namespace":{"description":"the display group it belongs to; the org is the isolation key","type":"string"},"recentInvocations":{"description":"RecentInvocations is its twenty most recent runs, newest first.","items":{"$ref":"#/components/schemas/function.invocationView"},"type":"array"},"secrets":{"description":"Secrets are the NAMES it mounts. Values are never read or returned.","items":{"type":"string"},"type":"array"},"status":{"description":"whether it is ready to serve","type":"string"},"successRate":{"description":"share of those runs that succeeded, 0..1","format":"double","type":"number"},"target":{"description":"where it runs: empty for the sandbox, \"fleet\" for the org's GPU fleet","type":"string"},"timeoutSec":{"description":"its per-invocation deadline","format":"int64","type":"integer"},"triggers":{"description":"Triggers is how this function is reached.","items":{"$ref":"#/components/schemas/function.triggerView"},"type":"array"}},"type":"object"},"function.functionView":{"properties":{"avgDurationMs":{"description":"mean wall-clock of those runs","format":"double","type":"number"},"createdAt":{"description":"when it was first published","type":"string"},"endpoint":{"description":"the path that invokes it","type":"string"},"envCount":{"description":"how many secret NAMES it mounts; values are never carried","format":"int64","type":"integer"},"environment":{"description":"the language it runs under","type":"string"},"errors7d":{"description":"how many of those runs failed","format":"int64","type":"integer"},"image":{"description":"the prebuilt image it runs, when it runs one instead of source","type":"string"},"invocations7d":{"description":"runs in the last 7 days; ABSENT, never 0, when it has not run","format":"int64","type":"integer"},"lastDeployedAt":{"description":"when its code last changed","type":"string"},"memoryLimit":{"description":"the memory it runs with, and the multiplier on its compute charge","type":"string"},"name":{"description":"the function's org-unique handle","type":"string"},"namespace":{"description":"the display group it belongs to; the org is the isolation key","type":"string"},"status":{"description":"whether it is ready to serve","type":"string"},"successRate":{"description":"share of those runs that succeeded, 0..1","format":"double","type":"number"},"target":{"description":"where it runs: empty for the sandbox, \"fleet\" for the org's GPU fleet","type":"string"},"timeoutSec":{"description":"its per-invocation deadline","format":"int64","type":"integer"}},"type":"object"},"function.invocationList":{"properties":{"invocations":{"description":"Invocations is one row per past run, newest first.","items":{"$ref":"#/components/schemas/function.invocationView"},"type":"array"}},"type":"object"},"function.invocationView":{"properties":{"durationMs":{"description":"how long it took","format":"int64","type":"integer"},"id":{"description":"the invocation's handle","type":"string"},"method":{"description":"the HTTP method that triggered it","type":"string"},"status":{"description":"how the run ended: ok, error or timeout","type":"string"},"statusCode":{"description":"Code is the status the function's OWN code answered with, which is not the\nstatus of the reply — a program can answer 500 through a healthy sandbox.","format":"int64","type":"integer"},"time":{"description":"when it ran, RFC3339","type":"string"}},"type":"object"},"function.invokeReq":{"properties":{"input":{"description":"Input is what the function is given on stdin. It is opaque to this surface.","type":"string"}},"type":"object"},"function.logLines":{"properties":{"logs":{"description":"Logs is that run's error text when it failed, else its output. It is empty\nwhen the function has never run.","type":"string"}},"type":"object"},"function.pointView":{"properties":{"t":{"description":"the bucket's start, RFC3339 (UTC)","type":"string"},"v":{"description":"how many invocations fell in it — a real count, never interpolated","format":"int64","type":"integer"}},"type":"object"},"function.secretList":{"properties":{"secrets":{"description":"Secrets is one row per distinct (namespace, name) a function mounts. Values\nare NEVER read or returned.","items":{"$ref":"#/components/schemas/function.secretView"},"type":"array"}},"type":"object"},"function.secretView":{"properties":{"mountedBy":{"description":"MountedBy is a function that mounts it.","type":"string"},"name":{"description":"Name is the environment variable the function mounts.","type":"string"},"namespace":{"description":"Namespace is the group the mounting function belongs to.","type":"string"}},"type":"object"},"function.statusBreakdown":{"properties":{"error":{"description":"invocations that ran and failed","format":"int64","type":"integer"},"success":{"description":"invocations whose code ran and wrote nothing to stderr","format":"int64","type":"integer"},"timeout":{"description":"invocations that hit their configured deadline","format":"int64","type":"integer"}},"type":"object"},"function.triggerList":{"properties":{"triggers":{"description":"Triggers is one row per function, describing how it is reached.","items":{"$ref":"#/components/schemas/function.triggerView"},"type":"array"}},"type":"object"},"function.triggerView":{"properties":{"enabled":{"description":"whether it currently fires","type":"boolean"},"functionName":{"description":"the function it calls","type":"string"},"id":{"description":"the trigger's handle","type":"string"},"name":{"description":"a human label for it","type":"string"},"target":{"description":"the path it calls","type":"string"},"type":{"description":"what kind of trigger it is; HTTP is the only one today","type":"string"}},"type":"object"},"function.usage":{"properties":{"costCents":{"description":"null — no per-invocation cost source","format":"int64","type":"integer"},"series":{"description":"one line per function that ran in the window","items":{"$ref":"#/components/schemas/function.costLine"},"type":"array"},"status":{"$ref":"#/components/schemas/function.statusBreakdown","description":"how those invocations ended"}},"type":"object"},"gateway.Policy":{"properties":{"cache_paths":{"additionalProperties":{"format":"int64","type":"integer"},"description":"CachePaths overrides CacheTTLSec per path PREFIX (key \"/v1/models\" → seconds).\nThe longest matching prefix wins.","type":"object"},"cache_ttl_sec":{"description":"CacheTTLSec is the org's default edge-cache TTL for its responses, in seconds;\n0 means no caching. Unset inherits the platform default.","format":"int64","type":"integer"},"cors_origins":{"description":"CORSOrigins is the PLATFORM-scope CORS allowlist EdgeCORS admits: an exact\norigin, a bare host, or a \"*.host\" wildcard. Writable only by a SuperAdmin —\nCORS is evaluated before identity, so it has no tenant to scope to.","items":{"type":"string"},"type":"array"},"methods":{"description":"Methods is the allowlist of HTTP methods the edge accepts for this org. Empty\nmeans all are accepted.","items":{"type":"string"},"type":"array"},"mode":{"description":"Mode is the abuse gate's posture for THIS scope: \"shadow\" scores traffic and\nrecords the verdict without acting on it, \"live\" enforces it. Unset means\nshadow.\n\nIt is the one per-org field that does NOT inherit. Every other field here\nlayers a platform default under the org's own value, which is right for a\ndefault: a tenant that sets no rate ceiling should get the platform's. Mode\nis not a default, it is an ARMING DECISION — it is what makes a statistical\njudgement start refusing real traffic — and inheriting it means arming one\nscope arms every tenant that never asked for it, without a write to their\nrow and without anything in their config changing. So a tenant is live only\nif that tenant's OWN row says live, and the platform row's mode governs\nexactly one scope: the anonymous lane, which has no tenant of its own.\n\nIt is also not self-service. Writing it requires SuperAdmin (see the\n/v1/gateway config op): the subject of an abuse control does not get to\nswitch the control off.","type":"string"},"org_cap":{"description":"OrgCap is the most this organization's ceiling may be, requests per minute.\nUnset, it is the platform's org_rpm, else 60,000. Only a SuperAdmin sets it: it\nis how the platform raises one organization above the default, and the\norganization a limit governs does not get to remove it. It does not inherit\nfrom the platform row. Read back, it is the cap in force.","format":"int64","type":"integer"},"org_rpm":{"description":"OrgRPM is the org's OWN authenticated rate ceiling, requests per minute, as\nScopeRateLimit enforces it across the deployment. An organization may lower it\nbut never raise it past its cap (org_cap); unset, the org is held to its cap.\nOn the platform row it is every organization's default cap, and it does not\ninherit into any organization's own row. Read back, it is the ceiling in\nforce: the org's own, clipped to its cap.","format":"int64","type":"integer"},"per_ip_rpm":{"description":"PerIPRPM is the PLATFORM-scope flood cap: requests admitted per WindowSec from\none client IP that presents no credential, or a credential that resolves to\nnobody. A request presenting a credential is held to ten times this from its\naddress until the credential is checked; a validated caller is then held by\nits key and org ceilings instead. SuperAdmin-only, same reason.","format":"int64","type":"integer"},"updated_at":{"description":"UpdatedAt is the unix second this policy row was last written. Server-stamped;\na client-supplied value is ignored.","format":"int64","type":"integer"},"updated_by":{"description":"UpdatedBy is the validated user id that wrote this policy row. Server-stamped;\na client-supplied value is ignored.","type":"string"},"window_sec":{"description":"WindowSec is the window PerIPRPM is counted over, in seconds. SuperAdmin-only.","format":"int64","type":"integer"}},"type":"object"},"gateway.TrafficCaller":{"properties":{"action":{"description":"Action is the verdict currently held against it, if any.","type":"string"},"cred":{"description":"Cred is the caller's key: a credential fingerprint (a per-process one-way\ndigest, not a key) for a validated caller, and \"ip:\u003caddr\u003e\" for one that\npresented no credential we could validate.","type":"string"},"failures":{"description":"Failures is how many ended 401 or 403.","format":"int64","type":"integer"},"held_until":{"description":"HeldUntil is when the held verdict lapses, unix seconds.","format":"int64","type":"integer"},"paths":{"description":"Paths is the approximate number of distinct paths it touched (max 64).","format":"int64","type":"integer"},"reason":{"description":"Reason is why that verdict was reached.","type":"string"},"requests":{"description":"Requests is its request count in the window.","format":"int64","type":"integer"}},"type":"object"},"gateway.TrafficView":{"properties":{"blind":{"description":"Blind is how many requests in the window carried no identity to attribute\nthem to — no validated credential and no client address. Non-zero on a\npublic plane means the client address is not reaching this process (a TCP\nload balancer with no PROXY protocol in front of it, typically), so this\nscope's callers cannot be told apart and nothing can be held against them.","format":"int64","type":"integer"},"callers":{"description":"Callers is the scope's busiest callers this window. A credentialed caller\nappears as a FINGERPRINT — a per-process one-way digest: enough to recognise\nthe same caller across requests, never enough to reconstruct the credential.","items":{"$ref":"#/components/schemas/gateway.TrafficCaller"},"type":"array"},"ceiling":{"description":"Ceiling is the most callers this scope may hold at once.","format":"int64","type":"integer"},"denied":{"description":"Denied is how many of them the gate refused.","format":"int64","type":"integer"},"lanes":{"additionalProperties":{"format":"int64","type":"integer"},"description":"Lanes is the request count per lane — agent, human, bot, unknown. This is\nthe split that separates a customer's automation from a scraper.","type":"object"},"mode":{"description":"Mode is the abuse gate's posture for this scope: \"shadow\" records the scorer's\naction without enforcing it, \"live\" enforces it.","type":"string"},"org":{"description":"Org is the scope this view was taken for — the validated principal's own,\nnever a value the caller supplied. Empty names the anonymous lane, the one\nscope that has no tenant.","type":"string"},"refused":{"description":"Refused is how many callers this scope's ceilings turned away in the window.","format":"int64","type":"integer"},"requests":{"description":"Requests is how many requests this scope made in the window.","format":"int64","type":"integer"},"screens":{"description":"Screens is how many of them were put to the scorer — the billable unit of\nthe risk product. Counted from the first request, whatever the SKU costs.","format":"int64","type":"integer"},"strain":{"description":"Strain is what this scope's ceilings are doing: \"clear\" below them, \"full\"\nat them, \"refuse\" once a caller has been turned away inside this window —\nwhich means that caller is UNMEASURED and the numbers here are a sample\nrather than a census. It is reported rather than logged because the\nalternative — a bound that degrades a scope silently — is the failure this\ndesign exists to rule out. No other scope can move it.","type":"string"},"tracked":{"description":"Tracked is how many callers this scope holds state for right now, and\nCeiling is the most it may hold. Tracked == Ceiling is the fact a bound\nthat binds cannot hide.","format":"int64","type":"integer"},"unscored":{"description":"Unscored is how many of those screens got NO answer — the scorer was absent,\nstuck, slow, erroring or silent. An unanswered screen allows ordinary\ntraffic, so this is the number that separates \"a quiet day\" from \"the judge\nstopped answering and nothing said so\".","format":"int64","type":"integer"},"window_sec":{"description":"WindowSec is the span the counts cover, in seconds.","format":"int64","type":"integer"}},"type":"object"},"git.blobJSON":{"properties":{"binary":{"description":"Binary marks content git could not treat as text; it comes back base64.","type":"boolean"},"content":{"description":"Content is the file's bytes, empty when Truncated.","type":"string"},"encoding":{"description":"Encoding is how Content is carried: \"utf8\" verbatim, or \"base64\".","type":"string"},"path":{"description":"Path is the file's repo-relative path.","type":"string"},"size":{"description":"Size is the file's byte length in the repo, whatever was returned below.","format":"int64","type":"integer"},"truncated":{"description":"Truncated marks a file past the 1 MiB view cap. No content is sent —\nclone the repo for it.","type":"boolean"}},"type":"object"},"git.commitJSON":{"properties":{"authorEmail":{"description":"AuthorEmail is the commit author's email.","type":"string"},"authorName":{"description":"AuthorName is the commit author's name.","type":"string"},"date":{"description":"Date is the author date, RFC 3339 UTC.","type":"string"},"message":{"description":"Message is the commit's SUBJECT — its first line only.","type":"string"},"sha":{"description":"SHA is the full commit hash.","type":"string"},"shortSha":{"description":"ShortSHA is the abbreviated hash a UI displays.","type":"string"}},"type":"object"},"git.commitsJSON":{"properties":{"commits":{"description":"Commits are newest first.","items":{"$ref":"#/components/schemas/git.commitJSON"},"type":"array"}},"type":"object"},"git.createReq":{"properties":{"description":{"description":"Description is a free-form blurb, max 4KiB.","type":"string"},"name":{"description":"Name is the repo's handle, unique within the scope, and the last segment of\nboth clone URLs. Must match ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$; a trailing\n\".git\" is stripped first. Required.","type":"string"},"project":{"description":"Project narrows the repo to a sub-scope of the org. Omit it to use the\ncaller's own X-Project-Id scope; it can never widen past the caller's org.","type":"string"},"public":{"description":"Public grants ANONYMOUS read (fetch) only; push and the whole control plane\nstay org-authed. Defaults to false.","type":"boolean"}},"type":"object"},"git.fileJSON":{"properties":{"content":{"description":"Content is the file's bytes, empty when Truncated.","type":"string"},"encoding":{"description":"Encoding is how Content is carried: \"utf8\" verbatim, or \"base64\".","type":"string"},"path":{"description":"Path is the file's repo-relative path.","type":"string"},"size":{"description":"Size is the file's byte length in the repo.","format":"int64","type":"integer"},"truncated":{"description":"Truncated marks a file past the read cap; no content is sent. A caller\nassembling a desired set must treat this as INCOMPLETE, never as empty.","type":"boolean"}},"type":"object"},"git.filesJSON":{"properties":{"files":{"description":"Files are the selected files, sorted by path. Directories are never\nreturned.","items":{"$ref":"#/components/schemas/git.fileJSON"},"type":"array"},"rev":{"description":"Rev is the full revision the ref resolved to — pin follow-up reads to it.","type":"string"}},"type":"object"},"git.gcOut":{"properties":{"maintained":{"description":"Maintained is always true; the call fails rather than reporting false.","type":"boolean"},"repo":{"description":"Repo is the repo that was repacked.","type":"string"},"sizeBytes":{"description":"SizeBytes is the size measured AFTER the repack — usually smaller, since\nrepacking drops the packs it supersedes.","format":"int64","type":"integer"}},"type":"object"},"git.jobView":{"properties":{"name":{"description":"Name is the job's id in the workflow document.","type":"string"},"pool":{"description":"Pool is the declared pool carrying every one of those labels, or empty\nwhen no pool does — which is the answer to \"why is nothing running\".","type":"string"},"runsOn":{"description":"RunsOn is the labels the job asked for.","items":{"type":"string"},"type":"array"}},"type":"object"},"git.link":{"properties":{"cloneUrl":{"description":"CloneURL is the address its history is fetched from and pushed to.","type":"string"},"name":{"description":"Name is the repository's name on its provider.","type":"string"},"owner":{"description":"Owner is the account the repository belongs to on its provider.","type":"string"},"provider":{"description":"Provider is \"github\", \"forge\" (git.hanzo.ai, Hanzo's own), or \"git\" for\nany other host.","type":"string"}},"type":"object"},"git.linkAll":{"properties":{"owner":{"description":"Owner is the GitHub account a repository named n is looked for under, as\ngithub.com/\u003cowner\u003e/\u003cn\u003e. Empty is the account the estate's table names for\nthe org; an org it does not name must give one.","type":"string"}},"type":"object"},"git.linkReq":{"properties":{"name":{"description":"Name is the repository, from the :name path segment. It is made when the\norg has none of that name.","type":"string"},"project":{"description":"Project is the sub-scope to make it in; empty uses the caller's own.","type":"string"},"source":{"description":"Source is where its history lives: an http(s) clone address, such as\nhttps://github.com/acme/widgets.git. Its host must let the caller read it.","type":"string"}},"type":"object"},"git.linked":{"properties":{"held":{"description":"Held are the repositories that hold their own history here, which a link\nwould hide.","items":{"type":"string"},"type":"array"},"linked":{"description":"Linked are the repositories it linked, each to its namesake on GitHub.","items":{"$ref":"#/components/schemas/git.repoView"},"type":"array"},"unmatched":{"description":"Unmatched are the repositories it left as they were, each with what GitHub\nanswered: no namesake readable as the caller is never replaced by a guess.","items":{"$ref":"#/components/schemas/git.unmatched"},"type":"array"}},"type":"object"},"git.mirrorList":{"properties":{"data":{"description":"Data holds the repo's outbound mirror targets.","items":{"$ref":"#/components/schemas/git.mirrorTargetView"},"type":"array"}},"type":"object"},"git.mirrorTargetReq":{"properties":{"host":{"description":"Host is an optional assertion of the target's hostname. The authoritative\nhost is the one in URL; a value that disagrees with it is refused.","type":"string"},"name":{"description":"Name is the repo whose advanced refs are pushed downstream, from the :name\npath segment.","type":"string"},"url":{"description":"URL is the downstream https git remote. Must be https to an allowlisted\nhost (github.com / gitlab.com); any embedded credentials are stripped.\nRequired.","type":"string"}},"type":"object"},"git.mirrorTargetView":{"properties":{"createdAt":{"description":"CreatedAt is RFC 3339 UTC.","type":"string"},"host":{"description":"Host is the target's lowercased hostname, taken from URL and never the body.","type":"string"},"id":{"description":"ID is the target's identifier (\"mir_…\"), the handle to remove it by.","type":"string"},"repo":{"description":"Repo is the repo whose advanced refs are pushed downstream.","type":"string"},"url":{"description":"URL is the canonical https remote, with any embedded credentials stripped.","type":"string"}},"type":"object"},"git.openReq":{"properties":{"base":{"description":"Base is the branch the work is proposed INTO, by short name. Defaults to\nthe repo's default branch, which is where a proposal goes when nobody says\notherwise.","type":"string"},"body":{"description":"Body is the longer description. Optional.","type":"string"},"head":{"description":"Head is the branch holding the work, by short name (agent/fix-503).\nRequired, and must already exist.","type":"string"},"name":{"description":"Name is the repo the proposal belongs to, from the :name path segment.","type":"string"},"title":{"description":"Title is the one-line summary of what is being proposed. Required.","type":"string"}},"type":"object"},"git.patchIn":{"properties":{"name":{"description":"Name is the repo to update, from the :name path segment.","type":"string"},"public":{"description":"Public flips anonymous read access. Omit it and the request is refused —\nthere is nothing else to update yet.","type":"boolean"}},"type":"object"},"git.poolDeclare":{"properties":{"labels":{"description":"Labels are what a workflow's `runs-on:` selects this pool by. A job is\nassigned to a pool that carries EVERY label it asked for.","items":{"type":"string"},"type":"array"},"name":{"description":"Name is the pool's handle in this org, e.g. \"evo\" or \"spark\".","type":"string"}},"type":"object"},"git.poolDeclared":{"properties":{"pool":{"$ref":"#/components/schemas/git.poolView","description":"Pool is the capacity that now exists."},"secret":{"description":"Secret is what a runner daemon presents to enter the pool. It is answered\nHERE AND NOWHERE ELSE — only a digest is stored — so a lost one is\nreplaced by declaring the pool again.","type":"string"}},"type":"object"},"git.poolList":{"properties":{"data":{"description":"Data is the org's declared pools, by name.","items":{"$ref":"#/components/schemas/git.poolView"},"type":"array"}},"type":"object"},"git.poolView":{"properties":{"createdAt":{"description":"CreatedAt is when the pool was declared, in unix seconds.","format":"int64","type":"integer"},"labels":{"description":"Labels are what a workflow's `runs-on:` selects this pool by.","items":{"type":"string"},"type":"array"},"name":{"description":"Name is the pool's handle in this org.","type":"string"},"runners":{"description":"Runners is how many daemons have entered the pool. Zero means the\ncapacity is declared and nothing has turned up to provide it.","format":"int64","type":"integer"}},"type":"object"},"git.pullList":{"properties":{"data":{"description":"Data holds the repo's pull requests, newest number first.","items":{"$ref":"#/components/schemas/git.pullView"},"type":"array"}},"type":"object"},"git.pullView":{"properties":{"author":{"description":"Author is the user who opened it; empty for a caller with no user.","type":"string"},"base":{"description":"Base is the branch the work is proposed into.","type":"string"},"body":{"description":"Body is the longer description; empty when none was given.","type":"string"},"createdAt":{"description":"CreatedAt is RFC 3339 UTC.","type":"string"},"head":{"description":"Head is the branch holding the work.","type":"string"},"mergedRev":{"description":"MergedRev is what base points at now that the merge landed. Empty while\nthe proposal is open.","type":"string"},"number":{"description":"Number is the proposal's per-repo handle, dense from 1.","format":"int64","type":"integer"},"repo":{"description":"Repo is the repository the proposal belongs to.","type":"string"},"state":{"description":"State is \"open\" or \"merged\".","type":"string"},"title":{"description":"Title is the one-line summary.","type":"string"},"updatedAt":{"description":"UpdatedAt is RFC 3339 UTC.","type":"string"}},"type":"object"},"git.pushFile":{"properties":{"content":{"description":"Content is the file's bytes, carried per Encoding.","type":"string"},"encoding":{"description":"Encoding is \"base64\", or \"utf-8\" (the default, also \"utf8\" / \"text\").","type":"string"},"path":{"description":"Path is repo-relative. Absolute or traversing paths, and paths inside .git,\nare refused. A path that changes CI (.hanzo/workflows, .github/workflows,\n.forgejo, .gitea) needs an org admin.","type":"string"}},"type":"object"},"git.pushReq":{"properties":{"branch":{"description":"Branch to advance; empty means \"main\". A fresh branch that is the repo's\nfirst also becomes HEAD.","type":"string"},"files":{"description":"Files are added to or overwritten on the branch tip — files already there\nand not listed SURVIVE. At least one, at most 5000, 32 MiB each.","items":{"$ref":"#/components/schemas/git.pushFile"},"type":"array"},"message":{"description":"Message is the commit message; empty gets a generated one.","type":"string"},"name":{"description":"Name is the repo to push into, from the :name path segment. It is CREATED\non first push if it does not exist.","type":"string"}},"type":"object"},"git.pushResp":{"properties":{"branch":{"description":"Branch is the branch that was advanced, resolved (never empty).","type":"string"},"cloneUrl":{"description":"CloneURL is the repo's HTTPS remote.","type":"string"},"commit":{"description":"Commit is the new commit's full hash.","type":"string"},"sshUrl":{"description":"SSHURL is the repo's scp-style SSH remote.","type":"string"}},"type":"object"},"git.readmeJSON":{"properties":{"content":{"description":"Content is the file's text, verbatim and unrendered.","type":"string"},"encoding":{"description":"Encoding is always \"utf8\" — a README is text by definition.","type":"string"},"path":{"description":"Path is the file the README was found at (README.md, README, …).","type":"string"}},"type":"object"},"git.refJSON":{"properties":{"name":{"description":"Name is the short ref name (\"main\", \"v1.2.0\"), not the full refs/… path.","type":"string"},"sha":{"description":"SHA is the full commit hash the ref resolves to.","type":"string"}},"type":"object"},"git.refsJSON":{"properties":{"branches":{"description":"Branches are the repo's heads; empty on a repo with no commits.","items":{"$ref":"#/components/schemas/git.refJSON"},"type":"array"},"default":{"description":"Default is the branch name a caller gets when it asks for no ref.","type":"string"},"tags":{"description":"Tags are the repo's tags; empty when there are none.","items":{"$ref":"#/components/schemas/git.refJSON"},"type":"array"}},"type":"object"},"git.repoList":{"properties":{"data":{"description":"Data holds the repos in scope, most recently updated first.","items":{"$ref":"#/components/schemas/git.repoView"},"type":"array"}},"type":"object"},"git.repoView":{"properties":{"branches":{"description":"Branches are the repo's branch names. Read live, so the detail view carries\nthem and a list row does not.","items":{"type":"string"},"type":"array"},"cloneUrl":{"description":"CloneURL is the HTTPS smart-HTTP remote `git clone` takes.","type":"string"},"createdAt":{"description":"CreatedAt is RFC 3339 UTC.","type":"string"},"defaultBranch":{"description":"DefaultBranch is where HEAD points on a fresh repo (\"main\").","type":"string"},"description":{"description":"Description is the caller-supplied blurb (max 4KiB).","type":"string"},"head":{"description":"Head is the resolved HEAD commit, empty on an empty repo.","type":"string"},"id":{"description":"ID is the repo's stable, prefixed identifier (\"repo_\" + 128 random bits).","type":"string"},"link":{"$ref":"#/components/schemas/git.link","description":"Link is where the repo's history lives when it is on another host: reads\nare served from a cache filled from there and pushes go there. Absent for\na repo whose history is here."},"name":{"description":"Name is the org-unique handle, and the last path segment of both URLs below.","type":"string"},"org":{"description":"Org owns the repo — the gateway-minted X-Org-Id, and the isolation key.","type":"string"},"project":{"description":"Project is the optional sub-scope the repo lives in; absent for the org's\ndefault scope.","type":"string"},"public":{"description":"Public grants ANONYMOUS read (fetch) only; push and the whole control plane\nstay org-authed.","type":"boolean"},"sizeBytes":{"description":"SizeBytes is the repo's measured on-disk size, re-measured on create, after\neach push, and after a gc. This is the number billing meters.","format":"int64","type":"integer"},"sshUrl":{"description":"SSHURL is the scp-style SSH remote (git@host:org/repo.git).","type":"string"},"updatedAt":{"description":"UpdatedAt is RFC 3339 UTC, empty until the first write.","type":"string"}},"type":"object"},"git.runStart":{"properties":{"ref":{"description":"Ref is the branch to run; empty means the repository's default.","type":"string"},"repo":{"description":"Repo is the repository to run.","type":"string"}},"type":"object"},"git.runnerList":{"properties":{"data":{"description":"Data is the daemons registered into this org's pools, newest first.","items":{"$ref":"#/components/schemas/git.runnerView"},"type":"array"}},"type":"object"},"git.runnerView":{"properties":{"ephemeral":{"description":"Ephemeral means the daemon takes ONE job and exits, so it is not expected\nback and its absence is not a fault.","type":"boolean"},"labels":{"description":"Labels are what the daemon last said it can do.","items":{"type":"string"},"type":"array"},"lastActive":{"description":"LastActive is when it was last EXECUTING a job, in unix seconds. It lags\nLastOnline on an idle daemon, which is how the two differ.","format":"int64","type":"integer"},"lastOnline":{"description":"LastOnline is when it last called at all, in unix seconds.","format":"int64","type":"integer"},"name":{"description":"Name is what the daemon called itself when it registered.","type":"string"},"pool":{"description":"Pool is the declared capacity it entered.","type":"string"},"version":{"description":"Version is the runner build the daemon last reported.","type":"string"}},"type":"object"},"git.subscribeReq":{"properties":{"channel":{"description":"Channel is the Slack channel the notifier posts to — an id (C…/G…), a\n#name, or a bare name. Required.","type":"string"},"events":{"description":"Events narrows delivery to these lifecycle kinds (push.landed,\ndeploy.live, deploy.failed). Omit it to receive every deliverable kind; a\nkind that is never posted to Slack is refused rather than silently dropped.","items":{"type":"string"},"type":"array"},"name":{"description":"Name is the repo to subscribe, from the :name path segment.","type":"string"}},"type":"object"},"git.subscriptionList":{"properties":{"data":{"description":"Data holds the repo's subscriptions.","items":{"$ref":"#/components/schemas/git.subscriptionView"},"type":"array"}},"type":"object"},"git.subscriptionView":{"properties":{"channel":{"description":"Channel is the Slack channel id or name the notifier posts to.","type":"string"},"createdAt":{"description":"CreatedAt is RFC 3339 UTC.","type":"string"},"events":{"description":"Events is the kind filter; absent means every deliverable kind.","items":{"type":"string"},"type":"array"},"id":{"description":"ID is the subscription's identifier (\"sub_…\"), the handle to delete it by.","type":"string"},"repo":{"description":"Repo is the repo whose lifecycle events are delivered.","type":"string"}},"type":"object"},"git.treeEntryJSON":{"properties":{"mode":{"description":"Mode is the octal git file mode (\"100644\", \"040000\", \"120000\").","type":"string"},"name":{"description":"Name is the entry's own name, no directory part.","type":"string"},"path":{"description":"Path is the entry's full repo-relative path.","type":"string"},"size":{"description":"Size is the file's byte length; 0 for a directory.","format":"int64","type":"integer"},"type":{"description":"Type is \"tree\" for a directory, \"blob\" for a file.","type":"string"}},"type":"object"},"git.treeJSON":{"properties":{"entries":{"description":"Entries are the immediate children, directories before files.","items":{"$ref":"#/components/schemas/git.treeEntryJSON"},"type":"array"}},"type":"object"},"git.unmatched":{"properties":{"name":{"description":"Name is the repository.","type":"string"},"reason":{"description":"Reason is what GitHub answered about its namesake.","type":"string"}},"type":"object"},"git.usageRepo":{"properties":{"name":{"description":"Name is the repo's org-unique handle.","type":"string"},"project":{"description":"Project is the sub-scope the repo lives in; absent for the default scope.","type":"string"},"sizeBytes":{"description":"SizeBytes is the repo's on-disk size at its last measurement.","format":"int64","type":"integer"}},"type":"object"},"git.usageView":{"properties":{"org":{"description":"Org the rollup is for.","type":"string"},"repos":{"description":"Repos is every repo the org owns, across every project sub-scope.","items":{"$ref":"#/components/schemas/git.usageRepo"},"type":"array"},"totalBytes":{"description":"TotalBytes is the sum over Repos — the org's whole git footprint.","format":"int64","type":"integer"}},"type":"object"},"git.workflowList":{"properties":{"data":{"description":"Data is the workflows the repository declares at the ref.","items":{"$ref":"#/components/schemas/git.workflowView"},"type":"array"}},"type":"object"},"git.workflowRun":{"properties":{"actor":{"description":"Actor is who caused it.","type":"string"},"commit":{"description":"Commit is the commit being run, in full.","type":"string"},"createdAt":{"description":"CreatedAt is when the run was opened, in unix seconds.","format":"int64","type":"integer"},"event":{"description":"Event is what caused the run, e.g. \"push\".","type":"string"},"id":{"description":"ID addresses this run.","type":"string"},"number":{"description":"Number is the run's position in its repository, counting from 1 — the\nhandle a person uses (\"#4\").","format":"int64","type":"integer"},"ref":{"description":"Ref is the full ref, e.g. \"refs/heads/main\".","type":"string"},"repo":{"description":"Repo is the repository the run is for.","type":"string"},"status":{"description":"Status is waiting, running, success, failure, cancelled or skipped.","type":"string"},"updatedAt":{"description":"UpdatedAt is when its status last changed, in unix seconds.","format":"int64","type":"integer"},"workflow":{"description":"Workflow is the path of the document being run, e.g.\n\".hanzo/workflows/ci.yml\".","type":"string"}},"type":"object"},"git.workflowRuns":{"properties":{"data":{"description":"Data is the runs in scope, newest first.","items":{"$ref":"#/components/schemas/git.workflowRun"},"type":"array"}},"type":"object"},"git.workflowView":{"properties":{"fault":{"description":"Fault is why this document cannot run at all, when it cannot be read.","type":"string"},"jobs":{"description":"Jobs is what it declares, and where each would run.","items":{"$ref":"#/components/schemas/git.jobView"},"type":"array"},"name":{"description":"Name is the document's path in the repository.","type":"string"}},"type":"object"},"git.workspaceView":{"properties":{"login":{"description":"Login is the caller's forge account in a made workspace.","type":"string"},"made":{"description":"Made says the platform made it for the org; false is the estate's.","type":"boolean"},"owner":{"description":"Owner is the forge namespace.","type":"string"}},"type":"object"},"graph.graphAnswerIn":{"properties":{"as_known":{"description":"AsKnown is how much this plane had heard, RFC 3339: the answer as it would\nhave been given then, which is what makes a past answer reproducible.\nAbsent is now.","type":"string"},"as_of":{"description":"AsOf answers from the graph as it stood at an instant of the world, RFC\n3339: what held then. Absent is now.","type":"string"},"question":{"description":"Question is what to answer, in words, 1000 bytes at most. Its words also\ndecide which communities are read first, so naming the things it is about\nis what aims it.","type":"string"}},"required":["question"],"type":"object"},"graph.graphAnswerOut":{"properties":{"answer":{"description":"Answer is the answer, in prose.","type":"string"},"as_known":{"description":"AsKnown is the knowledge instant it was taken at, RFC 3339, the same way.","type":"string"},"as_of":{"description":"AsOf is the instant the graph was read at, RFC 3339: the one asked for, or\nthe server's clock when none was.","type":"string"},"asked":{"description":"Asked is how many communities were read.","format":"int64","type":"integer"},"assertions":{"description":"Assertions are the IDs of every assertion the answer rests on, ascending.","items":{"type":"string"},"type":"array"},"calls":{"description":"Calls is how many model calls the answer made, each billed to the calling\norganization.","format":"int64","type":"integer"},"clipped":{"description":"Clipped says the answer did not read all it gathered: a community held\nmore facts than one call carries, or more members than one answer reads,\nand kept the ones the question named and then the most connected; a member\nheld more than 64 assertions and kept its newest; or the findings held more\nthan the answering call carries and kept the highest scored.","type":"boolean"},"communities":{"description":"Communities are every community the answer rests on, ascending.","items":{"format":"int64","type":"integer"},"type":"array"},"findings":{"description":"Findings are the findings the answer cites, most relevant first.","items":{"$ref":"#/components/schemas/graph.graphFinding"},"type":"array"},"grounded":{"description":"Grounded is false when no community held a fact bearing on the question,\nor the findings did not answer it. Answer is then empty: an answer resting\non nothing is not one this plane gives.","type":"boolean"},"skipped":{"description":"Skipped is how many were not, because one answer makes at most eight map\ncalls and reads at most 2048 entities. They are the ones the question's\nwords ranked last.","format":"int64","type":"integer"}},"type":"object"},"graph.graphAssertIn":{"properties":{"assertions":{"description":"Assertions is the batch. Each member is judged on its own: one refusal\ndoes not discard the rest, because a caller redelivering five facts must\nnot lose four of them to one malformed fifth.","items":{"$ref":"#/components/schemas/graph.graphFact"},"type":"array"}},"required":["assertions"],"type":"object"},"graph.graphAssertOut":{"properties":{"duplicate":{"description":"Duplicate is how many members this plane already held. A redelivery\ncollides on its content address and is counted here, not refused: it is\nthe success a retrying caller depends on.","format":"int64","type":"integer"},"reasons":{"description":"Reasons names why each refused member was refused, in the order sent.","items":{"type":"string"},"type":"array"},"recorded":{"description":"Recorded is how many members became new rows.","format":"int64","type":"integer"},"refused":{"description":"Refused is how many members were turned away — a missing entity, a\ntimestamp that is not RFC 3339, a confidence outside [0,1], a relation\nwhose declared domain or range the entity's type does not meet, or a\ndeclaration from a caller who is not an admin of the organization. The\nrest of the batch was still recorded; a batch refused whole answers 400,\nor 403 when a member of it was refused for want of authority.","format":"int64","type":"integer"}},"type":"object"},"graph.graphAtom":{"properties":{"object":{"description":"Object is its second argument. Absent for a predicate the rules use with\none argument.","type":"string"},"predicate":{"description":"Predicate is the relation the tuple is of.","type":"string"},"subject":{"description":"Subject is its first argument.","type":"string"}},"type":"object"},"graph.graphChange":{"properties":{"now":{"$ref":"#/components/schemas/graph.wireFact","description":"Now is the assertion in force at To: the claim that replaced Was, or,\nfor a retraction, the retraction itself — which is who withdrew it and on\nwhat evidence."},"was":{"$ref":"#/components/schemas/graph.wireFact","description":"Was is the assertion in force at From."}},"type":"object"},"graph.graphCommunitiesIn":{"properties":{"as_known":{"description":"AsKnown is how much this plane had heard, RFC 3339: the answer as it would\nhave been given then, which is what makes a past answer reproducible.\nAbsent is now.","type":"string"},"as_of":{"description":"AsOf partitions the graph as it stood at an instant of the world, RFC\n3339: the edges that held then. Absent is now.","type":"string"},"level":{"description":"Level is how fine a partition to answer with. 0, the default, is the\ncoarsest — the partition detection stops at, where modularity is highest —\nand each level above it is the pass before, finer. `levels` in the answer\nsays how many there are.","format":"int64","type":"integer"},"relation":{"description":"Relation narrows the graph to one edge relation, by its key. Absent\npartitions every edge.","type":"string"}},"type":"object"},"graph.graphCommunitiesOut":{"properties":{"as_known":{"description":"AsKnown is the knowledge instant it was taken at, RFC 3339, the same way.","type":"string"},"as_of":{"description":"AsOf is the instant the graph was read at, RFC 3339: the one asked for, or\nthe server's clock when none was.","type":"string"},"bound":{"description":"Bound is the most members listed in one answer.","format":"int64","type":"integer"},"ceiling":{"description":"Ceiling is the most edge assertions one partition reads — every row, so an\nedge three sources asserted counts three times. A graph over it is refused\nrather than partitioned from part of itself.","format":"int64","type":"integer"},"communities":{"description":"Communities are the communities, largest first.","items":{"$ref":"#/components/schemas/graph.graphCommunity"},"type":"array"},"edges":{"description":"Edges is how many distinct undirected edges were partitioned.","format":"int64","type":"integer"},"entities":{"description":"Entities is how many entities the edge graph holds. An entity with no edge\nin force at AsOf is in no community.","format":"int64","type":"integer"},"level":{"description":"Level is the level answered.","format":"int64","type":"integer"},"levels":{"description":"Levels is how many levels detection found. A graph where no two entities\nbelong together more than chance has one, of single entities.","format":"int64","type":"integer"},"modularity":{"description":"Modularity is Newman's Q of this level's partition, from -0.5 to 1: the\nshare of edge weight inside communities, less what chance would put there.\nAbove about 0.3 is usually read as real structure rather than chance.","format":"double","type":"number"},"truncated":{"description":"Truncated says the member lists stop at Bound entities in all, filled in\ncommunity order. Every community is still listed with its full Size.","type":"boolean"}},"type":"object"},"graph.graphCommunity":{"properties":{"id":{"description":"ID numbers the community by size, largest first, then by its lowest key.\nThe same graph at the same instant and level numbers it the same way every\ntime; another instant may not.","format":"int64","type":"integer"},"members":{"description":"Members are the entities in it, in key order.","items":{"type":"string"},"type":"array"},"size":{"description":"Size is how many entities belong to it, whether or not all are listed.","format":"int64","type":"integer"}},"type":"object"},"graph.graphConclusion":{"properties":{"decay":{"description":"Decay is the product of the confidences of the distinct statements the\nproof rests on: how much certainty survives the derivation. Absent unless\nevery one states a confidence above zero and the proof has at most 1024\natoms.","format":"double","type":"number"},"from":{"description":"From is the latest start among the statements the proof rests on, RFC\n3339. What a rule negates has no statement to date it, so a conclusion\ndrawn through a negation may not have held from then.","type":"string"},"object":{"description":"Object is its second argument. Absent for a predicate the rules use with\none argument.","type":"string"},"predicate":{"description":"Predicate is the relation concluded.","type":"string"},"rule":{"description":"Rule is the rule that concluded it, `rule:\u003cname\u003e`.","type":"string"},"rule_id":{"description":"RuleID is the ID of the assertion stating that rule's text as it was in\nforce.","type":"string"},"subject":{"description":"Subject is the tuple's first argument.","type":"string"},"supports":{"description":"Supports are the rule's positive atoms as they matched, in the order the\nrule writes them. What the rule negates is absent at the point and has no\nsupport to cite.","items":{"$ref":"#/components/schemas/graph.graphSupport"},"type":"array"},"until":{"description":"Until is the earliest until any of those statements states, RFC 3339.\nAbsent is open. A statement a later assertion ends is a later question,\nasked at a later as_of.","type":"string"},"weakest":{"description":"Weakest is the ID of the statement with the lowest confidence among them,\nthe first on a tie: the link the conclusion is only as strong as. Absent\nexactly when Decay is.","type":"string"}},"type":"object"},"graph.graphDeclared":{"properties":{"cardinality":{"description":"Cardinality is how many values the relation holds at once: one, or many.\nAbsent is the default — one for a property, many for an edge.","type":"string"},"domain":{"description":"Domain is the type the entity asserting it must have. Absent is any.","type":"string"},"range":{"description":"Range is the type the entity it points at must have; a relation with a\nrange is an edge. Absent is any.","type":"string"},"relation":{"description":"Relation is the relation declared, without its `relation:` prefix.","type":"string"}},"type":"object"},"graph.graphDeriveIn":{"properties":{"as_known":{"description":"AsKnown is how much this plane had heard, RFC 3339 — of the statements\nand of the rules — so a past answer is reproducible. Absent is now.","type":"string"},"as_of":{"description":"AsOf derives from the graph as it stood at an instant of the world, RFC\n3339: the statements that held then. Absent is now.","type":"string"},"file":{"description":"File files each tuple Derived lists as an assertion: (subject, predicate,\nobject) from the instant it was derived at, open, its source the rule,\nits evidence the rule's ID, its confidence the decay, and an edge when\nthe object is an entity by its proof. It requires an admin of the\norganization, the graph as it stands now — no as_of, as_known or\nwithout — and predicates with two arguments. It is refused whole when a\nrelation that holds one value at a time would keep only one of the\nvalues a subject is concluded or asserted to have, and when a conclusion\nis about a `relation:` or `rule:` key. Each is judged as any assertion\nis, and the write is on the audit trail before it commits. A filed\nconclusion is an assertion like any other: it does not fall when a\nsupport later does.","type":"boolean"},"predicates":{"description":"Predicates are what to derive: every tuple the rules in force conclude of\neach, with its proof. Each must be the head of a rule in force, asserted\nas (`rule:\u003cname\u003e`, `rule`, `\u003ctext\u003e`) — for example `ancestor(X, Z) :-\nparent(X, Y), ancestor(Y, Z)`. At least one, at most 256.","items":{"type":"string"},"type":"array"},"without":{"description":"Without is assertion IDs, of statements or of rules, to derive without as\nthough they had never been filed. The derivation then runs twice, and\nLost and Gained say what that changes. Each must be a row this derivation\nreads. At most 256.","items":{"type":"string"},"type":"array"}},"type":"object"},"graph.graphDeriveOut":{"properties":{"as_known":{"description":"AsKnown is the knowledge instant it was taken at, RFC 3339, the same way.","type":"string"},"as_of":{"description":"AsOf is the instant the graph was read at, RFC 3339: the one asked for, or\nthe server's clock when none was.","type":"string"},"bound":{"description":"Bound is the most tuples one evaluation derives.","format":"int64","type":"integer"},"cut":{"description":"Cut names the bound that stopped it: `tuples`, at Bound tuples derived,\nor `steps`, at Steps rows examined. Absent exactly when Truncated is\nfalse.","type":"string"},"derived":{"description":"Derived is every tuple of the predicates asked for that the rules derive,\nordered by predicate, subject and object. A tuple an assertion already\nstates is asserted, not derived, and is not here.","items":{"$ref":"#/components/schemas/graph.graphConclusion"},"type":"array"},"filed":{"$ref":"#/components/schemas/graph.graphAssertOut","description":"Filed is what filing Derived did, member by member as an assertion batch\nreports it. Absent unless file was asked."},"gained":{"description":"Gained is each that holds only without them — a negation those\nassertions had been refuting. Empty when Without is absent.","items":{"$ref":"#/components/schemas/graph.graphAtom"},"type":"array"},"lemmas":{"description":"Lemmas is every derived tuple of any other predicate a proof in Derived\ncites, in the same order, so every support that is not an assertion can\nbe followed to a proof.","items":{"$ref":"#/components/schemas/graph.graphConclusion"},"type":"array"},"lost":{"description":"Lost is each tuple of the predicates asked for, asserted or derived, that\nholds with everything and not without the assertions Without names.\nEmpty when Without is absent.","items":{"$ref":"#/components/schemas/graph.graphAtom"},"type":"array"},"steps":{"description":"Steps is the most rows one evaluation's joins examine.","format":"int64","type":"integer"},"truncated":{"description":"Truncated says a bound stopped the evaluation before its fixpoint. Every\ntuple listed still holds; some that hold are missing.","type":"boolean"}},"type":"object"},"graph.graphDiffIn":{"properties":{"entity":{"description":"Entity narrows the diff to what was asserted about one entity. Absent\ndiffs the whole graph, bounded by Limit.","type":"string"},"from":{"description":"From is the earlier instant of the world, RFC 3339. What held here is\nthe baseline, so a statement beginning exactly at From is part of it and\nnot a change. Absent is To: the diff is then of what was heard, not of\nwhat happened.","type":"string"},"from_known":{"description":"FromKnown is how much this plane had heard at the baseline, RFC 3339.\nAbsent is ToKnown: the diff is then of the world, as known once.","type":"string"},"limit":{"description":"Limit caps how many (entity, relation) pairs are examined, in key order.\nAbsent, zero, or anything above the walk ceiling is the ceiling.","format":"int64","type":"integer"},"to":{"description":"To is the later instant of the world, RFC 3339, and may not precede From.\nA statement beginning or ending exactly at To is in the diff. Absent is\nnow.","type":"string"},"to_known":{"description":"ToKnown is how much it had heard at the later point, RFC 3339, and may\nnot precede FromKnown. Absent is now.","type":"string"}},"type":"object"},"graph.graphDiffOut":{"properties":{"asserted":{"description":"Asserted is each statement holding at To that did not at From.","items":{"$ref":"#/components/schemas/graph.wireFact"},"type":"array"},"bound":{"description":"Bound is how many pairs this diff examined at most.","format":"int64","type":"integer"},"from":{"description":"From is the earlier instant, RFC 3339, echoed.","type":"string"},"from_known":{"description":"FromKnown is the knowledge instant of the baseline, RFC 3339.","type":"string"},"retracted":{"description":"Retracted is each statement that held at From and no longer does at To,\nwith what ended it as Now: the retraction, the later value, or the\nstatement itself when its own until did.","items":{"$ref":"#/components/schemas/graph.graphChange"},"type":"array"},"superseded":{"description":"Superseded is each property whose value at From was replaced by a\ndifferent one at To, once per pair however many came in between.","items":{"$ref":"#/components/schemas/graph.graphChange"},"type":"array"},"to":{"description":"To is the later instant, RFC 3339: the one asked for, or the server's\nclock when none was.","type":"string"},"to_known":{"description":"ToKnown is the knowledge instant of the later point, RFC 3339.","type":"string"},"truncated":{"description":"Truncated says more pairs gathered assertions in the interval than Bound,\nor that one pair holds more than a single read returns. Narrow by entity\nor by a shorter interval to see the rest.","type":"boolean"}},"type":"object"},"graph.graphEraseIn":{"properties":{"entity":{"description":"Entity is the key to erase. Every assertion ABOUT it and every edge\npointing AT it is removed, under every spelling it may have been filed\nunder — its NFC key, that key decomposed, and the bytes sent — so a subject\nfiled before keys were folded goes with the rest; a property whose scalar\nhappens to spell it is not a reference and stays. Required, 512 bytes at\nmost.","type":"string"},"reason":{"description":"Reason is why, as the audit trail will keep it — a request number, a legal\nbasis. It outlives the erasure, so it may not contain the entity: refused\nwhen it does. Required, 512 bytes at most.","type":"string"}},"required":["entity","reason"],"type":"object"},"graph.graphEraseOut":{"properties":{"at":{"description":"At is the instant of the erasure, RFC 3339, and the time on its audit\nrecord.","type":"string"},"by":{"description":"By is the identity that erased — `owner` or `owner/user` — from the\nvalidated principal.","type":"string"},"complete":{"description":"Complete is true only when no store may still hold the subject: every\nstore erased or absent and nothing Remaining. While a store is\nunsupported it is false, and that store is handled out of band before\nthe erasure is done.","type":"boolean"},"digest":{"description":"Digest is SHA-256, hex, over IDs in their ascending order, each written\n`\u003clength\u003e:\u003cid\u003e` — the same content address an assertion's own ID is. The\naudit trail records it in place of the ids, so the receipt verifies\nagainst the trail and the trail names nothing.","type":"string"},"entity":{"description":"Entity is the key that was erased, folded as every key here is (NFC, no\ncontrol characters) and echoed so a stored receipt says what it is for.\nThis plane keeps no copy of it.","type":"string"},"ids":{"description":"IDs are the content addresses of the assertions removed, ascending.","items":{"type":"string"},"type":"array"},"remaining":{"description":"Remaining is how many assertions still name the entity because one call\nremoves at most ten thousand. Non-zero means call again; each call is its\nown receipt.","format":"int64","type":"integer"},"sources":{"description":"Sources are the documents the removed assertions were filed from. This\nplane does not own them: ingesting one again files the subject again.","items":{"type":"string"},"type":"array"},"stores":{"description":"Stores is every store in this deployment that may hold what the org says\nabout the subject, and what happened in each: this graph first, then the\nstores this op cannot reach.","items":{"$ref":"#/components/schemas/graph.graphStore"},"type":"array"}},"type":"object"},"graph.graphExtractOut":{"properties":{"refused":{"description":"Refused are the relations found that filing would refuse — a subject or\nobject whose type is not the relation's declared domain or range, or a\ndeclaration from a caller who is not an admin — each carrying its reason.\nIngest records none of them.","items":{"$ref":"#/components/schemas/graph.graphTriple"},"type":"array"},"triples":{"description":"Triples are the relations found that the caller may file, in the order\nthe document states them.","items":{"$ref":"#/components/schemas/graph.graphTriple"},"type":"array"}},"type":"object"},"graph.graphFact":{"properties":{"at":{"description":"At is when the thing was so, RFC 3339. Required, and refused when it sits\nmore than five minutes ahead of the server clock — an assertion dated\nfurther out would never mature and would skew every read until it did.","type":"string"},"confidence":{"description":"Confidence in [0,1]. A tie-breaker within the order, never a substitute\nfor it. Absent is 0, the weakest an assertion can be.","format":"double","type":"number"},"entity":{"description":"Entity is the thing being described, in the organization's own namespace.\nIt is not created: an entity exists because something was asserted about it.\nIt is a key, folded to Unicode NFC with control characters removed, so two\nspellings of one name are one entity. An entity named `relation:\u003cname\u003e` is\nthat relation's declaration and one named `rule:\u003cname\u003e` is a rule\n(graphDerive), and only an admin of the organization may assert anything\nof either. Required, 512 bytes at most.","type":"string"},"evidence":{"description":"Evidence points at the record this claim came from, 512 bytes at most. An\nassertion without one is admitted and carries no defence.","type":"string"},"names":{"description":"Names says the value is an entity. A walk reads only the edges, so this is\na declaration and never a guess about the value's shape.","type":"boolean"},"relation":{"description":"Relation is what is being asserted — `depends`, `owner`, `same`, `title`\n— and a key, folded as Entity is. It is open until the organization\ndeclares it: once `relation:\u003cname\u003e` has a `domain` or `range` in force,\nthe entity's `type` (and, for range, the value's) must match it. Required,\n128 bytes at most.","type":"string"},"seen":{"description":"Seen is when this assertion became knowable, RFC 3339. Defaults to At and\nmay not precede it. It is provenance and it decides nothing: the instant\nevery read uses is derived as the later of Seen and the server's own clock.","type":"string"},"source":{"description":"Source names who asserted. Required, because an assertion nobody is named\nfor cannot be weighed against one that is. Open text: this plane ranks no\nsource above another.","type":"string"},"until":{"description":"Until is when the thing stopped being so, RFC 3339, and must follow At.\nAbsent is open: the statement holds until something ends it. A term of\noffice, an employment, a membership are At and Until on one statement.","type":"string"},"value":{"description":"Value is what the relation points at. When Names is true it is another\nentity's key, folded as Entity is, and the assertion is an EDGE; otherwise\nit is a scalar, kept byte for byte, and the assertion is a property. 2048\nbytes at most, or 512 when it names an entity.","type":"string"}},"required":["entity","relation","at","source"],"type":"object"},"graph.graphFinding":{"properties":{"assertions":{"description":"Assertions are the IDs of the assertions it cites, each a row a read of\nthis graph returns.","items":{"type":"string"},"type":"array"},"communities":{"description":"Communities are the communities of the facts it cites, at level 0 of the\npartition at AsOf — the ids POST /v1/graph/communities answers with.","items":{"format":"int64","type":"integer"},"type":"array"},"score":{"description":"Score is how much the model judged it helps, 1 to 100.","format":"int64","type":"integer"},"text":{"description":"Text is what the model found, in its words.","type":"string"}},"type":"object"},"graph.graphNeighborsIn":{"properties":{"as_known":{"description":"AsKnown is how much this plane had heard, RFC 3339: the answer as it would\nhave been given then, which is what makes a past answer reproducible.\nAbsent is now.","type":"string"},"as_of":{"description":"AsOf walks the graph as it stood at an instant of the world, RFC 3339:\nthe edges that held then. Absent is now.","type":"string"},"depth":{"description":"Depth is how many hops. Absent is one.","format":"int64","type":"integer"},"direction":{"description":"Direction is out, in or both. Out follows an edge from its entity to its\nvalue — what the node points at; in follows it the other way — what points\nat the node; both is the union of the two, not a third rule. Absent is out.","type":"string"},"relation":{"description":"Relation narrows the walk to one edge relation. Absent follows all. Only\nedges IN FORCE are ever followed — the assertion that wins its (entity,\nrelation) at the instant — so a superseded or retracted edge is not a hop,\nand neither is a property.","type":"string"},"seeds":{"description":"Seeds is where the walk starts. At least one.","items":{"type":"string"},"type":"array"}},"required":["seeds"],"type":"object"},"graph.graphNeighborsOut":{"properties":{"bound":{"description":"Bound is the ceiling this walk was held to, the same for every caller, so\nTruncated can be read against a number rather than guessed at.","format":"int64","type":"integer"},"depth":{"description":"Depth is the deepest hop count actually reached. It is at most the depth\nasked for, and smaller when the walk ran out of edges first.","format":"int64","type":"integer"},"entities":{"description":"Entities is everything reached, the seeds included, ordered by the fewest\nhops that reach each one and then by key.","items":{"type":"string"},"type":"array"},"truncated":{"description":"Truncated says the bound stopped the walk. The bound is part of the answer\nrather than a silent short read.","type":"boolean"}},"type":"object"},"graph.graphPathIn":{"properties":{"as_known":{"description":"AsKnown is how much this plane had heard, RFC 3339: the answer as it would\nhave been given then, which is what makes a past answer reproducible.\nAbsent is now.","type":"string"},"as_of":{"description":"AsOf finds the path through the graph as it stood at an instant of the\nworld, RFC 3339: an edge that did not hold then is not crossed. Absent is\nnow.","type":"string"},"direction":{"description":"Direction is out, in or both. Out crosses each edge from its entity to\nits value; in crosses it backwards; both crosses it either way. Absent is\nout.","type":"string"},"from":{"description":"From is the entity the path starts at. Required.","type":"string"},"relations":{"description":"Relations is the edge relations a path may cross. Absent crosses every\nrelation. A causal chain is this list naming the relations that mean\ncause — `caused_by` and `influenced` under the decision convention. At\nmost 256.","items":{"type":"string"},"type":"array"},"to":{"description":"To is the entity the path ends at. Required.","type":"string"}},"required":["from","to"],"type":"object"},"graph.graphPathOut":{"properties":{"as_known":{"description":"AsKnown is the knowledge instant it was taken at, RFC 3339, the same way.","type":"string"},"as_of":{"description":"AsOf is the instant the path was taken at, RFC 3339: the one asked for,\nor the server's clock when none was.","type":"string"},"bound":{"description":"Bound is the ceiling the search was held to, the same one a walk is.","format":"int64","type":"integer"},"decay":{"description":"Decay is the product of the edges' confidences: how much certainty\nsurvives the whole chain. Absent unless every edge states a confidence\nabove zero — an unstated confidence reads as zero, and a product of\nnumbers nobody gave measures nothing.","format":"double","type":"number"},"edges":{"description":"Edges is the path from From to To, one assertion per hop, each with its\nsource, evidence and filer. An edge is listed as it was asserted, so\nunder in or both it may point against the direction of travel.","items":{"$ref":"#/components/schemas/graph.wireFact"},"type":"array"},"found":{"description":"Found is false when no path of in-force edges joins the two within the\nbound. That is an answer, not an error.","type":"boolean"},"hops":{"description":"Hops is how many edges the path crosses: zero when From is To, and zero\nwhen nothing was found.","format":"int64","type":"integer"},"truncated":{"description":"Truncated says the bound stopped the search before a path was found, so\nFound false means none within the bound rather than none at all.","type":"boolean"},"weakest":{"$ref":"#/components/schemas/graph.wireFact","description":"Weakest is the edge with the lowest confidence, the first of them on a\ntie: the link the chain is only as strong as. Absent exactly when Decay\nis."}},"type":"object"},"graph.graphReadOut":{"properties":{"assertions":{"description":"Assertions are the matching rows: a read's in the order they were written,\noldest first; a search's best match first. Every version is here: this\nresolves nothing and withholds nothing, so a superseded claim and the one\nthat superseded it both appear.","items":{"$ref":"#/components/schemas/graph.wireFact"},"type":"array"},"truncated":{"description":"Truncated says more assertions matched than came back: the limit, or the\nceiling, stopped the read. Narrow it, or page by as_known, to see the rest;\na search that stopped kept the best matches.","type":"boolean"}},"type":"object"},"graph.graphResolveIn":{"properties":{"as_known":{"description":"AsKnown is how much this plane had heard, RFC 3339: the answer as it would\nhave been given then, which is what makes a past answer reproducible.\nAbsent is now.","type":"string"},"as_of":{"description":"AsOf is the instant of the world to answer about, RFC 3339: what held\nthen. Absent is now.","type":"string"},"entity":{"description":"Entity is the thing to answer about. Required.","type":"string"},"relation":{"description":"Relation is the one relation to settle. Required: this answers a single\n(entity, relation) pair, never a whole entity at once.","type":"string"}},"required":["entity","relation"],"type":"object"},"graph.graphResolveOut":{"properties":{"as_known":{"description":"AsKnown is the knowledge instant it was taken at, RFC 3339, the same way.","type":"string"},"as_of":{"description":"AsOf is the valid instant this answer was taken at, RFC 3339: the one\nasked for, or the server's clock when none was.","type":"string"},"conflicts":{"description":"Conflicts is, for a relation holding one value, every weaker account of\nthe winner's moment that names a different value, strongest first. They\nlost the order and stay visible, so a disagreement is never resolved into\nsilence.","items":{"$ref":"#/components/schemas/graph.wireFact"},"type":"array"},"contested":{"description":"Contested is true exactly when Conflicts is not empty.","type":"boolean"},"entity":{"description":"Entity is the entity the question named, echoed so a stored answer still\nsays what it is about.","type":"string"},"held":{"description":"Held is every statement holding at the point, Winner first, one per\nvalue: one for a relation that holds one value at a time, and every one\nthe pair holds for a relation that holds many — the five holders of a\nposition over five terms are five.","items":{"$ref":"#/components/schemas/graph.wireFact"},"type":"array"},"known":{"description":"Known is false when nothing held at the point. That is an answer, not an\nerror.","type":"boolean"},"relation":{"description":"Relation is the relation the question named, echoed for the same reason.","type":"string"},"truncated":{"description":"Truncated says this pair holds more statements than one read returns, so\nthe answer was decided from the ceiling-full begun most recently. It is\nreported because a provenance plane that trims silently is a plane that\nanswers confidently and wrongly; narrow the question with as_of to see\nwhat it dropped.","type":"boolean"},"winner":{"$ref":"#/components/schemas/graph.wireFact","description":"Winner is the statement holding at the point that began most recently,\nthen the strongest under the order `rule` names. Absent exactly when Known\nis false."}},"type":"object"},"graph.graphSourceIn":{"properties":{"at":{"description":"At is when what the source says was so, RFC 3339. Required by ingest — which\nrecords — and read by nothing in extract, which records nothing. Required for\nthe same reason /v1/graph requires it: it is part of the assertion's content\naddress, so re-reading one source at one instant records one set of rows\nhowever many times it is delivered. A clock read here instead would append\nthe whole document again on every re-read.","type":"string"},"source":{"description":"Source names where the text came from — a URL, a document id, a page title.\nIt is stamped on every assertion as its source, and with the section number\nas its evidence, so a claim can be traced back to the passage that made it.\nRequired.","type":"string"},"subject":{"description":"Subject is the entity the text is about before any heading names one. A\ndocument that states relations above its first heading needs it; one whose\nevery section is headed does not.","type":"string"},"text":{"description":"Text is the document. Relations are read from it and from nothing else: a\nline written `relation:: value` states one, and prose states none. Required.","type":"string"}},"required":["source","text"],"type":"object"},"graph.graphStore":{"properties":{"detail":{"description":"Detail says what an unsupported store is missing before an erasure could\nreach it.","type":"string"},"removed":{"description":"Removed is how many of its rows were removed.","format":"int64","type":"integer"},"status":{"description":"Status is erased (rows naming the entity were removed), absent (it held\nnone) or unsupported (this op cannot reach it, so it may still hold the\nsubject).","type":"string"},"store":{"description":"Store names it: `graph` is the caller's own (org, project) assertion\nfile, its full-text index included; `knowledge` is the org's wiki pages,\nmemories and sources with their vectors; `ai.memory` is /v1/ai/memory.","type":"string"}},"type":"object"},"graph.graphSupport":{"properties":{"assertion":{"description":"Assertion is the ID of the statement in force the atom rests on. Absent\nwhen the atom is itself derived: it is then an entry of Derived or\nLemmas, with a proof of its own.","type":"string"},"object":{"description":"Object is its second argument. Absent for a predicate the rules use with\none argument.","type":"string"},"predicate":{"description":"Predicate is the relation the supporting atom is of.","type":"string"},"subject":{"description":"Subject is its first argument.","type":"string"}},"type":"object"},"graph.graphTriple":{"properties":{"names":{"description":"Names is the author's declaration that Object is an entity and the assertion\nis an EDGE, written `[[key]]`. Absent, the relation is a property of Subject.\nIt is read from the notation and never guessed from the value's shape.","type":"boolean"},"object":{"description":"Object is what the relation points at. When Names is true it has been\nunwrapped from its `[[…]]` and is another entity's key.","type":"string"},"predicate":{"description":"Predicate is the relation, exactly as the line spells it before the `::`.\nThis surface holds no vocabulary, so it renames nothing.","type":"string"},"reason":{"description":"Reason is why filing it would be refused: the declared schema, or a\ndeclaration from a caller who is not an admin of the organization. Present\nonly on a member of Refused.","type":"string"},"section":{"description":"Section is which section of the source stated it, counting from zero. It is\nthe second half of every resulting assertion's evidence, `\u003csource\u003e#\u003csection\u003e`.","format":"int64","type":"integer"},"subject":{"description":"Subject is the entity the statement is about: the nearest heading above the\nline, or the request's own subject where no heading has appeared yet.","type":"string"}},"type":"object"},"graph.graphVocabularyOut":{"properties":{"bound":{"description":"Bound is the ceiling on one walk.","format":"int64","type":"integer"},"relations":{"description":"Relations is what this organization has actually asserted. This plane\ndeclares none of its own.","items":{"type":"string"},"type":"array"},"rule":{"description":"Rule names the terms of the precedence order, in the order they apply. A\nreader who is told a winner without the rule cannot check it.","items":{"type":"string"},"type":"array"},"schema":{"description":"Schema is what the organization has declared, in force now: each relation\nwith a domain or range, asserted as (`relation:\u003cname\u003e`, `domain` |\n`range`, `\u003ctype\u003e`) and checked against the entities' (`\u003centity\u003e`, `type`,\n`\u003ctype\u003e`). A relation absent here is open.\n\nA decision is an entity of type `decision` by convention, never enforced:\n`scenario`, `reasoning`, `outcome` and `confidence` are its properties;\n`decided_by`, `caused_by`, `influenced` and `precedent` are its edges.\nDeclare their domain and range to make that convention checked; find a\nprecedent with search, then neighbors over `precedent`.","items":{"$ref":"#/components/schemas/graph.graphDeclared"},"type":"array"}},"type":"object"},"graph.wireFact":{"properties":{"at":{"description":"At is when the thing was so, RFC 3339, as the asserter gave it.","type":"string"},"by":{"description":"By is the identity that filed it — `owner` or `owner/user` — stamped from\nthe validated principal at the write, never from the body.","type":"string"},"confidence":{"description":"Confidence in [0,1] as the asserter gave it; absent is 0. It breaks a tie\nbetween two assertions equally knowable and decides nothing else.","format":"double","type":"number"},"entity":{"description":"Entity is the thing described, in the organization's own namespace.","type":"string"},"evidence":{"description":"Evidence points at the record the claim came from. Absent when the asserter\ngave none.","type":"string"},"id":{"description":"ID is the assertion's content address, minted by the server from what was\nasserted. Two callers who assert the identical thing land on one ID and one\nrow; changing any asserted field makes a different ID and a second row.","type":"string"},"knowable":{"description":"Knowable is the first instant this plane could have answered with the\nassertion, RFC 3339: the later of Seen and the server's clock at the write.\nDerived and never supplied, which is what stops history filed today from\nbeing backdated into a past read.","type":"string"},"names":{"description":"Names true means the assertion is an edge and Value is an entity. A walk\nreads only these.","type":"boolean"},"relation":{"description":"Relation is what was asserted of it.","type":"string"},"seen":{"description":"Seen is when the asserter says it became knowable, RFC 3339. Provenance\nonly — Knowable is what an as-of read is bounded by.","type":"string"},"source":{"description":"Source names who asserted, as the caller gave it. This plane ranks no\nsource above another, so it never outweighs a later Knowable.","type":"string"},"until":{"description":"Until is when the thing stopped being so, RFC 3339, as the asserter gave\nit. Absent is open.","type":"string"},"value":{"description":"Value is what the relation points at: another entity's key when Names is\ntrue, otherwise a scalar.","type":"string"}},"type":"object"},"graphQLError":{"properties":{"message":{"type":"string"},"path":{"items":{},"type":"array"}},"type":"object"},"graphQLIn":{"properties":{"operationName":{"type":"string"},"query":{"type":"string"},"variables":{}},"type":"object"},"graphQLOut":{"properties":{"data":{},"errors":{"items":{"$ref":"#/components/schemas/graphQLError"},"type":"array"}},"type":"object"},"guide.ActionRecord":{"properties":{"args":{"description":"Args is the JSON the tool was called with, recorded as TEXT exactly as sent —\nincluding whatever the AI drafted into it — so a run can be read back and\nreproduced. It is a string, not an object.","type":"string"},"createdAt":{"description":"CreatedAt is when the run was recorded, as Unix seconds. The ledger is read\nnewest-first on this column.","format":"int64","type":"integer"},"err":{"description":"Err is why the run failed, when it did. Empty on a successful run.","type":"string"},"id":{"description":"ID identifies this one execution. The ledger is append-only, so an id is\nnever reused and never updated.","type":"string"},"ok":{"description":"OK is whether the tool ran to completion. It is the ledger's own verdict, not\nthe tool's opinion of the outcome — a tool that succeeded at reporting bad\nnews is ok.","type":"boolean"},"result":{"description":"Result is the tool's own answer, likewise recorded as JSON text. Present on a\nfailed run too, where the tool answered but the answer was a refusal.","type":"string"},"stepId":{"description":"StepID is the checklist step the Business AI was acting on.","type":"string"},"tool":{"description":"Tool is the MCP tool that was dispatched, by name.","type":"string"}},"type":"object"},"guide.Curriculum":{"properties":{"steps":{"description":"Steps are the enabled steps in authoring order. Order is the tiebreak the\nnext-step logic walks, so it is part of the contract rather than cosmetic.","items":{"$ref":"#/components/schemas/guide.JourneyStep"},"type":"array"},"title":{"description":"Title is the playbook's name as it heads the checklist.","type":"string"},"version":{"description":"Version identifies the authored playbook this journey was projected from, so\ntwo orgs on different playbooks can be told apart. It is the blueprint's own\n`version` string, not the store's numeric revision.","type":"string"}},"type":"object"},"guide.Funnel":{"properties":{"available":{"description":"Available separates \"this org has no traffic\" from \"we could not ask\". False\nmeans the warehouse was unreachable or the org has emitted nothing at all, and\nevery count below is then a placeholder zero rather than a measurement — a\ncaller must read this before reading any of them.","type":"boolean"},"orders":{"description":"Orders counts completed orders in the window — purchases, not carts started.","format":"int64","type":"integer"},"pageviews":{"description":"Pageviews counts page events in the window, one per view rather than per\nperson, so a single visitor reading ten pages counts ten.","format":"int64","type":"integer"},"revenue":{"description":"Revenue is the sum of the amounts those orders reported, in whatever currency\nthe beacon stamped on them (major units, e.g. 49.5 for $49.50) — NOT cents,\nand not converted to a single currency. Contrast revenueCents on the profile,\nwhich is the money of record.","format":"double","type":"number"},"signups":{"description":"Signups counts completed signups in the window, the step where an anonymous\nvisitor becomes somebody with an account.","format":"int64","type":"integer"},"visitors":{"description":"Visitors is the number of DISTINCT people seen in the window, counted by the\nbeacon's distinct id — so it is unique visitors, not sessions and not views.","format":"int64","type":"integer"},"windowDays":{"description":"WindowDays is the length of the trailing window every count covers, so a\nreader knows whether 40 signups is a month or a day.","format":"int64","type":"integer"}},"type":"object"},"guide.JourneyStep":{"properties":{"args":{"additionalProperties":{},"description":"Args are the tool's default arguments, merged under whatever the caller\npasses at run time, so a step ships with the arguments that make it work.","type":"object"},"deps":{"description":"Dependencies are step ids that must be done/skipped before this step is\navailable. The wire key is `deps` (the blueprint contract); the Go field keeps\nits descriptive name.","items":{"type":"string"},"type":"array"},"detail":{"description":"Detail is the juncture — what the Guide explains, or asks for, at this step.","type":"string"},"draft":{"description":"Draft, when set, is the prompt the embedded AI answers first; its output is\nfolded into one of Args before the tool runs, so the model writes the\ncontent and the tool only delivers it.","type":"string"},"draftInto":{"description":"DraftInto names the argument the drafted text lands in. Empty means \"brief\".","type":"string"},"enabled":{"description":"Enabled is the admin on/off lever. A NIL pointer reads as ENABLED (absence ==\non): a legacy/org curriculum that omits the field keeps every step, and only an\nexplicit `enabled: false` (an admin disable) drops a step from the journey. See\non() in blueprint.go and the Blueprint.Curriculum() projection.","type":"boolean"},"id":{"description":"ID is the stable slug the whole plane addresses this step by — the value in\n`deps`, in `next`, in the progress rows, and in the URL of every step route.\nRenaming it orphans an org's recorded progress for this step.","type":"string"},"section":{"description":"Section is the id of the phase this step groups under. A disabled section\ntakes its steps out of the journey with it.","type":"string"},"signal":{"description":"Signal, when set, names a machine detector (detect.go). When the detector\nreports the org's real state present, the step auto-marks done.","type":"string"},"title":{"description":"Title is the one-line quest as a person reads it in the checklist.","type":"string"},"tool":{"description":"Tool, when set, names the MCP tool the Business AI runs for \"do it for me\".\nA step with no tool can only be completed by a person; it is the field the\n`automatable` flag on every projection of this step is derived from.","type":"string"}},"type":"object"},"guide.actionsView":{"properties":{"data":{"description":"Data is the most-recent actions first, capped at listActionsLimit.","items":{"$ref":"#/components/schemas/guide.ActionRecord"},"type":"array"}},"type":"object"},"guide.analyticsView":{"properties":{"funnel":{"$ref":"#/components/schemas/guide.Funnel","description":"Funnel is the org's trailing-30-day traffic → signups → orders from the\nshared analytics warehouse; available is false when it has emitted nothing."},"recommendations":{"description":"Recommendations are the next-best GTM actions derived from that funnel.","items":{"type":"string"},"type":"array"}},"type":"object"},"guide.chatRequest":{"properties":{"message":{"description":"Message is the founder's question for the Business AI. Required; trimmed,\nand clipped to 4 KiB so a caller cannot amplify the AI prompt.","type":"string"}},"type":"object"},"guide.chatResponse":{"properties":{"funnel":{"$ref":"#/components/schemas/guide.Funnel","description":"Funnel is the org's trailing-window traffic → signups → orders."},"reply":{"description":"Reply is the coach's answer, grounded only in the quests and funnel below.\nWhen no AI plane is reachable it is the deterministic reply naming the top\nreal quest — never silence, never invention.","type":"string"},"suggestions":{"description":"Suggestions are the current candidate quests, ranked best-first.","items":{"$ref":"#/components/schemas/guide.suggestion"},"type":"array"}},"type":"object"},"guide.corpusView":{"properties":{"count":{"description":"Count is how many tactics survived every filter.","format":"int64","type":"integer"},"stage":{"description":"Stage is the growth stage the tag join ran at — the org's observed stage, or\nthe one ?stage= previewed.","type":"string"},"strategies":{"description":"Strategies are the surviving tactics, in corpus authoring order.","items":{"$ref":"#/components/schemas/guide.strategyView"},"type":"array"}},"type":"object"},"guide.curriculumView":{"properties":{"curriculum":{"$ref":"#/components/schemas/guide.Curriculum","description":"Curriculum is the enabled journey: its version, title and ordered steps."},"custom":{"description":"Custom is true when the org's OWN curriculum override is active; false when\nthe journey comes from the brand blueprint or the embedded fixture.","type":"boolean"}},"type":"object"},"guide.overviewView":{"properties":{"custom":{"description":"Custom is true when the org replaced the shared playbook with one of its own\n— the difference between \"everyone's checklist\" and \"the one you authored\".","type":"boolean"},"funnel":{"$ref":"#/components/schemas/guide.Funnel","description":"Funnel is the org's analytics lens, present only where the read asked for it\n— absent means it was not requested, never that the org has no traffic."},"progress":{"$ref":"#/components/schemas/guide.progressView","description":"Progress is how far through the journey the org is."},"steps":{"description":"Steps are every enabled step with the org's own state folded in, in\nauthoring order.","items":{"$ref":"#/components/schemas/guide.stepView"},"type":"array"},"title":{"description":"Title is the playbook's name as it heads the checklist.","type":"string"},"version":{"description":"Version identifies the playbook this journey came from, so a caller can tell\nthat the checklist itself changed under them.","type":"string"}},"type":"object"},"guide.profileMetrics":{"properties":{"funnel":{"$ref":"#/components/schemas/guide.Funnel","description":"Funnel is what the org's analytics observed over the trailing window. Read\nits `available` first: an org with no analytics reports zeros here, and zero\ntraffic and no measurement are different facts."},"launchProgress":{"$ref":"#/components/schemas/guide.progressView","description":"LaunchProgress is the org's own position in the launch checklist, folded in\nso a profile carries both what the org has BUILT and what it has DONE."},"records":{"description":"Records is how many business records the org holds — the volume that tells a\nreal book of customers from an empty account. It feeds the `customers`\nsignal, which crosses at a threshold rather than at one row.","format":"int64","type":"integer"},"revenueCents":{"description":"RevenueCents is the org's money OF RECORD — what its books say, in whole\ncents, never a float and never a display string. This is the number the\nscaling stage is decided on; funnel.revenue is the beacon's separate,\nunreconciled view of the same business. Zero when the org has none, and also\nzero when the books could not be read, which is why the `revenue` signal\nbeside it is the thing to trust.","format":"int64","type":"integer"}},"type":"object"},"guide.profileResponse":{"properties":{"keyMetrics":{"$ref":"#/components/schemas/guide.profileMetrics","description":"KeyMetrics are the org's OWN numbers behind those signals — never another\norg's, and never a platform aggregate."},"signals":{"additionalProperties":{"type":"boolean"},"description":"Signals is what was observed of the org right now, one boolean per probe.\nA probe that could not be run reports FALSE, not absent — the shape is stable\nso a caller never has to tell a missing key from a negative answer, and the\ncost is that \"not observed\" and \"not there\" look alike here. Keys are the\nprobe names, including the `module:\u003cname\u003e` and `connected:\u003cprovider\u003e`\nfamilies.","type":"object"},"stage":{"description":"Stage is how far the business itself has got — formed, launched, activated or\nscaling — decided purely from the signals below, and by what the org has\nACHIEVED rather than what it has configured. It reads the STRONGEST evidence\npresent, so money of record makes an org scaling even if an earlier rung's\nsignal was never observed. It is unrelated to checklist progress.","type":"string"}},"type":"object"},"guide.progressView":{"properties":{"done":{"description":"Done counts steps that are FINISHED — done and skipped alike, since a step\nthe org deliberately passed over is not still owed. It therefore rises when\nsomebody skips, which is the intended reading of a checklist.","format":"int64","type":"integer"},"next":{"description":"Next is the id of the step to do next: the first available, unfinished step\nin authoring order. Empty when the journey is complete, and also empty when\nevery remaining step is blocked by a dependency.","type":"string"},"percent":{"description":"Percent is done/total as a whole number 0-100, rounded, so a caller renders\na bar without recomputing it. Total zero reads as 0.","format":"int64","type":"integer"},"total":{"description":"Total is how many steps this org's journey holds — the ENABLED steps of the\nplaybook, so it shrinks when an operator disables one and does not match the\nauthored step count.","format":"int64","type":"integer"}},"type":"object"},"guide.stepView":{"properties":{"args":{"additionalProperties":{},"description":"Args are the tool's default arguments, merged under whatever the caller\npasses at run time.","type":"object"},"automatable":{"description":"Automatable is true when the Business AI can run this step (it names a tool).","type":"boolean"},"available":{"description":"Available is true when every dependency is done or skipped.","type":"boolean"},"blockedBy":{"description":"BlockedBy lists the unfinished dependencies keeping the step unavailable.","items":{"type":"string"},"type":"array"},"deps":{"description":"Dependencies are step ids that must be done/skipped before this step is\navailable. The wire key is `deps` (the blueprint contract).","items":{"type":"string"},"type":"array"},"detail":{"description":"Detail is the prose/juncture — what the Guide asks or explains here.","type":"string"},"draft":{"description":"Draft, when set, is the prompt the embedded AI answers first; its output is\nfolded into one of Args before the tool runs.","type":"string"},"draftInto":{"description":"DraftInto names the argument the drafted text lands in. Empty means \"brief\".","type":"string"},"enabled":{"description":"Enabled is the admin on/off lever; absent reads as enabled.","type":"boolean"},"id":{"description":"ID is the step's id, as it appears in the journey (e.g. \"gsuite\").","type":"string"},"section":{"description":"Section is the phase (section id) this step groups under.","type":"string"},"signal":{"description":"Signal names the machine detector that auto-marks this step done.","type":"string"},"source":{"description":"Source records what marked the state: manual, auto (detected) or agent.","type":"string"},"state":{"description":"State is the step's per-org lifecycle state: todo|in_progress|done|skipped.","type":"string"},"title":{"description":"Title is the one-line quest as a person reads it in the checklist.","type":"string"},"tool":{"description":"Tool is the MCP tool the Business AI runs for \"do it for me\". A step naming\nnone can only be completed by a person.","type":"string"}},"type":"object"},"guide.strategyView":{"properties":{"action":{"description":"Action is the tactic itself: the thing to go and do.","type":"string"},"category":{"description":"Category is the growth discipline the tactic belongs to — the axis\n`?category=` narrows on.","type":"string"},"id":{"description":"ID is the tactic's stable slug in the corpus.","type":"string"},"tags":{"description":"Tags are the PRECONDITIONS this tactic already satisfied to appear in the\nanswer — `stage:\u003cname\u003e` and `has:\u003ccapability\u003e` predicates over the org's\nobserved profile. They are carried back so a caller can show why a tactic\nsurfaced, not so it can filter again.","items":{"type":"string"},"type":"array"},"workload":{"description":"Workload is how much effort running the tactic costs, so a corpus can be cut\nto what the org has the hands for.","type":"string"}},"type":"object"},"guide.suggestResponse":{"properties":{"funnel":{"$ref":"#/components/schemas/guide.Funnel","description":"Funnel is the org's trailing-window traffic → signups → orders."},"narrative":{"description":"Narrative is the AI's grounded prose over those quests and numbers. Absent\nwhen no AI plane is wired or the completion failed — never fabricated.","type":"string"},"next":{"description":"Next is the id of the single next step the static journey names — the\nlinear answer the ranked Suggestions refine.","type":"string"},"recommendations":{"description":"Recommendations are the next-best GTM actions derived from that funnel.","items":{"type":"string"},"type":"array"},"suggestions":{"description":"Suggestions are the available, non-terminal quests ranked best-first by how\nmuch downstream work each unblocks.","items":{"$ref":"#/components/schemas/guide.suggestion"},"type":"array"}},"type":"object"},"guide.suggestion":{"properties":{"automatable":{"description":"Automatable is true when the step names a tool, so the Business AI can do it\nrather than only describe it.","type":"boolean"},"detail":{"description":"Detail is the step's own prose — what it asks for.","type":"string"},"rationale":{"description":"Rationale is why this step is being suggested NOW, written for the person\nreading it. It explains the ranking, not the step.","type":"string"},"stepId":{"description":"StepID is the checklist step being recommended — the id every step route\ntakes, so a caller can act on the suggestion directly.","type":"string"},"title":{"description":"Title is the step's own one-line quest.","type":"string"},"unlocks":{"description":"Unlocks is how many downstream steps completing this one immediately makes\navailable (its leverage) — the primary ranking key.","format":"int64","type":"integer"}},"type":"object"},"help.helpArticle":{"properties":{"body":{"description":"Body is the article's rich-text content as the author saved it.","type":"string"},"category":{"description":"Category is the name of the knowledge-base section the article sits in, or\nempty when it is filed under none.","type":"string"},"excerpt":{"description":"Excerpt is the short summary the author wrote for listings, or empty.","type":"string"},"slug":{"description":"Slug is the article's stable public identifier — the path segment it was\naddressed by.","type":"string"},"title":{"description":"Title is the article's headline.","type":"string"},"updatedAt":{"description":"UpdatedAt is the unix second the article was last written.","format":"int64","type":"integer"}},"type":"object"},"help.helpArticleCard":{"properties":{"category":{"description":"Category is the name of the knowledge-base section the article sits in, or\nempty when it is filed under none.","type":"string"},"excerpt":{"description":"Excerpt is the short summary the author wrote for listings, or empty.","type":"string"},"slug":{"description":"Slug is the article's stable public identifier and the path segment\n/v1/help/articles/{slug} addresses it by.","type":"string"},"title":{"description":"Title is the article's headline.","type":"string"},"updatedAt":{"description":"UpdatedAt is the unix second the article was last written, in the help\ncenter's own store.","format":"int64","type":"integer"}},"type":"object"},"help.helpArticleList":{"properties":{"data":{"description":"Data is the matching Published, public articles, newest write order last —\nthe store's order, not a ranking. Empty when the center has none.","items":{"$ref":"#/components/schemas/help.helpArticleCard"},"type":"array"}},"type":"object"},"help.helpCategory":{"properties":{"description":{"description":"Description is the section's blurb, or empty.","type":"string"},"name":{"description":"Name is the section's name, and the value an article's category matches.","type":"string"}},"type":"object"},"help.helpCategoryList":{"properties":{"data":{"description":"Data is the sections that front at least one public article. Empty when the\ncenter publishes none.","items":{"$ref":"#/components/schemas/help.helpCategory"},"type":"array"}},"type":"object"},"help.helpTicketFiled":{"properties":{"status":{"description":"Status is the lifecycle state the ticket was filed in — always \"Open\".","type":"string"},"ticket":{"description":"Ticket is the opaque, random customer-facing reference (\"tkt_\" + 24 hex\ncharacters). It is NOT the ticket's internal name: that name is sequential,\nand handing it out would disclose the center's ticket volume.","type":"string"}},"type":"object"},"help.helpTicketIntake":{"properties":{"description":{"description":"Description is the customer's message. Optional; it becomes the ticket's\ndescription AND the opening entry of its conversation thread. Clipped at\n16 KiB.","type":"string"},"email":{"description":"Email is how the support team replies. Required; clipped at 320 characters\n(the RFC 5321 maximum). It is recorded as the ticket's customer, and it is\nnot verified.","type":"string"},"priority":{"description":"Priority is Low, Medium, High or Urgent, case-insensitively. Anything else —\nincluding omitting it — is recorded as Medium rather than refused.","type":"string"},"subject":{"description":"Subject is the one-line summary of the problem. Required; longer than 300\ncharacters is clipped rather than refused.","type":"string"}},"type":"object"},"iam.AccountItem":{"properties":{"modifyRule":{"type":"string"},"name":{"type":"string"},"regex":{"type":"string"},"tab":{"type":"string"},"viewRule":{"type":"string"},"visible":{"type":"boolean"}},"type":"object"},"iam.Address":{"properties":{"city":{"type":"string"},"line1":{"type":"string"},"line2":{"type":"string"},"region":{"type":"string"},"state":{"type":"string"},"tag":{"type":"string"},"zipCode":{"type":"string"}},"type":"object"},"iam.Answer":{"properties":{"code":{"description":"Code is a STABLE machine-readable reason, where the human `msg` is\ndeliberately generic. `msg` is prose for a person and several distinct causes\nlegitimately share one sentence; a caller that must BRANCH on the cause — or\ntell its own user which of them happened — cannot parse prose. Optional, so\nevery existing envelope is byte-identical and no SDK changes.","type":"string"},"data":{},"data2":{},"data3":{},"msg":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"},"sub":{"type":"string"}},"type":"object"},"iam.Application":{"properties":{"affiliationUrl":{"type":"string"},"category":{"type":"string"},"cert":{"type":"string"},"certObj":{"$ref":"#/components/schemas/iam.Cert"},"certPublicKey":{"type":"string"},"clientCert":{"type":"string"},"clientId":{"description":"ClientId is the OAuth2/OIDC client identifier and the GLOBAL key every\nconfidential-client resolver authenticates against (store.GetApplicationByClientId,\nthe mint gates, Basic auth). It MUST be globally unique across ALL owners — a\ncollision would let one app shadow another at that key. This store persists each\nentity as a JSON document in a shared table, so there is no per-field column to\ncarry a DB UNIQUE index; uniqueness is enforced at the write in\napplications.Create/Update (ensureClientIdUnique), exactly as the (owner,name)\nnatural key is, and store.GetApplicationByClientId resolves admin-preferring as\ndefense-in-depth.","type":"string"},"clientSecret":{"type":"string"},"codeResendTimeout":{"format":"int64","type":"integer"},"cookieExpireInHours":{"format":"int64","type":"integer"},"createdAt":{"format":"date-time","type":"string"},"createdTime":{"type":"string"},"customScopes":{"items":{"$ref":"#/components/schemas/iam.ScopeDescription"},"type":"array"},"defaultGroup":{"type":"string"},"deleted":{"type":"boolean"},"description":{"type":"string"},"disableSamlAttributes":{"type":"boolean"},"disableSignin":{"type":"boolean"},"displayName":{"type":"string"},"domain":{"type":"string"},"enableAutoSignin":{"type":"boolean"},"enableCodeSignin":{"type":"boolean"},"enableExclusiveSignin":{"type":"boolean"},"enableLinkWithEmail":{"type":"boolean"},"enablePassword":{"type":"boolean"},"enableSamlAssertionSignature":{"type":"boolean"},"enableSamlC14n10":{"type":"boolean"},"enableSamlCompress":{"type":"boolean"},"enableSamlPostBinding":{"type":"boolean"},"enableSignUp":{"type":"boolean"},"enableSigninSession":{"type":"boolean"},"enableWebAuthn":{"type":"boolean"},"environment":{"type":"string"},"expireInHours":{"format":"double","type":"number"},"failedSigninFrozenTime":{"format":"int64","type":"integer"},"failedSigninLimit":{"format":"int64","type":"integer"},"favicon":{"type":"string"},"footerHtml":{"type":"string"},"forcedRedirectOrigin":{"type":"string"},"forgetUrl":{"type":"string"},"formBackgroundUrl":{"type":"string"},"formBackgroundUrlMobile":{"type":"string"},"formCss":{"type":"string"},"formCssMobile":{"type":"string"},"formOffset":{"format":"int64","type":"integer"},"formSideHtml":{"type":"string"},"grantTypes":{"items":{"type":"string"},"type":"array"},"headerHtml":{"type":"string"},"homepageUrl":{"type":"string"},"id":{"description":"Persisted fields","type":"string"},"ipRestriction":{"type":"string"},"ipWhitelist":{"type":"string"},"isShared":{"type":"boolean"},"logo":{"type":"string"},"name":{"type":"string"},"order":{"format":"int64","type":"integer"},"orgChoiceMode":{"type":"string"},"organization":{"type":"string"},"organizationObj":{"$ref":"#/components/schemas/iam.Organization"},"otherDomains":{"items":{"type":"string"},"type":"array"},"owner":{"type":"string"},"platform":{"description":"Platform marks an application the platform itself declares (init_data.json):\nits own consoles and apps, never one a tenant registered. The seed stamps it on\nevery declared application at boot, and only a SuperAdmin may change it over\nthe API. It is what lets a signed-in person act through IAM with a bearer on\nthe platform's behalf — sending an invitation from the platform's own email\naccount, joining an org — which a tenant's application may not do with the\ntokens its users hand it.","type":"boolean"},"project":{"type":"string"},"providers":{"items":{"$ref":"#/components/schemas/iam.ProviderItem"},"type":"array"},"redirectUris":{"items":{"type":"string"},"type":"array"},"refreshExpireInHours":{"format":"double","type":"number"},"samlAttributes":{"items":{"$ref":"#/components/schemas/iam.SamlItem"},"type":"array"},"samlHashAlgorithm":{"type":"string"},"samlReplyUrl":{"type":"string"},"scopes":{"items":{"$ref":"#/components/schemas/iam.ScopeItem"},"type":"array"},"signinHtml":{"type":"string"},"signinItems":{"items":{"$ref":"#/components/schemas/iam.SigninItem"},"type":"array"},"signinMethods":{"items":{"$ref":"#/components/schemas/iam.SigninMethod"},"type":"array"},"signinUrl":{"type":"string"},"signupHtml":{"type":"string"},"signupItems":{"items":{"$ref":"#/components/schemas/iam.SignupItem"},"type":"array"},"signupUrl":{"type":"string"},"sslCert":{"type":"string"},"sslMode":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"},"termsOfUse":{"type":"string"},"themeData":{"$ref":"#/components/schemas/iam.ThemeData"},"title":{"type":"string"},"tokenAttributes":{"items":{"$ref":"#/components/schemas/iam.JwtItem"},"type":"array"},"tokenFields":{"items":{"type":"string"},"type":"array"},"tokenFormat":{"type":"string"},"tokenSigningMethod":{"type":"string"},"type":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"upstreamHost":{"type":"string"},"useEmailAsSamlNameId":{"type":"boolean"}},"type":"object"},"iam.ApplicationListResult":{"properties":{"applications":{"items":{"$ref":"#/components/schemas/iam.Application"},"type":"array"}},"type":"object"},"iam.AuditLog":{"properties":{"action":{"type":"string"},"clientIp":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"createdTime":{"type":"string"},"deleted":{"type":"boolean"},"id":{"description":"Persisted fields","type":"string"},"isTriggered":{"type":"boolean"},"language":{"type":"string"},"method":{"type":"string"},"name":{"type":"string"},"object":{"type":"string"},"organization":{"type":"string"},"owner":{"type":"string"},"requestUri":{"type":"string"},"response":{"type":"string"},"statusCode":{"format":"int64","type":"integer"},"updatedAt":{"format":"date-time","type":"string"},"user":{"type":"string"}},"type":"object"},"iam.CartItem":{"properties":{"displayName":{"type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"price":{"format":"double","type":"number"},"quantity":{"format":"int64","type":"integer"}},"type":"object"},"iam.Cert":{"properties":{"accessKey":{"type":"string"},"accessSecret":{"type":"string"},"account":{"type":"string"},"bitSize":{"format":"int64","type":"integer"},"certificate":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"createdTime":{"type":"string"},"cryptoAlgorithm":{"type":"string"},"deleted":{"type":"boolean"},"displayName":{"type":"string"},"domainExpireTime":{"type":"string"},"expireInYears":{"format":"int64","type":"integer"},"expireTime":{"type":"string"},"id":{"description":"Persisted fields","type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"provider":{"type":"string"},"scope":{"type":"string"},"type":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"iam.ConsentRecord":{"properties":{"application":{"type":"string"},"grantedScopes":{"items":{"type":"string"},"type":"array"}},"type":"object"},"iam.CreateInput":{"properties":{"password":{"type":"string"},"user":{"$ref":"#/components/schemas/iam.User"}},"type":"object"},"iam.CreateOrganizationInput":{"properties":{"accountItems":{"items":{"$ref":"#/components/schemas/iam.AccountItem"},"type":"array"},"accountMenu":{"type":"string"},"avatar":{"description":"How the organization appears across Hanzo — the square mark beside its\nname — as an image or as one emoji, never both. It is the pair a person\ncarries (User.Avatar) under the same names, resolved the same way, so a\nscreen draws a subject without asking which kind of subject it has. Both\nhalves live on the row: a mark that appears everywhere cannot be kept on\none device. Written through schema.MarkOf; Logo and LogoDark above are a\ndifferent thing, the wordmark a login screen draws.","type":"string"},"balanceCredit":{"format":"double","type":"number"},"balanceCurrency":{"type":"string"},"countryCodes":{"items":{"type":"string"},"type":"array"},"createdAt":{"format":"date-time","type":"string"},"createdTime":{"type":"string"},"dcrPolicy":{"type":"string"},"defaultApplication":{"type":"string"},"defaultAvatar":{"type":"string"},"defaultPassword":{"type":"string"},"deleted":{"type":"boolean"},"disableSignin":{"type":"boolean"},"displayName":{"type":"string"},"emoji":{"type":"string"},"enableSoftDeletion":{"type":"boolean"},"enableTour":{"type":"boolean"},"failedSigninFrozenTime":{"format":"int64","type":"integer"},"failedSigninLimit":{"description":"Per-organization signin throttle. Zero means \"inherit the application\ndefault\"; a non-zero value overrides it. Safe bounds are clamped by the\nresource service before persistence.","format":"int64","type":"integer"},"favicon":{"type":"string"},"founder":{"description":"Founder is the stable storage id of the identity that provisioned this org\n(self-service onboarding). It is the resume token that makes provisioning\nconverge on a backend where each write autocommits independently (no\ntransaction rollback): after a partial failure that created the org but did\nnot move the founder in, a retry recognises the org as the founder's own and\ncompletes it, instead of refusing it as \"already taken\". It also fences the\norg to ONE tenant — a different identity can never complete or join it.","type":"string"},"hasPrivilegeConsent":{"type":"boolean"},"id":{"description":"Persisted fields","type":"string"},"initScore":{"format":"int64","type":"integer"},"ipRestriction":{"type":"string"},"ipWhitelist":{"type":"string"},"isPersonal":{"type":"boolean"},"isProfilePublic":{"type":"boolean"},"kerberosKdcHost":{"type":"string"},"kerberosKeytab":{"type":"string"},"kerberosRealm":{"type":"string"},"kerberosServiceName":{"type":"string"},"languages":{"items":{"type":"string"},"type":"array"},"ldapAttributes":{"items":{"type":"string"},"type":"array"},"logo":{"type":"string"},"logoDark":{"type":"string"},"masterPassword":{"type":"string"},"masterVerificationCode":{"type":"string"},"mfaItems":{"items":{"$ref":"#/components/schemas/iam.MfaItem"},"type":"array"},"mfaRememberInHours":{"format":"int64","type":"integer"},"name":{"type":"string"},"navItems":{"items":{"type":"string"},"type":"array"},"orgBalance":{"description":"Balance fields are read-only mirrors; authoritative balances live in\nCommerce (billing.hanzo.ai). Carried for field-complete v1 parity.","format":"double","type":"number"},"owner":{"type":"string"},"passwordExpireDays":{"format":"int64","type":"integer"},"passwordObfuscatorKey":{"type":"string"},"passwordObfuscatorType":{"type":"string"},"passwordOptions":{"items":{"type":"string"},"type":"array"},"passwordSalt":{"type":"string"},"passwordType":{"type":"string"},"platform":{"description":"Platform marks an organization the platform itself declares (init_data.json):\nthe brand orgs and the others the seed creates, never one a customer made. The\nseed stamps it on every declared organization at boot, and no request sets or\nclears it. Only a SuperAdmin may delete an organization that carries it.","type":"boolean"},"tags":{"items":{"type":"string"},"type":"array"},"themeData":{"$ref":"#/components/schemas/iam.ThemeData"},"updatedAt":{"format":"date-time","type":"string"},"useEmailAsUsername":{"type":"boolean"},"usePermanentAvatar":{"type":"boolean"},"userBalance":{"format":"double","type":"number"},"userNavItems":{"items":{"type":"string"},"type":"array"},"userTypes":{"items":{"type":"string"},"type":"array"},"websiteUrl":{"type":"string"},"widgetItems":{"items":{"type":"string"},"type":"array"}},"type":"object"},"iam.CreateSessionIn":{"properties":{"application":{"type":"string"},"exclusiveSignin":{"type":"boolean"},"name":{"type":"string"},"owner":{"type":"string"},"sessionId":{"items":{"type":"string"},"type":"array"}},"required":["owner","name","application"],"type":"object"},"iam.DeleteOrganizationOutput":{"properties":{"affected":{"type":"boolean"}},"type":"object"},"iam.DeleteOutput":{"properties":{"deleted":{"type":"boolean"}},"type":"object"},"iam.DeleteResponse":{"properties":{"deleted":{"type":"boolean"}},"type":"object"},"iam.DeleteResult":{"properties":{"deleted":{"type":"boolean"}},"type":"object"},"iam.DeleteSessionOut":{"properties":{"deleted":{"type":"boolean"}},"type":"object"},"iam.FaceId":{"properties":{"faceIdData":{"items":{"format":"double","type":"number"},"type":"array"},"imageUrl":{"type":"string"},"name":{"type":"string"}},"type":"object"},"iam.Input":{"properties":{"createdTime":{"type":"string"},"description":{"type":"string"},"displayName":{"type":"string"},"domains":{"items":{"type":"string"},"type":"array"},"isEnabled":{"type":"boolean"},"name":{"description":"Name addresses the team on update and names it on create; every other\nfield is content and binds from the BODY, never the URL.","type":"string"},"owner":{"type":"string"},"roles":{"items":{"type":"string"},"type":"array"},"teams":{"items":{"type":"string"},"type":"array"},"users":{"items":{"type":"string"},"type":"array"}},"type":"object"},"iam.Invitation":{"properties":{"application":{"type":"string"},"code":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"createdTime":{"type":"string"},"defaultCode":{"type":"string"},"deleted":{"type":"boolean"},"displayName":{"type":"string"},"email":{"type":"string"},"generated":{"description":"Generated reports that IAM minted Code itself, from crypto/rand, when the\ninvitation was created. Only such a code is compared without limit; any code\na caller wrote is compared only while the org is not being guessed at, however\nit looks, because a code that looks random need not be.","type":"boolean"},"id":{"description":"Persisted fields","type":"string"},"isRegexp":{"type":"boolean"},"name":{"type":"string"},"owner":{"type":"string"},"phone":{"type":"string"},"quota":{"format":"int64","type":"integer"},"sentTime":{"description":"SentTime is when an email about this invitation last went to its pinned\naddress (RFC 3339), \"\" when none has. It paces resends, so the send\nendpoint cannot be used to mail one address over and over.","type":"string"},"signupGroup":{"type":"string"},"state":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"updatedTime":{"type":"string"},"usedCount":{"format":"int64","type":"integer"},"username":{"type":"string"}},"type":"object"},"iam.JwtItem":{"properties":{"category":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"value":{"type":"string"}},"type":"object"},"iam.Key":{"properties":{"accessKey":{"description":"AccessKey (pk-*) is the publishable identifier and lookup index;\nAccessSecret (sk-*) is the confidential secret.\nAccessSecret IS NOT PERSISTED for a key minted at or after the digest\nchange: it carries the secret out to its holder once, in the mint response,\nand the row keeps only AccessSecretDigest. It stays on the struct because\nthat one-time reveal is the whole point of minting, and it stays in the\nschema because rows written before the change still hold a plaintext secret\nthat the resolver drains on first use.","type":"string"},"accessSecret":{"type":"string"},"accessSecretDigest":{"description":"AccessSecretDigest is how a presented secret finds its key: the resolver\ndigests what the caller sent and looks THAT up. It is what lets the row hold\nno plaintext and still be found in one indexed read — a salted hash cannot be\nlooked up by value, which is the reason the plaintext was here.","type":"string"},"act":{"description":"Act is the durable, opt-in grant that lets this key act FOR a user in its\nown org — the credential behind as(): presenting it authorizes minting a\nshort-lived, user-bound token for a member of the key's tenant. Default\nfalse, so a server key mints nothing on anyone's behalf until the grant is\nset deliberately — the capability is never inherited by every key. It is\nconfined at mint time to the key's OWN Owner, and a reserved-org or\nSuperAdmin target is refused, so the grant reaches only ordinary members of\nthe one tenant that holds the key.","type":"boolean"},"application":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"createdTime":{"description":"CreatedTime and UpdatedTime are RFC3339 audit stamps carried as strings\nfor byte-parity with the v1 row (orm.Model separately tracks CreatedAt /\nUpdatedAt as time.Time for the store's own lifecycle).","type":"string"},"deleted":{"type":"boolean"},"displayName":{"description":"DisplayName is the human-facing label.","type":"string"},"expireTime":{"description":"ExpireTime is when the key stops being honored (empty = never). State is\nthe lifecycle flag (\"Active\", \"test\", …); \"test\" mints test-env\ncredentials instead of live ones.","type":"string"},"id":{"description":"Persisted fields","type":"string"},"name":{"type":"string"},"organization":{"type":"string"},"owner":{"description":"Owner is the tenant that holds the key; Name is unique within Owner.","type":"string"},"prefix":{"description":"Prefix is the head of the credential the holder presents — the sk- of a\nsecret key, the pk- of a publishable one — recorded when the key is minted\n(PrefixOf). It lets a listing say which string a row is, and is far too\nshort to use: the secret itself is never stored.","type":"string"},"revokeTime":{"type":"string"},"revoker":{"description":"Revoker is who revoked the key and RevokeTime when. Revoking sets State to\nKeyStateRevoked and keeps the row, so the key is still listed and its\nhistory can be read; the resolvers refuse it, and no update reopens it.","type":"string"},"scope":{"description":"Scope is the key's ACCESS CLASS, orthogonal to Type (which names the bound\nprincipal). Empty (the default, \"secret\") is a full key: a pk- publishable\nhalf AND a confidential sk- half, the sk- authenticating a server-side reader.\nKeyScopePublish is a WRITE-ONLY publishable key — a pk- half only, no secret —\nthat resolves to just an ORG (never a principal) at the ingest endpoint and is safe\nto ship in client JS. A missing value on an existing row reads as the default,\nso every pre-Scope key is a secret key unchanged.","type":"string"},"state":{"type":"string"},"type":{"description":"Type is the scope the key is bound to — \"Organization\", \"Application\",\n\"User\", or \"General\" — and Organization / Application / User name the\nconcrete principal for whichever scope Type selects.","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"updatedTime":{"type":"string"},"usedTime":{"description":"UsedTime is when the key was last presented and resolved. A list read fills\nit from the key's Sighting; the key row itself never holds it, so recording a\nuse never rewrites the row a person may be editing.","type":"string"},"user":{"type":"string"}},"type":"object"},"iam.ListOrganizationsOutput":{"properties":{"cursor":{"type":"string"},"organizations":{"items":{"$ref":"#/components/schemas/iam.Organization"},"type":"array"}},"type":"object"},"iam.ListOutput":{"properties":{"total":{"format":"int64","type":"integer"},"users":{"items":{"$ref":"#/components/schemas/iam.User"},"type":"array"}},"type":"object"},"iam.ListResponse":{"properties":{"permissions":{"items":{"$ref":"#/components/schemas/iam.Permission"},"type":"array"}},"type":"object"},"iam.ListSessionsOut":{"properties":{"sessions":{"items":{"$ref":"#/components/schemas/iam.Session"},"type":"array"}},"type":"object"},"iam.ManagedAccount":{"properties":{"application":{"type":"string"},"signinUrl":{"type":"string"},"username":{"type":"string"}},"type":"object"},"iam.MfaAccount":{"properties":{"accountName":{"type":"string"},"issuer":{"type":"string"},"origin":{"type":"string"}},"type":"object"},"iam.MfaItem":{"properties":{"name":{"type":"string"},"rule":{"type":"string"}},"type":"object"},"iam.MfaProps":{"properties":{"countryCode":{"type":"string"},"enabled":{"type":"boolean"},"isPreferred":{"type":"boolean"},"mfaRememberInHours":{"format":"int64","type":"integer"},"mfaType":{"type":"string"},"url":{"type":"string"}},"type":"object"},"iam.Organization":{"properties":{"accountItems":{"items":{"$ref":"#/components/schemas/iam.AccountItem"},"type":"array"},"accountMenu":{"type":"string"},"avatar":{"description":"How the organization appears across Hanzo — the square mark beside its\nname — as an image or as one emoji, never both. It is the pair a person\ncarries (User.Avatar) under the same names, resolved the same way, so a\nscreen draws a subject without asking which kind of subject it has. Both\nhalves live on the row: a mark that appears everywhere cannot be kept on\none device. Written through schema.MarkOf; Logo and LogoDark above are a\ndifferent thing, the wordmark a login screen draws.","type":"string"},"balanceCredit":{"format":"double","type":"number"},"balanceCurrency":{"type":"string"},"countryCodes":{"items":{"type":"string"},"type":"array"},"createdAt":{"format":"date-time","type":"string"},"createdTime":{"type":"string"},"dcrPolicy":{"type":"string"},"defaultApplication":{"type":"string"},"defaultAvatar":{"type":"string"},"defaultPassword":{"type":"string"},"deleted":{"type":"boolean"},"disableSignin":{"type":"boolean"},"displayName":{"type":"string"},"emoji":{"type":"string"},"enableSoftDeletion":{"type":"boolean"},"enableTour":{"type":"boolean"},"failedSigninFrozenTime":{"format":"int64","type":"integer"},"failedSigninLimit":{"description":"Per-organization signin throttle. Zero means \"inherit the application\ndefault\"; a non-zero value overrides it. Safe bounds are clamped by the\nresource service before persistence.","format":"int64","type":"integer"},"favicon":{"type":"string"},"founder":{"description":"Founder is the stable storage id of the identity that provisioned this org\n(self-service onboarding). It is the resume token that makes provisioning\nconverge on a backend where each write autocommits independently (no\ntransaction rollback): after a partial failure that created the org but did\nnot move the founder in, a retry recognises the org as the founder's own and\ncompletes it, instead of refusing it as \"already taken\". It also fences the\norg to ONE tenant — a different identity can never complete or join it.","type":"string"},"hasPrivilegeConsent":{"type":"boolean"},"id":{"description":"Persisted fields","type":"string"},"initScore":{"format":"int64","type":"integer"},"ipRestriction":{"type":"string"},"ipWhitelist":{"type":"string"},"isPersonal":{"type":"boolean"},"isProfilePublic":{"type":"boolean"},"kerberosKdcHost":{"type":"string"},"kerberosKeytab":{"type":"string"},"kerberosRealm":{"type":"string"},"kerberosServiceName":{"type":"string"},"languages":{"items":{"type":"string"},"type":"array"},"ldapAttributes":{"items":{"type":"string"},"type":"array"},"logo":{"type":"string"},"logoDark":{"type":"string"},"masterPassword":{"type":"string"},"masterVerificationCode":{"type":"string"},"mfaItems":{"items":{"$ref":"#/components/schemas/iam.MfaItem"},"type":"array"},"mfaRememberInHours":{"format":"int64","type":"integer"},"name":{"type":"string"},"navItems":{"items":{"type":"string"},"type":"array"},"orgBalance":{"description":"Balance fields are read-only mirrors; authoritative balances live in\nCommerce (billing.hanzo.ai). Carried for field-complete v1 parity.","format":"double","type":"number"},"owner":{"type":"string"},"passwordExpireDays":{"format":"int64","type":"integer"},"passwordObfuscatorKey":{"type":"string"},"passwordObfuscatorType":{"type":"string"},"passwordOptions":{"items":{"type":"string"},"type":"array"},"passwordSalt":{"type":"string"},"passwordType":{"type":"string"},"platform":{"description":"Platform marks an organization the platform itself declares (init_data.json):\nthe brand orgs and the others the seed creates, never one a customer made. The\nseed stamps it on every declared organization at boot, and no request sets or\nclears it. Only a SuperAdmin may delete an organization that carries it.","type":"boolean"},"tags":{"items":{"type":"string"},"type":"array"},"themeData":{"$ref":"#/components/schemas/iam.ThemeData"},"updatedAt":{"format":"date-time","type":"string"},"useEmailAsUsername":{"type":"boolean"},"usePermanentAvatar":{"type":"boolean"},"userBalance":{"format":"double","type":"number"},"userNavItems":{"items":{"type":"string"},"type":"array"},"userTypes":{"items":{"type":"string"},"type":"array"},"websiteUrl":{"type":"string"},"widgetItems":{"items":{"type":"string"},"type":"array"}},"type":"object"},"iam.Permission":{"properties":{"actions":{"items":{"type":"string"},"type":"array"},"adapter":{"type":"string"},"approveTime":{"type":"string"},"approver":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"createdTime":{"description":"Descriptive metadata.","type":"string"},"deleted":{"type":"boolean"},"description":{"type":"string"},"displayName":{"type":"string"},"domains":{"items":{"type":"string"},"type":"array"},"effect":{"type":"string"},"id":{"description":"Persisted fields","type":"string"},"isEnabled":{"type":"boolean"},"model":{"description":"Authorization model, targets, and decision. AuthzModel carries the v1\n`model` column (the named authz model); it is not the Go identifier\n`Model` because that name is taken by the embedded orm.Model[Permission]\nmixin. The HTTP contract is unchanged — json:\"model\".","type":"string"},"name":{"type":"string"},"owner":{"description":"Identity — the (owner, name) natural key.","type":"string"},"resourceType":{"type":"string"},"resources":{"items":{"type":"string"},"type":"array"},"roles":{"items":{"type":"string"},"type":"array"},"state":{"type":"string"},"submitter":{"description":"Submission / approval workflow.","type":"string"},"teams":{"items":{"type":"string"},"type":"array"},"updatedAt":{"format":"date-time","type":"string"},"users":{"description":"Subjects the grant is evaluated for.","items":{"type":"string"},"type":"array"}},"type":"object"},"iam.Project":{"properties":{"createdAt":{"format":"date-time","type":"string"},"createdTime":{"type":"string"},"deleted":{"type":"boolean"},"description":{"type":"string"},"displayName":{"type":"string"},"id":{"description":"Persisted fields","type":"string"},"isDefault":{"type":"boolean"},"metadata":{"type":"string"},"name":{"type":"string"},"organization":{"type":"string"},"owner":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"},"updatedAt":{"format":"date-time","type":"string"},"workspace":{"type":"string"}},"type":"object"},"iam.Provider":{"properties":{"appId":{"type":"string"},"bucket":{"type":"string"},"category":{"type":"string"},"cert":{"type":"string"},"clientId":{"type":"string"},"clientId2":{"type":"string"},"clientSecret":{"type":"string"},"clientSecret2":{"type":"string"},"content":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"createdTime":{"type":"string"},"customAuthUrl":{"type":"string"},"customLogo":{"type":"string"},"customTokenUrl":{"type":"string"},"customUserInfoUrl":{"type":"string"},"deleted":{"type":"boolean"},"disableSsl":{"type":"boolean"},"displayName":{"type":"string"},"domain":{"type":"string"},"emailRegex":{"type":"string"},"enablePkce":{"type":"boolean"},"enableProxy":{"type":"boolean"},"enableSignAuthnRequest":{"type":"boolean"},"endpoint":{"type":"string"},"host":{"type":"string"},"httpHeaders":{"additionalProperties":{"type":"string"},"type":"object"},"id":{"description":"Persisted fields","type":"string"},"idP":{"type":"string"},"intranetEndpoint":{"type":"string"},"issuerUrl":{"type":"string"},"metadata":{"type":"string"},"method":{"type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"pathPrefix":{"type":"string"},"port":{"format":"int64","type":"integer"},"providerUrl":{"type":"string"},"receiver":{"type":"string"},"regionId":{"type":"string"},"scopes":{"type":"string"},"signName":{"type":"string"},"sslMode":{"type":"string"},"subType":{"type":"string"},"templateCode":{"type":"string"},"title":{"type":"string"},"type":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"userMapping":{"additionalProperties":{"type":"string"},"type":"object"}},"type":"object"},"iam.ProviderItem":{"properties":{"bindingRule":{"items":{"type":"string"},"type":"array"},"canSignIn":{"type":"boolean"},"canSignUp":{"type":"boolean"},"canUnlink":{"type":"boolean"},"countryCodes":{"items":{"type":"string"},"type":"array"},"name":{"type":"string"},"owner":{"type":"string"},"prompted":{"type":"boolean"},"provider":{"$ref":"#/components/schemas/iam.Provider"},"rule":{"type":"string"},"signupGroup":{"type":"string"}},"type":"object"},"iam.ReleaseOutput":{"properties":{"released":{"type":"boolean"}},"type":"object"},"iam.Role":{"properties":{"createdAt":{"format":"date-time","type":"string"},"createdTime":{"type":"string"},"deleted":{"type":"boolean"},"description":{"type":"string"},"displayName":{"type":"string"},"domains":{"items":{"type":"string"},"type":"array"},"id":{"description":"Persisted fields","type":"string"},"isEnabled":{"type":"boolean"},"name":{"type":"string"},"owner":{"type":"string"},"roles":{"items":{"type":"string"},"type":"array"},"teams":{"items":{"type":"string"},"type":"array"},"updatedAt":{"format":"date-time","type":"string"},"users":{"items":{"type":"string"},"type":"array"}},"type":"object"},"iam.SamlItem":{"properties":{"name":{"type":"string"},"nameFormat":{"type":"string"},"value":{"type":"string"}},"type":"object"},"iam.ScopeDescription":{"properties":{"description":{"type":"string"},"displayName":{"type":"string"},"scope":{"type":"string"}},"type":"object"},"iam.ScopeItem":{"properties":{"description":{"type":"string"},"displayName":{"type":"string"},"name":{"type":"string"},"tools":{"items":{"type":"string"},"type":"array"}},"type":"object"},"iam.SendOutput":{"properties":{"sent":{"type":"boolean"},"to":{"type":"string"}},"type":"object"},"iam.Session":{"properties":{"application":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"createdTime":{"type":"string"},"deleted":{"type":"boolean"},"exclusiveSignin":{"description":"ExclusiveSignin is a transient control flag (v1 xorm:\"-\"): a caller sets\nit on a create to collapse SessionId down to the single incoming cookie\ninstead of appending. It is never stored — a persisted session always\ncarries it false, so orm:\"-\" keeps it off the column backends and\nomitempty keeps it out of the SQLite JSON blob.","type":"boolean"},"id":{"description":"Persisted fields","type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"sessionId":{"items":{"type":"string"},"type":"array"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"iam.SetAvatarInput":{"properties":{"avatar":{"type":"string"},"emoji":{"type":"string"},"name":{"type":"string"},"owner":{"type":"string"}},"type":"object"},"iam.SetProfileInput":{"properties":{"displayName":{"type":"string"},"favicon":{"type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"websiteUrl":{"type":"string"}},"type":"object"},"iam.SigninItem":{"properties":{"customCss":{"type":"string"},"isCustom":{"type":"boolean"},"label":{"type":"string"},"name":{"type":"string"},"placeholder":{"type":"string"},"rule":{"type":"string"},"visible":{"type":"boolean"}},"type":"object"},"iam.SigninMethod":{"properties":{"displayName":{"type":"string"},"name":{"type":"string"},"rule":{"type":"string"}},"type":"object"},"iam.SignupItem":{"properties":{"customCss":{"type":"string"},"label":{"type":"string"},"name":{"type":"string"},"options":{"items":{"type":"string"},"type":"array"},"placeholder":{"type":"string"},"prompted":{"type":"boolean"},"regex":{"type":"string"},"required":{"type":"boolean"},"rule":{"type":"string"},"type":{"type":"string"},"visible":{"type":"boolean"}},"type":"object"},"iam.Team":{"properties":{"createdAt":{"format":"date-time","type":"string"},"createdTime":{"type":"string"},"deleted":{"type":"boolean"},"description":{"type":"string"},"displayName":{"type":"string"},"id":{"description":"Persisted fields","type":"string"},"isEnabled":{"type":"boolean"},"name":{"type":"string"},"organization":{"type":"string"},"owner":{"type":"string"},"parent":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"users":{"items":{"type":"string"},"type":"array"}},"type":"object"},"iam.ThemeData":{"properties":{"borderRadius":{"format":"int64","type":"integer"},"colorPrimary":{"type":"string"},"isCompact":{"type":"boolean"},"isEnabled":{"type":"boolean"},"themeType":{"type":"string"}},"type":"object"},"iam.Token":{"properties":{"accessToken":{"type":"string"},"accessTokenHash":{"type":"string"},"actor":{"description":"Actor is the SuperAdmin (\"owner/name\") who opened this grant AS its User —\nimpersonation, /v1/iam/impersonate — and Reason is why they said they did.\nBoth empty on every grant a person established themselves. A grant with an\nActor mints a short access token that names the actor in `act` and carries\n`imp`, and never a refresh token (issueTokens), and /v1/iam/signin refuses\nits code, so it cannot become a session at the issuer.","type":"string"},"application":{"type":"string"},"code":{"type":"string"},"codeChallenge":{"type":"string"},"codeChallengeMethod":{"type":"string"},"codeExpireIn":{"format":"int64","type":"integer"},"codeIsUsed":{"type":"boolean"},"createdAt":{"format":"date-time","type":"string"},"createdTime":{"type":"string"},"deleted":{"type":"boolean"},"expiresIn":{"format":"int64","type":"integer"},"id":{"description":"Persisted fields","type":"string"},"name":{"type":"string"},"nonce":{"description":"Nonce is the OIDC authorize nonce, stored on the code and echoed into the\nid_token minted at the exchange (OIDC Core §3.1.3.6) so a relying party\nbinds the id_token to its own request and detects replay.","type":"string"},"organization":{"type":"string"},"owner":{"type":"string"},"publicGrant":{"description":"PublicGrant records that this grant was established WITHOUT client\nauthentication — a PKCE code exchange from a client that presented no\nsecret. Whether a client is confidential is a property of the GRANT, not\nonly of the registration: `hanzo-cli` and every @hanzo/iam SPA keep a\nregistered secret for a BACKEND path while the surface that actually signs\nin is a public PKCE client that cannot hold one. authorizationCodeGrant\nalready makes exactly that bounded relaxation; this is the same fact,\nrecorded so refreshTokenGrant can honour it instead of demanding a secret\nthe client never had (which 401s invalid_client and kills the session at\nthe access token's expiry). Carried across rotation, so the second refresh\nbehaves like the first.","type":"boolean"},"reason":{"type":"string"},"redirectUri":{"description":"RedirectUri binds the authorization code to the exact redirect URI of the\nauthorize request (RFC 6749 §4.1.3): the token endpoint refuses a code\nredeemed with a different redirect_uri, closing code-injection across a\nclient's registered URIs.","type":"string"},"refreshConsumed":{"type":"boolean"},"refreshExpireIn":{"format":"int64","type":"integer"},"refreshFamily":{"description":"Refresh-token rotation state (v2). Each refresh belongs to a family (the\ngrant); rotation mints a new row in the same family and marks the prior\none consumed. Presenting a consumed refresh is reuse — the whole family is\nrevoked (RFC 9700 §4.14.2). RefreshExpireIn is the refresh token's own\nabsolute expiry (unix), independent of the access token's shorter life.","type":"string"},"refreshToken":{"type":"string"},"refreshTokenHash":{"type":"string"},"resource":{"description":"RFC 8707 resource indicator","type":"string"},"scope":{"type":"string"},"tokenType":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"user":{"type":"string"},"userCode":{"type":"string"}},"type":"object"},"iam.Tombstone":{"properties":{"createdAt":{"format":"date-time","type":"string"},"createdTime":{"type":"string"},"deleted":{"type":"boolean"},"founder":{"description":"Founder carries the deleted org's founder, so an org counted against its\nfounder's cap stays counted after it is deleted.","type":"string"},"id":{"description":"Persisted fields","type":"string"},"name":{"description":"the organization's name","type":"string"},"owner":{"description":"the admin registry, as for organizations","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"iam.UpdateInput":{"properties":{"password":{"type":"string"},"user":{"$ref":"#/components/schemas/iam.User"}},"type":"object"},"iam.UpdateOrganizationInput":{"properties":{"accountItems":{"items":{"$ref":"#/components/schemas/iam.AccountItem"},"type":"array"},"accountMenu":{"type":"string"},"avatar":{"description":"How the organization appears across Hanzo — the square mark beside its\nname — as an image or as one emoji, never both. It is the pair a person\ncarries (User.Avatar) under the same names, resolved the same way, so a\nscreen draws a subject without asking which kind of subject it has. Both\nhalves live on the row: a mark that appears everywhere cannot be kept on\none device. Written through schema.MarkOf; Logo and LogoDark above are a\ndifferent thing, the wordmark a login screen draws.","type":"string"},"balanceCredit":{"format":"double","type":"number"},"balanceCurrency":{"type":"string"},"countryCodes":{"items":{"type":"string"},"type":"array"},"createdAt":{"format":"date-time","type":"string"},"createdTime":{"type":"string"},"dcrPolicy":{"type":"string"},"defaultApplication":{"type":"string"},"defaultAvatar":{"type":"string"},"defaultPassword":{"type":"string"},"deleted":{"type":"boolean"},"disableSignin":{"type":"boolean"},"displayName":{"type":"string"},"emoji":{"type":"string"},"enableSoftDeletion":{"type":"boolean"},"enableTour":{"type":"boolean"},"failedSigninFrozenTime":{"format":"int64","type":"integer"},"failedSigninLimit":{"description":"Per-organization signin throttle. Zero means \"inherit the application\ndefault\"; a non-zero value overrides it. Safe bounds are clamped by the\nresource service before persistence.","format":"int64","type":"integer"},"favicon":{"type":"string"},"founder":{"description":"Founder is the stable storage id of the identity that provisioned this org\n(self-service onboarding). It is the resume token that makes provisioning\nconverge on a backend where each write autocommits independently (no\ntransaction rollback): after a partial failure that created the org but did\nnot move the founder in, a retry recognises the org as the founder's own and\ncompletes it, instead of refusing it as \"already taken\". It also fences the\norg to ONE tenant — a different identity can never complete or join it.","type":"string"},"hasPrivilegeConsent":{"type":"boolean"},"id":{"description":"Persisted fields","type":"string"},"initScore":{"format":"int64","type":"integer"},"ipRestriction":{"type":"string"},"ipWhitelist":{"type":"string"},"isPersonal":{"type":"boolean"},"isProfilePublic":{"type":"boolean"},"kerberosKdcHost":{"type":"string"},"kerberosKeytab":{"type":"string"},"kerberosRealm":{"type":"string"},"kerberosServiceName":{"type":"string"},"languages":{"items":{"type":"string"},"type":"array"},"ldapAttributes":{"items":{"type":"string"},"type":"array"},"logo":{"type":"string"},"logoDark":{"type":"string"},"masterPassword":{"type":"string"},"masterVerificationCode":{"type":"string"},"mfaItems":{"items":{"$ref":"#/components/schemas/iam.MfaItem"},"type":"array"},"mfaRememberInHours":{"format":"int64","type":"integer"},"name":{"type":"string"},"navItems":{"items":{"type":"string"},"type":"array"},"orgBalance":{"description":"Balance fields are read-only mirrors; authoritative balances live in\nCommerce (billing.hanzo.ai). Carried for field-complete v1 parity.","format":"double","type":"number"},"owner":{"type":"string"},"passwordExpireDays":{"format":"int64","type":"integer"},"passwordObfuscatorKey":{"type":"string"},"passwordObfuscatorType":{"type":"string"},"passwordOptions":{"items":{"type":"string"},"type":"array"},"passwordSalt":{"type":"string"},"passwordType":{"type":"string"},"platform":{"description":"Platform marks an organization the platform itself declares (init_data.json):\nthe brand orgs and the others the seed creates, never one a customer made. The\nseed stamps it on every declared organization at boot, and no request sets or\nclears it. Only a SuperAdmin may delete an organization that carries it.","type":"boolean"},"tags":{"items":{"type":"string"},"type":"array"},"themeData":{"$ref":"#/components/schemas/iam.ThemeData"},"updatedAt":{"format":"date-time","type":"string"},"useEmailAsUsername":{"type":"boolean"},"usePermanentAvatar":{"type":"boolean"},"userBalance":{"format":"double","type":"number"},"userNavItems":{"items":{"type":"string"},"type":"array"},"userTypes":{"items":{"type":"string"},"type":"array"},"websiteUrl":{"type":"string"},"widgetItems":{"items":{"type":"string"},"type":"array"}},"type":"object"},"iam.UpdateSessionIn":{"properties":{"application":{"type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"sessionId":{"items":{"type":"string"},"type":"array"}},"required":["owner","name","application"],"type":"object"},"iam.User":{"properties":{"accessKey":{"description":"API credentials. AccessSecret / AccessSecretHash / the OAuth tokens are\nbearer material, so Mask blanks them and the handler's redact() strips them\nbefore responding. They carry real json tags because a field orm never saves\nis a field that silently vanishes.\n\nA presented secret is resolved through Key.AccessSecretDigest and nowhere\nelse, so no credential is ISSUED into these columns: they hold what older\nrows left behind, and every writer that touches them clears them.","type":"string"},"accessSecret":{"type":"string"},"accessSecretHash":{"type":"string"},"accessToken":{"type":"string"},"address":{"items":{"type":"string"},"type":"array"},"addresses":{"items":{"$ref":"#/components/schemas/iam.Address"},"type":"array"},"adfs":{"type":"string"},"affiliation":{"type":"string"},"alipay":{"type":"string"},"amazon":{"type":"string"},"apple":{"type":"string"},"applicationScopes":{"items":{"$ref":"#/components/schemas/iam.ConsentRecord"},"type":"array"},"auth0":{"type":"string"},"avatar":{"type":"string"},"avatarType":{"type":"string"},"azuread":{"type":"string"},"azureadb2c":{"type":"string"},"baidu":{"type":"string"},"balance":{"description":"Balance mirrors v1 for lossless migration but is authoritative in\nCommerce (billing.hanzo.ai), not here — do not write it from IAM.","format":"double","type":"number"},"balanceCredit":{"format":"double","type":"number"},"balanceCurrency":{"type":"string"},"battlenet":{"type":"string"},"bilibili":{"type":"string"},"bio":{"type":"string"},"birthday":{"type":"string"},"bitbucket":{"type":"string"},"box":{"type":"string"},"cart":{"items":{"$ref":"#/components/schemas/iam.CartItem"},"type":"array"},"cloudfoundry":{"type":"string"},"countryCode":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"createdIp":{"description":"Sign-in provenance.","type":"string"},"createdTime":{"type":"string"},"currency":{"type":"string"},"custom":{"type":"string"},"custom10":{"type":"string"},"custom2":{"type":"string"},"custom3":{"type":"string"},"custom4":{"type":"string"},"custom5":{"type":"string"},"custom6":{"type":"string"},"custom7":{"type":"string"},"custom8":{"type":"string"},"custom9":{"type":"string"},"dailymotion":{"type":"string"},"deezer":{"type":"string"},"deleted":{"type":"boolean"},"deletedTime":{"type":"string"},"digitalocean":{"type":"string"},"dingtalk":{"type":"string"},"discord":{"type":"string"},"displayName":{"description":"Profile.","type":"string"},"douyin":{"type":"string"},"dropbox":{"type":"string"},"education":{"type":"string"},"email":{"type":"string"},"emailVerified":{"type":"boolean"},"eveonline":{"type":"string"},"externalId":{"type":"string"},"faceIds":{"items":{"$ref":"#/components/schemas/iam.FaceId"},"type":"array"},"facebook":{"type":"string"},"firstName":{"type":"string"},"fitbit":{"type":"string"},"gender":{"type":"string"},"gitea":{"type":"string"},"gitee":{"type":"string"},"github":{"description":"Linked federated-identity subjects, one column per connector (v1 parity).","type":"string"},"gitlab":{"type":"string"},"google":{"type":"string"},"hash":{"type":"string"},"heroku":{"type":"string"},"homepage":{"type":"string"},"iam":{"type":"string"},"id":{"description":"Id is the user's STABLE OPAQUE identifier — the value the OIDC `sub` claim\ncarries. It is the v1 the legacy surface per-row UUID (e.g.\n\"e7d7fda0-4c53-4508-9d35-7ec892b7e5d7\"), migrated verbatim so a user's `sub`\nis byte-identical across the cutover: every live session, external reference,\nand the downstream money-path principal keyed on `sub` survive unchanged. A\nuser minted natively in v2 is assigned a fresh UUID here on create, so the\n`sub` is ALWAYS a stable opaque id going forward — never the (Owner, Name)\npair, which is mutable (a rename would otherwise silently reissue identity).\n\nIt is distinct from the embedded orm.Model STORAGE KEY — the value the datastore\nlocks and looks a row up by — which is NOT (Owner, Name) for every row: a MIGRATED\nlegacy row is stamped \"owner/name\" (SetId in the migrator), but a v2-native\nusers.Create'd row is NOT — Create allocates rather than pinning a key, so its\nstorage key is a store-assigned surrogate id (a decimal string like\n\"17847909129933610000001\"). (Owner, Name) is therefore the natural/QUERY key\n(unique, indexed), not necessarily the storage key: resolve a row for a locked\nwrite by its REAL key (store.GetUserByName(...).Key().Encode(), which stamps both\nshapes — see internal/oidc updateUser), never by assuming \"owner/name\". This Id is\na first-class, indexed DOMAIN field; its json tag \"id\" dominates the promoted\norm.Model `Id_` (also \"id\") by shallower depth, so the persisted record's \"id\" is\nthis UUID — exactly the v1 shape. A row that carries no Id (a not-yet-assigned\npre-cutover user) falls back to the (Owner, Name) subject at mint; every other\npath resolves `sub`→user by Id.","type":"string"},"idCard":{"type":"string"},"idCardType":{"type":"string"},"influxcloud":{"type":"string"},"infoflow":{"type":"string"},"instagram":{"type":"string"},"intercom":{"type":"string"},"invitation":{"type":"string"},"invitationCode":{"type":"string"},"ipWhitelist":{"type":"string"},"isAdmin":{"type":"boolean"},"isDefaultAvatar":{"description":"State flags.","type":"boolean"},"isDeleted":{"type":"boolean"},"isForbidden":{"type":"boolean"},"isOnline":{"type":"boolean"},"isVerified":{"type":"boolean"},"kakao":{"type":"string"},"karma":{"format":"int64","type":"integer"},"kwai":{"type":"string"},"language":{"type":"string"},"lark":{"type":"string"},"lastChangePasswordTime":{"type":"string"},"lastName":{"type":"string"},"lastSigninIp":{"type":"string"},"lastSigninTime":{"type":"string"},"lastSigninWrongTime":{"type":"string"},"lastfm":{"type":"string"},"ldap":{"type":"string"},"line":{"type":"string"},"linkedin":{"type":"string"},"location":{"type":"string"},"mailru":{"type":"string"},"managedAccounts":{"items":{"$ref":"#/components/schemas/iam.ManagedAccount"},"type":"array"},"meetup":{"type":"string"},"mfaAccounts":{"items":{"$ref":"#/components/schemas/iam.MfaAccount"},"type":"array"},"mfaEmailEnabled":{"type":"boolean"},"mfaItems":{"items":{"$ref":"#/components/schemas/iam.MfaItem"},"type":"array"},"mfaPhoneEnabled":{"type":"boolean"},"mfaPushEnabled":{"type":"boolean"},"mfaPushProvider":{"type":"string"},"mfaPushReceiver":{"type":"string"},"mfaRadiusEnabled":{"type":"boolean"},"mfaRadiusProvider":{"type":"string"},"mfaRadiusUsername":{"type":"string"},"mfaRememberDeadline":{"type":"string"},"mfaRememberDigest":{"description":"MfaRememberDigest is the digest of the token held by the ONE browser the\ndeadline above applies to. Without it the deadline is account-wide and \"don't\nask again on this browser\" switches the second factor off everywhere. It is a\ndigest, never the token, so a database dump yields nothing presentable — and it\ncarries a REAL json tag because orm persists via json.Marshal, so `json:\"-\"`\nwould never be stored (the trap PasswordHash documents above); Mask() strips it\nfrom every response instead.","type":"string"},"microsoftonline":{"type":"string"},"multiFactorAuths":{"items":{"$ref":"#/components/schemas/iam.MfaProps"},"type":"array"},"name":{"type":"string"},"nameKey":{"description":"NameKey is Fold(Name), derived on every save (BeforeCreate, BeforeUpdate) and\non every open for a row saved without it (store.Prepare): the indexed key a\ncase-insensitive username lookup reads (store.GetUserByName). It is always\nwritten, empty or not, so a row that has been keyed is never mistaken for one\nthat has not.","readOnly":true,"type":"string"},"naver":{"type":"string"},"needUpdatePassword":{"type":"boolean"},"nextcloud":{"type":"string"},"okta":{"type":"string"},"onedrive":{"type":"string"},"originalRefreshToken":{"type":"string"},"originalToken":{"type":"string"},"oura":{"type":"string"},"owner":{"description":"Identity / tenancy. (Owner, Name) is the natural key.","type":"string"},"passwordHash":{"description":"Credential material. PasswordHash is a one-way bcrypt digest and is\nverify-only. It MUST be persisted (orm serializes the entity to its JSON\ndata column, so a json:\"-\" field would never be stored — that silently\nbroke login), so it carries a real json tag; the users API redact() strips\nit (and every other secret) from every response. PasswordType and\nPasswordSalt describe the digest scheme so rows hashed under the legacy\nargon2id scheme can still be verified and lazily re-hashed to bcrypt.","type":"string"},"passwordSalt":{"type":"string"},"passwordType":{"type":"string"},"patreon":{"type":"string"},"paypal":{"type":"string"},"permanentAvatar":{"type":"string"},"phone":{"type":"string"},"preHash":{"type":"string"},"preferredMfaType":{"type":"string"},"properties":{"additionalProperties":{"type":"string"},"type":"object"},"qq":{"type":"string"},"ranking":{"format":"int64","type":"integer"},"realName":{"type":"string"},"recoveryCodes":{"items":{"type":"string"},"type":"array"},"region":{"type":"string"},"registerSource":{"type":"string"},"registerType":{"type":"string"},"salesforce":{"type":"string"},"score":{"format":"int64","type":"integer"},"shopify":{"type":"string"},"signinWrongTimes":{"format":"int64","type":"integer"},"signupApplication":{"type":"string"},"slack":{"type":"string"},"soundcloud":{"type":"string"},"spotify":{"type":"string"},"steam":{"type":"string"},"strava":{"type":"string"},"stripe":{"type":"string"},"tag":{"type":"string"},"telegram":{"type":"string"},"tiktok":{"type":"string"},"title":{"type":"string"},"totpSecret":{"type":"string"},"tumblr":{"type":"string"},"twitch":{"type":"string"},"twitter":{"type":"string"},"type":{"type":"string"},"typetalk":{"type":"string"},"uber":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"updatedTime":{"type":"string"},"verificationCode":{"type":"string"},"vk":{"type":"string"},"webauthnCredentials":{"description":"Multi-factor authentication. TotpSecret and RecoveryCodes are secret\nverify-only material — the handler strips them from every response.\nWebauthnCredentials is carried as raw JSON here for lossless migration;\nthe typed passkey model is the sibling WebauthnCredential entity.","items":{},"type":"array"},"wechat":{"type":"string"},"wecom":{"type":"string"},"weibo":{"type":"string"},"wepay":{"type":"string"},"xero":{"type":"string"},"yahoo":{"type":"string"},"yammer":{"type":"string"},"yandex":{"type":"string"},"zoom":{"type":"string"}},"type":"object"},"iam.WebauthnCredential":{"properties":{"aaguid":{"contentEncoding":"base64","type":"string"},"attachment":{"type":"string"},"attestationFormat":{"description":"AttestationFormat is the statement format the authenticator attested in\n(\"packed\", \"apple\", \"none\", …), which is a DIFFERENT value from the\nattestation type above. The library reads it back when resolving the FIDO\nAppID extension, so a row that dropped it would round-trip a credential the\nverifier no longer recognises as the one it stored.","type":"string"},"attestationType":{"type":"string"},"backupEligible":{"type":"boolean"},"backupState":{"type":"boolean"},"cloneWarning":{"type":"boolean"},"createdAt":{"format":"date-time","type":"string"},"createdTime":{"type":"string"},"credentialId":{"contentEncoding":"base64","type":"string"},"deleted":{"type":"boolean"},"id":{"description":"Persisted fields","type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"publicKey":{"contentEncoding":"base64","type":"string"},"signCount":{"format":"uint32","type":"integer"},"transport":{"items":{"type":"string"},"type":"array"},"updatedAt":{"format":"date-time","type":"string"},"user":{"type":"string"},"userPresent":{"type":"boolean"},"userVerified":{"type":"boolean"}},"type":"object"},"iam.Workspace":{"properties":{"bucket":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"createdTime":{"type":"string"},"deleted":{"type":"boolean"},"description":{"type":"string"},"displayName":{"type":"string"},"id":{"description":"Persisted fields","type":"string"},"isDefault":{"type":"boolean"},"metadata":{"type":"string"},"name":{"type":"string"},"organization":{"type":"string"},"owner":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"iam.acceptBody":{"properties":{"code":{"type":"string"},"emailCode":{"type":"string"},"owner":{"type":"string"}},"type":"object"},"iam.accountBody":{"properties":{"avatar":{"type":"string"},"bio":{"type":"string"},"displayName":{"type":"string"},"homepage":{"type":"string"}},"type":"object"},"iam.auditlogs.DeleteOutput":{"properties":{"deleted":{"type":"boolean"}},"type":"object"},"iam.auditlogs.Input":{"properties":{"action":{"type":"string"},"clientIp":{"type":"string"},"createdTime":{"type":"string"},"isTriggered":{"type":"boolean"},"language":{"type":"string"},"method":{"type":"string"},"name":{"type":"string"},"object":{"type":"string"},"organization":{"type":"string"},"owner":{"type":"string"},"requestUri":{"type":"string"},"response":{"type":"string"},"statusCode":{"format":"int64","type":"integer"},"user":{"type":"string"}},"type":"object"},"iam.auditlogs.ListOutput":{"properties":{"auditLogs":{"items":{"$ref":"#/components/schemas/iam.AuditLog"},"type":"array"},"total":{"format":"int64","type":"integer"}},"type":"object"},"iam.bulk":{"properties":{"maxOperations":{"format":"int64","type":"integer"},"maxPayloadSize":{"format":"int64","type":"integer"},"supported":{"type":"boolean"}},"type":"object"},"iam.certs.DeleteOutput":{"properties":{"deleted":{"type":"boolean"}},"type":"object"},"iam.certs.ListOutput":{"properties":{"certs":{"items":{"$ref":"#/components/schemas/iam.Cert"},"type":"array"},"total":{"format":"int64","type":"integer"}},"type":"object"},"iam.config":{"properties":{"authenticationSchemes":{"items":{"$ref":"#/components/schemas/iam.scheme"},"type":"array"},"bulk":{"$ref":"#/components/schemas/iam.bulk"},"changePassword":{"$ref":"#/components/schemas/iam.toggle"},"documentationUri":{"type":"string"},"etag":{"$ref":"#/components/schemas/iam.toggle"},"filter":{"$ref":"#/components/schemas/iam.filter"},"patch":{"$ref":"#/components/schemas/iam.toggle"},"schemas":{"items":{"type":"string"},"type":"array"},"sort":{"$ref":"#/components/schemas/iam.toggle"}},"type":"object"},"iam.filter":{"properties":{"maxResults":{"format":"int64","type":"integer"},"supported":{"type":"boolean"}},"type":"object"},"iam.identifierBody":{"properties":{"clientId":{"description":"ClientId is the application's OAuth client id.","type":"string"},"identifier":{"description":"Identifier is the email address the person typed.","type":"string"}},"type":"object"},"iam.invitations.DeleteOutput":{"properties":{"deleted":{"type":"boolean"}},"type":"object"},"iam.invitations.Input":{"properties":{"application":{"type":"string"},"code":{"type":"string"},"createdTime":{"type":"string"},"defaultCode":{"type":"string"},"displayName":{"type":"string"},"email":{"type":"string"},"isRegexp":{"type":"boolean"},"name":{"type":"string"},"owner":{"type":"string"},"phone":{"type":"string"},"quota":{"format":"int64","type":"integer"},"signupGroup":{"type":"string"},"state":{"type":"string"},"updatedTime":{"type":"string"},"usedCount":{"format":"int64","type":"integer"},"username":{"type":"string"}},"type":"object"},"iam.invitations.ListOutput":{"properties":{"invitations":{"items":{"$ref":"#/components/schemas/iam.Invitation"},"type":"array"},"total":{"format":"int64","type":"integer"}},"type":"object"},"iam.keys.DeleteResponse":{"properties":{"deleted":{"type":"boolean"}},"type":"object"},"iam.keys.ListResponse":{"properties":{"keys":{"items":{"$ref":"#/components/schemas/iam.Key"},"type":"array"}},"type":"object"},"iam.listProvidersOut":{"properties":{"providers":{"items":{"$ref":"#/components/schemas/iam.Provider"},"type":"array"}},"type":"object"},"iam.listResponse":{"properties":{"Resources":{"items":{},"type":"array"},"itemsPerPage":{"format":"int64","type":"integer"},"schemas":{"items":{"type":"string"},"type":"array"},"startIndex":{"format":"int64","type":"integer"},"totalResults":{"format":"int64","type":"integer"}},"type":"object"},"iam.listTokensOut":{"properties":{"tokens":{"items":{"$ref":"#/components/schemas/iam.Token"},"type":"array"}},"type":"object"},"iam.listWebauthnCredentialsOut":{"properties":{"webauthnCredentials":{"items":{"$ref":"#/components/schemas/iam.WebauthnCredential"},"type":"array"}},"type":"object"},"iam.mutationResult":{"properties":{"affected":{"type":"boolean"},"provider":{"$ref":"#/components/schemas/iam.Provider"}},"type":"object"},"iam.passwordBody":{"properties":{"code":{"description":"Code is the one-time code delivered to the account's own address.","type":"string"},"oldPassword":{"description":"OldPassword is the credential being replaced, the proof a signed-in caller\ngives instead of a code.","type":"string"},"organization":{"description":"The account being recovered, for a caller who cannot be signed in. Read on\nthe CODE arm only — a signed-in caller is resolved from its own session or\ntoken, never from these.","type":"string"},"password":{"description":"Password is the new credential. It must satisfy the platform floor and the\norganization's own complexity options.","type":"string"},"username":{"description":"email, username OR phone","type":"string"}},"type":"object"},"iam.person":{"properties":{"displayName":{"type":"string"},"email":{"type":"string"},"isAdmin":{"type":"boolean"},"name":{"type":"string"},"owner":{"type":"string"},"password":{"type":"string"},"passwordType":{"type":"string"},"phone":{"type":"string"}},"type":"object"},"iam.projects.DeleteOutput":{"properties":{"deleted":{"type":"boolean"}},"type":"object"},"iam.projects.Input":{"properties":{"createdTime":{"type":"string"},"description":{"type":"string"},"displayName":{"type":"string"},"isDefault":{"type":"boolean"},"metadata":{"type":"string"},"name":{"type":"string"},"organization":{"type":"string"},"owner":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"},"workspace":{"type":"string"}},"type":"object"},"iam.projects.ListOutput":{"properties":{"projects":{"items":{"$ref":"#/components/schemas/iam.Project"},"type":"array"},"total":{"format":"int64","type":"integer"}},"type":"object"},"iam.providerResult":{"properties":{"provider":{"$ref":"#/components/schemas/iam.Provider"}},"type":"object"},"iam.registration":{"properties":{"cert":{"type":"string"},"clientId":{"type":"string"},"clientSecret":{"type":"string"},"displayName":{"type":"string"},"enableCodeSignin":{"description":"EnableCodeSignin offers sign-in by an emailed or texted one-time code\nbeside the password. A POINTER for the same reason as IsShared: a plain\nbool reads as false on every reconcile that says nothing and would switch\nthe method off for every app whose caller never mentioned it.","type":"boolean"},"expireInHours":{"description":"ExpireInHours and RefreshExpireInHours are the application's token\nlifetimes. They are the ONLY declarative way to say that a refresh token\nmust OUTLIVE its access token: with neither stated, oidc.refreshTTL clamps\nthe refresh lifetime to the access lifetime, so the refresh_token grant the\nregistration advertises expires at the same instant as the token it was\nmeant to renew and can never be exercised. `hanzo-cli` sat in exactly that\nstate — a browser re-login every hour, and a live refresh returning 401.\n\nPOINTERS, for the same reason as IsShared: a plain float would read as 0 on\nevery reconcile that says nothing and reset a deliberate lifetime back to\nthe default. Nil means \"not stated, leave it\".","format":"double","type":"number"},"grantTypes":{"items":{"type":"string"},"type":"array"},"isShared":{"description":"IsShared declares that this application serves EVERY organization, not only\nthe one named in Organization. It is the honest description of a brand app —\nhanzo-id, hanzo-chat, a brand console — whose customers each live in their own\ntenant: self-service onboarding moves a founder OUT of the brand org, so\n`user.Owner != app.Organization` is the steady state and the app really does\nserve every org. Application.ServesOrg reads it as one of the three ways to\nsay yes.\n\nA POINTER because omission must PRESERVE. This upsert is the operator's\nsteady-state reconcile and most callers say nothing about sharing; a plain\nbool would read as false on every one of them and silently un-share an app —\nthe same shape of accident that de-secreted apps through update-application.\nNil means \"not stated, leave it\"; only an explicit true or false moves it.","type":"boolean"},"name":{"type":"string"},"organization":{"type":"string"},"public":{"description":"Public declares a client that CANNOT hold a credential — a browser SPA,\na CLI, a desktop app. It proves itself with PKCE instead, and the token\nendpoint treats \"no stored secret\" as exactly that (token.go: a secret is\nverified only when one is stored). Without this flag every upsert minted\na secret, so a public client could never be registered at all and its\nbrowser code-\u003etoken exchange 401'd `invalid_client` forever.","type":"boolean"},"redirectUris":{"items":{"type":"string"},"type":"array"},"refreshExpireInHours":{"format":"double","type":"number"}},"type":"object"},"iam.reply":{"properties":{"action":{"type":"string"},"data":{},"msg":{"type":"string"},"status":{"type":"string"}},"type":"object"},"iam.roles.DeleteOutput":{"properties":{"deleted":{"type":"boolean"}},"type":"object"},"iam.roles.ListOutput":{"properties":{"roles":{"items":{"$ref":"#/components/schemas/iam.Role"},"type":"array"},"total":{"format":"int64","type":"integer"}},"type":"object"},"iam.scheme":{"properties":{"description":{"type":"string"},"name":{"type":"string"},"primary":{"type":"boolean"},"type":{"type":"string"}},"type":"object"},"iam.teams.DeleteOutput":{"properties":{"deleted":{"type":"boolean"}},"type":"object"},"iam.teams.Input":{"properties":{"createdTime":{"type":"string"},"description":{"type":"string"},"displayName":{"type":"string"},"isEnabled":{"type":"boolean"},"name":{"description":"Name addresses the team on update and names it on create; every other\nfield is content and binds from the BODY, never the URL.","type":"string"},"organization":{"type":"string"},"parent":{"type":"string"},"users":{"items":{"type":"string"},"type":"array"}},"type":"object"},"iam.teams.ListOutput":{"properties":{"teams":{"items":{"$ref":"#/components/schemas/iam.Team"},"type":"array"},"total":{"format":"int64","type":"integer"}},"type":"object"},"iam.termsBody":{"properties":{"aup":{"type":"string"},"terms":{"type":"string"}},"type":"object"},"iam.toggle":{"properties":{"supported":{"type":"boolean"}},"type":"object"},"iam.tokenMutation":{"properties":{"affected":{"type":"boolean"},"token":{"$ref":"#/components/schemas/iam.Token"}},"type":"object"},"iam.tokenResult":{"properties":{"token":{"$ref":"#/components/schemas/iam.Token"}},"type":"object"},"iam.webauthnCredentialMutationResult":{"properties":{"affected":{"type":"boolean"},"webauthnCredential":{"$ref":"#/components/schemas/iam.WebauthnCredential"}},"type":"object"},"iam.webauthnCredentialResult":{"properties":{"webauthnCredential":{"$ref":"#/components/schemas/iam.WebauthnCredential"}},"type":"object"},"iam.workspaces.DeleteOutput":{"properties":{"deleted":{"type":"boolean"}},"type":"object"},"iam.workspaces.Input":{"properties":{"bucket":{"type":"string"},"createdTime":{"type":"string"},"description":{"type":"string"},"displayName":{"type":"string"},"isDefault":{"type":"boolean"},"metadata":{"type":"string"},"name":{"type":"string"},"organization":{"type":"string"},"owner":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"}},"type":"object"},"iam.workspaces.ListOutput":{"properties":{"total":{"format":"int64","type":"integer"},"workspaces":{"items":{"$ref":"#/components/schemas/iam.Workspace"},"type":"array"}},"type":"object"},"index.indexCount":{"properties":{"isIndexing":{"description":"IsIndexing is always false: writes are applied before their response, so\nthere is never a background pass a caller could be waiting on.","type":"boolean"},"numberOfDocuments":{"description":"NumberOfDocuments is how many documents this org holds in that index.","format":"int64","type":"integer"}},"type":"object"},"index.indexDocuments":{"properties":{"limit":{"description":"Limit is how many documents this page could hold.","format":"int64","type":"integer"},"offset":{"description":"Offset is where this page starts.","format":"int64","type":"integer"},"results":{"description":"Results are the documents themselves, exactly as they were stored.","items":{},"type":"array"},"total":{"description":"Total is how many documents the index holds altogether.","format":"int64","type":"integer"}},"type":"object"},"index.indexEnqueued":{"properties":{"enqueuedAt":{"description":"EnqueuedAt is when the task was recorded, RFC 3339 — which is also when it\ncompleted.","type":"string"},"indexUid":{"description":"IndexUID names the index the write landed in.","type":"string"},"status":{"description":"Status is always `enqueued`, for dialect compatibility. The work is\nalready done.","type":"string"},"taskUid":{"description":"TaskUID identifies the task for a client that polls it. Polling resolves\nimmediately.","format":"int64","type":"integer"},"type":{"description":"Type is the dialect's name for the kind of write: indexCreation,\nindexDeletion, settingsUpdate, documentAdditionOrUpdate, documentDeletion.","type":"string"}},"type":"object"},"index.indexFilter":{"properties":{"filterableAttributes":{"description":"FilterableAttributes replaces the whole filterable set. Omitted leaves it\nunchanged; an empty array clears it.","items":{"type":"string"},"type":"array"}},"type":"object"},"index.indexHealth":{"properties":{"status":{"description":"Status is `available` when the store is readable and `unavailable` when it\nis not — the second answer rides a 503, so a pod with a broken volume is\ntaken out of rotation rather than serving empty searches.","type":"string"}},"type":"object"},"index.indexHits":{"properties":{"estimatedTotalHits":{"description":"EstimatedTotalHits is the dialect's name for the match count. Every hit is\nmaterialised here, so for this page it is exact rather than estimated.","format":"int64","type":"integer"},"hits":{"description":"Hits are the matching documents, most relevant first, exactly as stored.","items":{},"type":"array"},"limit":{"description":"Limit is how many hits this page could hold.","format":"int64","type":"integer"},"offset":{"description":"Offset is where this page starts.","format":"int64","type":"integer"},"processingTimeMs":{"description":"ProcessingTimeMs is how long the query took, in milliseconds.","format":"int64","type":"integer"},"query":{"description":"Query echoes the search terms, which is what a client renders above the\nresults.","type":"string"}},"type":"object"},"index.indexList":{"properties":{"limit":{"description":"Limit is how many rows this page could hold.","format":"int64","type":"integer"},"offset":{"description":"Offset is where this page starts.","format":"int64","type":"integer"},"results":{"description":"Results are the index definitions themselves.","items":{"$ref":"#/components/schemas/index.indexView"},"type":"array"},"total":{"description":"Total is how many indexes the org holds altogether.","format":"int64","type":"integer"}},"type":"object"},"index.indexNew":{"properties":{"primaryKey":{"description":"PrimaryKey is the document field that identifies a row. Optional — the\nfirst write establishes one when it is omitted.","type":"string"},"uid":{"description":"UID is the index's name within the org. Required.","type":"string"}},"type":"object"},"index.indexQuery":{"properties":{"filter":{"description":"Filter narrows the hits, in the dialect's filter syntax: a string, or an\narray of strings combined with AND. Only attributes named in the index's\nfilterableAttributes can be constrained. Left unconstrained here because\nthe dialect accepts both shapes and naming one would publish an API that\ncannot send the other."},"limit":{"description":"Limit is how many hits to return. Absent means 20; the ceiling is 1000.","format":"int64","type":"integer"},"offset":{"description":"Offset is where to start. Absent means 0.","format":"int64","type":"integer"},"q":{"description":"Q is the search text. Typos are forgiven. An empty Q matches everything,\nwhich is how a client lists an index by relevance rather than by insertion\norder.","type":"string"}},"type":"object"},"index.indexSettings":{"properties":{"filterableAttributes":{"description":"FilterableAttributes are the document fields a search `filter` may\nconstrain. A field not listed here cannot be filtered on.","items":{"type":"string"},"type":"array"}},"type":"object"},"index.indexStats":{"properties":{"databaseSize":{"description":"DatabaseSize is the org's total document count across its indexes. It is a\ncount, not bytes: the store is shared by every tenant, so a byte figure\nwould either be the whole file (another tenant's size) or a fiction.","format":"int64","type":"integer"},"indexes":{"additionalProperties":{"$ref":"#/components/schemas/index.indexCount"},"description":"Indexes maps each index uid to its own count.","type":"object"}},"type":"object"},"index.indexTask":{"properties":{"enqueuedAt":{"description":"EnqueuedAt, StartedAt and FinishedAt are the same instant: the write was\napplied before its task id was minted.","type":"string"},"finishedAt":{"description":"FinishedAt is when the write completed.","type":"string"},"startedAt":{"description":"StartedAt is when the write began.","type":"string"},"status":{"description":"Status is always `succeeded`.","type":"string"},"type":{"description":"Type names the kind of write, for a client that inspects it.","type":"string"},"uid":{"description":"UID echoes the task id that was asked about.","format":"int64","type":"integer"}},"type":"object"},"index.indexVersion":{"properties":{"commitDate":{"description":"CommitDate is empty here: this surface is a dialect implementation, not a\nbuild of Meilisearch, so there is no upstream commit to date.","type":"string"},"commitSha":{"description":"CommitSha names the implementation (`hanzo-cloud`) rather than a build\nhash, so a client logging it records which server answered instead of\nimplying a Meilisearch release.","type":"string"},"pkgVersion":{"description":"PkgVersion is this dialect implementation's own version.","type":"string"}},"type":"object"},"index.indexView":{"properties":{"createdAt":{"description":"CreatedAt is when this org first created the index, RFC 3339.","type":"string"},"primaryKey":{"description":"PrimaryKey is the document field that identifies a row; an upsert is keyed\non it. Empty until a document establishes one.","type":"string"},"uid":{"description":"UID is the index's name within the org. Two orgs may both hold `messages`.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the index or its settings last changed, RFC 3339.","type":"string"}},"type":"object"},"indexEnqueued":{"properties":{"enqueuedAt":{"type":"string"},"indexUid":{"type":"string"},"status":{"type":"string"},"taskUid":{"type":"integer"},"type":{"type":"string"}},"type":"object"},"ingress.Backend":{"properties":{"url":{"description":"URL is the upstream server, http(s)://host[:port].","type":"string"},"weight":{"description":"Weight is this member's share of the round-robin; must be \u003e= 0.","format":"int64","type":"integer"}},"type":"object"},"ingress.Middleware":{"properties":{"config":{"additionalProperties":{"type":"string"},"description":"Config is the transform's parameters: redirectScheme takes scheme (default\nhttps) and permanent (\"true\" ⇒ 301, else 302); stripPrefix REQUIRES\nprefixes (comma-separated, first match wins); addPrefix REQUIRES prefix;\nheaders is a header→value map set on the response.","type":"object"},"id":{"description":"ID identifies the transform within the org: [A-Za-z0-9-_.], at most 128\nchars. A create that omits it gets a generated one. Routes reference it by\nthis id.","type":"string"},"type":{"description":"Type is the transform: redirectScheme, stripPrefix, addPrefix or headers.","type":"string"}},"type":"object"},"ingress.Route":{"properties":{"host":{"description":"Host is the exact hostname this route matches, lowercased with any trailing\ndot stripped. It is a GLOBALLY unique claim — one route across the whole\nedge may hold a host, so no tenant can hijack another's.","type":"string"},"id":{"description":"ID identifies the route within the org: [A-Za-z0-9-_.], at most 128 chars.\nA create that omits it gets a generated one.","type":"string"},"middlewares":{"description":"Middlewares are the ids of the edge transforms to apply, in this order,\nbefore the request reaches the service. At most 16.","items":{"type":"string"},"type":"array"},"pathPrefix":{"description":"PathPrefix narrows the match to requests under this path; it must start\nwith \"/\". Empty matches every path on the host.","type":"string"},"priority":{"description":"Priority orders routes that share a host: higher wins, and equal priorities\nfall back to the longer PathPrefix.","format":"int64","type":"integer"},"service":{"description":"Service is the id of the backend pool this route dispatches to. A route\nnaming a service that does not exist is skipped at compile, not served.","type":"string"},"tls":{"description":"TLS asks the edge to terminate TLS for Host with an ACME-managed certificate.","type":"boolean"}},"type":"object"},"ingress.TLSConfig":{"properties":{"acmeEmail":{"description":"ACMEEmail is the ACME account email. It binds an account for the lifetime\nof an edge process, so it applies only when the edge (re)starts.","type":"string"},"extraHosts":{"description":"ExtraHosts get certificates without owning a route — at most 256. They feed\nthe ACME HostPolicy and hot-apply on the next reload.","items":{"type":"string"},"type":"array"},"staging":{"description":"Staging issues from Let's Encrypt's staging directory (untrusted certs, high\nrate limits). Like ACMEEmail it applies only when the edge (re)starts.","type":"boolean"}},"type":"object"},"ingress.Upstream":{"properties":{"backends":{"description":"Backends are the upstream servers to balance across: 1..32 of them.","items":{"$ref":"#/components/schemas/ingress.Backend"},"type":"array"},"id":{"description":"ID identifies the pool within the org: [A-Za-z0-9-_.], at most 128 chars.\nA create that omits it gets a generated one. Routes reference it by this id.","type":"string"},"passHostHeader":{"description":"PassHostHeader forwards the client's original Host header upstream instead\nof rewriting it to the backend's.","type":"boolean"}},"type":"object"},"ingress.ingressMiddlewares":{"properties":{"middlewares":{"description":"Middlewares is the org's middlewares, ordered by id.","items":{"$ref":"#/components/schemas/ingress.Middleware"},"type":"array"}},"type":"object"},"ingress.ingressRoutes":{"properties":{"routes":{"description":"Routes is the org's routes, ordered by id.","items":{"$ref":"#/components/schemas/ingress.Route"},"type":"array"}},"type":"object"},"ingress.ingressServices":{"properties":{"services":{"description":"Services is the org's services, ordered by id.","items":{"$ref":"#/components/schemas/ingress.Upstream"},"type":"array"}},"type":"object"},"ingress.ingressStatus":{"properties":{"acmeCacheDir":{"description":"ACMECacheDir is where autocert persists accounts and certificates.","type":"string"},"acmeStaging":{"description":"ACMEStaging is true when certificates are issued from Let's Encrypt staging.","type":"boolean"},"edgeEnabled":{"description":"EdgeEnabled is true when the edge listeners are actually bound.","type":"boolean"},"httpAddr":{"description":"HTTPAddr is the address the ACME HTTP-01 + HTTP router listens on.","type":"string"},"httpsAddr":{"description":"HTTPSAddr is the address the SNI TLS terminator listens on.","type":"string"},"liveHosts":{"description":"LiveHosts is how many hosts the compiled table routes.","format":"int64","type":"integer"},"proxy":{"description":"Proxy names the reverse-proxy implementation behind every route.","type":"string"},"role":{"description":"Role is \"edge\" when CLOUD_INGRESS_EDGE_ENABLED is set, else \"app\".","type":"string"},"tlsHosts":{"description":"TLSHosts is how many hosts the ACME HostPolicy will issue a certificate\nfor. NOT a subset of LiveHosts: an extraHost owns no route, and a TLS route\nnaming a missing service is skipped while its host still wants a cert.","format":"int64","type":"integer"}},"type":"object"},"ingress.ingressTLS":{"properties":{"acmeDirectory":{"description":"ACMEDirectory is the ACME endpoint in use: the staging URL, or\n\"letsencrypt-production\".","type":"string"},"acmeEmail":{"description":"ACMEEmail is the account email the PROCESS was started with\n(CLOUD_INGRESS_ACME_EMAIL), not the stored config's.","type":"string"},"config":{"$ref":"#/components/schemas/ingress.TLSConfig","description":"Config is the caller org's stored ACME intent."},"edgeEnabled":{"description":"EdgeEnabled is true when the edge listeners are actually bound.","type":"boolean"},"managedHosts":{"description":"ManagedHosts is every host the ACME HostPolicy will issue a certificate for\n— the union across ALL orgs of TLS-marked routes and configured extraHosts,\nbecause one process holds one certificate cache.","items":{"type":"string"},"type":"array"},"note":{"description":"Note states which fields hot-apply and which need an edge restart.","type":"string"},"role":{"description":"Role is \"edge\" when this instance binds the listeners, else \"app\".","type":"string"}},"type":"object"},"insightsBody":{"properties":{"batch":{"items":{"$ref":"#/components/schemas/insightsEvent"},"type":"array"},"distinct_id":{"type":"string"},"event":{"type":"string"},"properties":{"additionalProperties":{},"type":"object"},"timestamp":{"type":"string"},"uuid":{"type":"string"}},"type":"object"},"insightsEvent":{"properties":{"distinct_id":{"type":"string"},"event":{"type":"string"},"properties":{"additionalProperties":{},"type":"object"},"timestamp":{"type":"string"},"uuid":{"type":"string"}},"type":"object"},"kms.SecretMeta":{"properties":{"env":{"description":"Env is the environment the secret belongs to. It is part of the storage\nkey, so the same name in two environments is two secrets.","type":"string"},"name":{"description":"Name is the secret's name within its path and environment.","type":"string"},"path":{"description":"Path is the subpath the secret is stored under, beneath the org root.","type":"string"},"scheme":{"description":"Scheme names how the value is sealed at rest, so a caller can tell a\nmigrated record from a current one without opening it.","type":"string"}},"type":"object"},"kms.kmsConfig":{"properties":{"apiBase":{"description":"APIBase is this subsystem's own prefix, `/v1/kms`.","type":"string"},"brand":{"description":"Brand is the deployment's brand, so the console renders as the right\nproduct.","type":"string"},"issuer":{"description":"Issuer is the OIDC issuer the console authenticates against.","type":"string"},"loginPath":{"description":"LoginPath is the credential exchange's address.","type":"string"}},"type":"object"},"kms.kmsHealth":{"properties":{"audit":{"description":"Audit is the state of the audit trail every access is recorded to: `ok`,\n`failing` when it did not take the last record, or `absent` when this\nprocess has none. Every access is refused in the last two. Absent from the\nanswer when there is no in-process client to audit.","type":"string"},"enforcing":{"description":"Enforcing is whether a secret value the declaration in force does not\ngrant is refused. False while it says `enforce: false` and while none has\nloaded; every such value is then logged and audited as would-deny.","type":"boolean"},"error":{"description":"Error is the honest reason readiness is false: no in-process KMS client,\nor no master key. Absent when ready.","type":"string"},"policy":{"description":"Policy is the sha256 of the grant declaration in force, so a probe can\nprove which one is live. Absent when none has ever loaded, which measures:\nthe rule each caller had before still decides.","type":"string"},"ready":{"description":"Ready is whether a secret operation would actually succeed right now.\nThese are exactly the states in which the secret operations refuse.","type":"boolean"},"refused":{"description":"Refused is what the MOUNTED declaration reads as — its sha256, or \"absent\"\nor \"unreadable\" — when it is not the one in force: a document cloud refused\nto parse, or a mount that went away. The declaration in force stays, so a\nbad edit changes nothing, and this is where it shows.","type":"string"},"service":{"description":"Service names the subsystem answering, `kms`.","type":"string"},"signing":{"description":"Signing reports whether signing keys are configured. Absent when there is\nno in-process client to ask.","type":"boolean"},"status":{"description":"Status is `ok` or `degraded`, the one-word form of Ready.","type":"string"}},"type":"object"},"kms.kmsLogin":{"properties":{"clientId":{"description":"ClientID is the machine identity's id, as IAM issued it.","type":"string"},"clientSecret":{"description":"ClientSecret is that identity's secret. It is never logged, never echoed,\nand never carried in an error.","type":"string"}},"type":"object"},"kms.kmsPut":{"properties":{"env":{"description":"Env is the environment to write under. REQUIRED, with no default: it is\npart of the storage key, so a silently defaulted write lands in a bucket\nthe readers that resolve project, environment and path never look in, and\nthe stale value keeps being served.","type":"string"},"name":{"description":"Name is the secret's name. Required.","type":"string"},"path":{"description":"Path is an optional subpath beneath the org root, e.g. \"/ci\".","type":"string"},"value":{"description":"Value is the secret itself. It is sealed under a fresh per-secret data key\nbefore storage, so plaintext never reaches disk, and it is never echoed\nback, logged, or carried in an error.","type":"string"}},"type":"object"},"kms.kmsSecrets":{"properties":{"names":{"description":"Names is the same listing reduced to bare names, which is the shape the\nKMS operator reads. Both are emitted so either consumer keeps working.","items":{"type":"string"},"type":"array"},"secrets":{"description":"Secrets are the descriptors: name, path, environment and sealing scheme.\nNo value and no ciphertext appears here.","items":{"$ref":"#/components/schemas/kms.SecretMeta"},"type":"array"},"total":{"description":"Total is how many descriptors this listing carries.","format":"int64","type":"integer"}},"type":"object"},"kms.kmsStored":{"properties":{"env":{"description":"Env is the environment the secret was written under.","type":"string"},"name":{"description":"Name is the secret's name.","type":"string"},"stored":{"description":"Stored is true; a write confirms by not failing.","type":"boolean"}},"type":"object"},"kms.kmsToken":{"properties":{"accessToken":{"description":"AccessToken is IAM's own JWT, verbatim. Its `owner` claim scopes it to\nexactly one org, which is what every secret operation then reads.","type":"string"},"expiresIn":{"description":"ExpiresIn is the token's lifetime in seconds, as IAM reported it.","format":"int64","type":"integer"},"tokenType":{"description":"TokenType is `Bearer`.","type":"string"}},"type":"object"},"knowledge.File":{"properties":{"bucket":{"description":"Bucket is the org bucket the object is in, by the friendly name\n/v1/s3/buckets lists.","type":"string"},"chars":{"description":"Chars is the length of the text read out of the file, in bytes.","format":"int64","type":"integer"},"clipped":{"description":"Clipped is true when only the file's beginning is indexed: its text ran\npast the org's bound or the room the index has. Note says how far.","type":"boolean"},"created":{"description":"Created is when the file was first registered, in unix seconds.","format":"int64","type":"integer"},"done":{"description":"Done is how far the running stage has come, of Total: bytes of the file\nread (extract), sections summarized (toc), cut into passages (passages)\nand linked (graph), passages embedded (embed). Absent between stages and\nonce the ingest is done.","format":"int64","type":"integer"},"embedded":{"description":"Embedded is how many of those passages carry a vector — Passages once the\nembed stage is done, unless Note says the file is embedded in part.","format":"int64","type":"integer"},"error":{"description":"Error is why a stored or failed file was not indexed — or, on a ready\nfile, why it is searched by its words alone — in words a person can act\non. Absent otherwise.","type":"string"},"id":{"description":"ID names the file in its org. It is derived from the bucket and key, so\nregistering the same object twice answers the same file.","type":"string"},"key":{"description":"Key is the object's key in that bucket. GET\n/v1/s3/buckets/{bucket}/objects/{key} answers a signed download URL for it.","type":"string"},"name":{"description":"Name is the object's file name, the last segment of its key.","type":"string"},"note":{"description":"Note says in words where the file is indexed less than whole and why: its\ntext past the org's bound or the room the index has, its passages past\nthe bound on vectors. Absent when the whole file is indexed every way.","type":"string"},"parent":{"description":"Parent is the id of the archive this file was unpacked from. Absent for a\nfile uploaded on its own.","type":"string"},"passages":{"description":"Passages is how many passages its text was cut into.","format":"int64","type":"integer"},"project":{"description":"Project is the project scope it is indexed under. Absent for the org's\nown files.","type":"string"},"sections":{"description":"Sections is how many nodes its table of contents has, the document's own\nroot included.","format":"int64","type":"integer"},"size":{"description":"Size is the object's length in bytes, as the store reports it.","format":"int64","type":"integer"},"stage":{"description":"Stage is the ingest stage the file is in: extract, toc, passages or graph\nwhile indexing, embed while a ready file's vectors are written. Absent once\nthe ingest is done.","type":"string"},"status":{"description":"Status is queued, indexing, ready, stored (kept but not indexed — Error\nsays why) or failed. A ready file's contents, passages and links are all\nreadable and its full text is searched; its vectors may still be filling\nin (Stage embed), which adds search by meaning as it goes.","type":"string"},"total":{"description":"Total is what the running stage has to do in all, in Done's units.","format":"int64","type":"integer"},"type":{"description":"Type is the object's media type as the store holds it, or the one its\nname implies when the store holds only the generic default.","type":"string"},"updated":{"description":"Updated is when its record last changed, in unix seconds.","format":"int64","type":"integer"}},"type":"object"},"knowledge.catalogEntry":{"properties":{"configured":{"description":"Configured is whether THIS DEPLOYMENT holds the OAuth client credentials for\nthe provider. False means Connect would dead-end, so the console can offer it\ndisabled instead of broken. It is deployment-wide and says nothing about\nwhether the caller's org has connected the source — that is the connector\nlist's `status`.","type":"boolean"},"description":{"description":"Description is one line of shop copy: what connecting this source pulls in.\nNative connectors carry written prose; a provider-backed one reads\n\"activepieces connector (\u003cprovider\u003e)\".","type":"string"},"displayName":{"description":"DisplayName is the label to show a person. First-party connectors carry a\nwritten name (\"GitHub\", \"Google Drive\"); a provider-backed one falls back to the\nprovider capitalized, because the rich activepieces metadata lives behind a\ncross-service call this read will not make.","type":"string"},"kind":{"description":"\"native\" | \"provider\"","type":"string"},"provider":{"description":"Provider is the source's id and the address every connector op takes it by\n(/v1/knowledge/connectors/:provider). One of github, slack, google, notion.","type":"string"}},"type":"object"},"knowledge.catalogOut":{"properties":{"connectors":{"description":"Connectors is every connectable source, sorted by provider.","items":{"$ref":"#/components/schemas/knowledge.catalogEntry"},"type":"array"}},"type":"object"},"knowledge.citedPassage":{"properties":{"cite":{"description":"Cite is how an answer cites it: file › section path › ¶part.","type":"string"},"file":{"$ref":"#/components/schemas/knowledge.fileBrief","description":"File is the file the passage is from."},"part":{"description":"Part is the passage's place in its section, from 1.","format":"int64","type":"integer"},"score":{"description":"Score is the fused rank score, comparable within one response only.","format":"double","type":"number"},"section":{"$ref":"#/components/schemas/knowledge.sectionBrief","description":"Section is the section it is in."},"text":{"description":"Text is the passage: a span of its section of about 2000 bytes, never\ncrossing into another section.","type":"string"},"via":{"description":"Via is how retrieval reached it: search (it matched), toc (it is in a\nsection the table of contents pointed at) or graph (a linked section).","type":"string"},"why":{"description":"Why says, for a passage reached through the graph, which edge led there.","type":"string"}},"type":"object"},"knowledge.connectionOut":{"properties":{"account":{"description":"Account names the connected external account, when the provider reports one.","type":"string"},"provider":{"description":"Provider is the connector this answer is about.","type":"string"},"status":{"description":"Status is the connection state: connected or disconnected.","type":"string"}},"type":"object"},"knowledge.connectorView":{"properties":{"account":{"description":"Account names the connected external account. Absent until the org connects.","type":"string"},"configured":{"description":"Configured is true when this deployment holds OAuth credentials for the provider.","type":"boolean"},"docCount":{"description":"DocCount is the live count of this provider's documents in the org's store.","format":"int64","type":"integer"},"error":{"description":"Error is the last sync failure, if any. Absent until the org connects.","type":"string"},"kind":{"description":"Kind is \"native\" for a first-party Go connector, \"provider\" for a long-tail one.","type":"string"},"lastSync":{"description":"LastSync is when the last pull finished. Absent until the org connects.","type":"string"},"provider":{"description":"Provider is the connector's id.","type":"string"},"status":{"description":"Status is connected, disconnected, syncing or error.","type":"string"}},"type":"object"},"knowledge.fileBrief":{"properties":{"bucket":{"description":"Bucket and Key are where its bytes are: GET\n/v1/s3/buckets/{bucket}/objects/{key} answers a signed download URL.","type":"string"},"id":{"description":"ID is the file's id.","type":"string"},"key":{"description":"Key is the object's key in Bucket.","type":"string"},"name":{"description":"Name is the file's name.","type":"string"},"type":{"description":"Type is the file's media type.","type":"string"}},"type":"object"},"knowledge.fileEntity":{"properties":{"files":{"description":"Files is how many other files of the org name it too.","format":"int64","type":"integer"},"kind":{"description":"Kind is person, org, product, place or term.","type":"string"},"name":{"description":"Name is the entity as the text names it.","type":"string"},"sections":{"description":"Sections is how many of the file's sections name it.","format":"int64","type":"integer"}},"type":"object"},"knowledge.fileGraph":{"properties":{"entities":{"description":"Entities are the entities it names, most mentioned first.","items":{"$ref":"#/components/schemas/knowledge.fileEntity"},"type":"array"},"file":{"$ref":"#/components/schemas/knowledge.File","description":"File is the file the graph is of."},"links":{"description":"Links are the other files it is joined to, strongest first.","items":{"$ref":"#/components/schemas/knowledge.fileLink"},"type":"array"}},"type":"object"},"knowledge.fileIn":{"properties":{"bucket":{"description":"Bucket is one of the org's buckets, by the friendly name /v1/s3/buckets\nlists. Required.","type":"string"},"key":{"description":"Key is the object's key in that bucket, as the upload wrote it. Required.","type":"string"},"project":{"description":"Project indexes the file under one project scope. Empty is the org's own.","type":"string"}},"type":"object"},"knowledge.fileLink":{"properties":{"direction":{"description":"Direction is out when this file links to the other, in when the other\nlinks to this one, and shared when the two name the same entities.","type":"string"},"file":{"description":"File is the other file, by id.","type":"string"},"kind":{"description":"Kind is href (a hyperlink), cites (the text names the file), xref (a\ncross-reference inside one document) or entity (shared mentions).","type":"string"},"label":{"description":"Label is the link's own text, or the entities the two files share.","type":"string"},"name":{"description":"Name is the other file's name.","type":"string"},"weight":{"description":"Weight is how many edges of this kind join the two; for shared entities,\nhow many entities they share.","format":"int64","type":"integer"}},"type":"object"},"knowledge.fileSearchIn":{"properties":{"files":{"description":"Files restricts the search to these file ids. Empty searches every file\nthe org holds.","items":{"type":"string"},"type":"array"},"limit":{"description":"Limit bounds the passages returned. Default 8, maximum 50.","format":"int64","type":"integer"},"project":{"description":"Project restricts the search to files indexed under one project scope.","type":"string"},"query":{"description":"Query is the question or phrase. Required.","type":"string"}},"type":"object"},"knowledge.fileSearchOut":{"properties":{"degraded":{"description":"Degraded is true when a leg failed — the query could not be embedded, or\nthe full-text index could not be read — and Passages are what the other\nleg found.","type":"boolean"},"passages":{"description":"Passages are the matching passages, best first, at most Limit.","items":{"$ref":"#/components/schemas/knowledge.citedPassage"},"type":"array"}},"type":"object"},"knowledge.filesOut":{"properties":{"files":{"description":"Files are the org's files, most recently changed first.","items":{"$ref":"#/components/schemas/knowledge.File"},"type":"array"}},"type":"object"},"knowledge.forgotten":{"properties":{"id":{"description":"ID is the file whose index was removed.","type":"string"}},"type":"object"},"knowledge.graphEdge":{"properties":{"from":{"description":"From is the id of the node the edge starts at: the child page for a parent\nedge, the page holding the wikilink for a link edge, the kb.source for a\nprovenance edge. Always one of Nodes.","type":"string"},"kind":{"description":"parent | link | provenance","type":"string"},"to":{"description":"To is the id of the node the edge points at: the parent page, the linked\npage, the kb.connector. Always one of Nodes — a wikilink matching no page\npoints at a synthetic \"unresolved:\u003clowercased title\u003e\" node rather than\ndangling.","type":"string"}},"type":"object"},"knowledge.graphNode":{"properties":{"id":{"description":"\"\u003cdoctype\u003e:\u003cname\u003e\" — globally unique, click-to-open key","type":"string"},"name":{"description":"the document name (empty for synthetic nodes)","type":"string"},"project":{"description":"Project is the project scope the underlying document was saved under. Absent\nfor a document saved with none, and for the synthetic nodes — unresolved link\ntargets and connectors belong to no project. When ?project= narrows the\ngraph, every page, memory and source node carries that value.","type":"string"},"title":{"description":"display label","type":"string"},"type":{"description":"kb.page | kb.memory | kb.source | kb.connector | unresolved","type":"string"}},"type":"object"},"knowledge.graphOut":{"properties":{"degraded":{"description":"Degraded is true when the store was unreachable and this graph is honestly\nempty rather than wrong. Absent on a normal answer.","type":"boolean"},"edges":{"description":"Edges are the parent tree, the resolved wikilinks and the connector provenance.","items":{"$ref":"#/components/schemas/knowledge.graphEdge"},"type":"array"},"nodes":{"description":"Nodes are the pages, memories, sources, connectors and unresolved link targets.","items":{"$ref":"#/components/schemas/knowledge.graphNode"},"type":"array"}},"type":"object"},"knowledge.hit":{"properties":{"doctype":{"description":"DocType is which kind of knowledge matched, by address: kb.page (a wiki\npage), kb.memory (a unit of agent memory) or kb.source (a document a\nconnector ingested).\nThose three are the whole indexed set, and searchIn.DocTypes filters on them.","type":"string"},"name":{"description":"Name is the document's name in the framework store — the id to read or open\nit with. Unique per (org, doctype), so it identifies the document with\nDocType and not alone.","type":"string"},"project":{"description":"Project is the project scope the document was saved under. Absent for a\ndocument saved with none, which is also why a project-scoped query cannot\nreach it.","type":"string"},"provider":{"description":"Provider is the connector that ingested the document — github, slack, google\nor notion. Absent for a page or memory written in the product, which came\nfrom no connector.","type":"string"},"score":{"description":"Score is the cosine similarity between the query's embedding and the\ndocument's BEST-matching passage, from -1 to 1, higher being closer. A\ndocument is cut into passages of about 2000 bytes, each embedded on its own,\nso a fact deep in a long page scores as high as one in its first paragraph.\n0 for a document only the lexical leg found, which has no similarity to\nreport. There is no absolute cutoff: what counts as a good score moves with\nthe query and the embedding model, so compare scores within one response and\nnot across queries.","format":"double","type":"number"},"title":{"description":"Title is the document's title. Empty for a document saved without one; it\nis a label to show, never the id (that is Name).","type":"string"},"url":{"description":"URL is the document's link back into the app it was ingested from. Absent\nwhen the document carries none, which is the normal case for pages and\nmemories.","type":"string"}},"type":"object"},"knowledge.kbAuthorizeOut":{"properties":{"authorizeUrl":{"description":"AuthorizeURL is the provider's authorize endpoint with an org-bound signed state.","type":"string"}},"type":"object"},"knowledge.kbConnectorsOut":{"properties":{"connectors":{"description":"Connectors is every supported provider with this org's connection state.","items":{"$ref":"#/components/schemas/knowledge.connectorView"},"type":"array"}},"type":"object"},"knowledge.kbSyncOut":{"properties":{"ingested":{"description":"Ingested is how many documents landed in the org's knowledge store.","format":"int64","type":"integer"},"provider":{"description":"Provider is the connector that was pulled.","type":"string"}},"type":"object"},"knowledge.pickedSection":{"properties":{"file":{"$ref":"#/components/schemas/knowledge.fileBrief","description":"File is the file it is in."},"section":{"$ref":"#/components/schemas/knowledge.sectionBrief","description":"Section is where it is."},"summary":{"description":"Summary is its one-line account.","type":"string"}},"type":"object"},"knowledge.reindexOut":{"properties":{"failed":{"description":"Failed is how many documents could not be indexed; each is logged with its\nname and has no passages — the rest of the rebuild went on without it.","format":"int64","type":"integer"},"lexical":{"description":"Lexical is how many rows the org's lexical index holds now; 0 in a\ndeployment without the index app.","format":"int64","type":"integer"},"removed":{"description":"Removed is how many rows the lexical index held for documents that no\nlonger exist; 0 without the index app.","format":"int64","type":"integer"},"vectors":{"description":"Vectors is how many documents were read back, cut into passages, embedded\nand written to the org's passage store, which was emptied first — so it now\nholds these documents' passages and nothing else.","format":"int64","type":"integer"}},"type":"object"},"knowledge.retrieveIn":{"properties":{"files":{"description":"Files are the files the question is about — the files a chat message\nreferences. Empty asks the whole workspace. The graph may still reach\nfiles beyond them.","items":{"type":"string"},"type":"array"},"limit":{"description":"Limit bounds the passages drilled out of the chosen sections. Default 8,\nmaximum 24. The graph adds up to four more.","format":"int64","type":"integer"},"project":{"description":"Project restricts retrieval to files indexed under one project scope.","type":"string"},"query":{"description":"Query is the question to answer. Required.","type":"string"}},"type":"object"},"knowledge.retrieveOut":{"properties":{"degraded":{"description":"Degraded is true when a search leg failed along the way.","type":"boolean"},"passages":{"description":"Passages are the passages drilled out of those sections, then those the\ngraph reached, each citing file › section › paragraph.","items":{"$ref":"#/components/schemas/knowledge.citedPassage"},"type":"array"},"picked":{"description":"Picked says how the sections were chosen: whole when the documents were\nshort enough to read every section, model when a model read the tables of\ncontents, search when the sections of the best passages stood in — the\ndocuments had no headings to choose by, or no model answered.","type":"string"},"sections":{"description":"Sections are the sections chosen from the candidate documents' tables of\ncontents.","items":{"$ref":"#/components/schemas/knowledge.pickedSection"},"type":"array"}},"type":"object"},"knowledge.searchIn":{"properties":{"doctypes":{"description":"DocTypes restricts retrieval to a subset of the indexed knowledge doctypes\n(kb.page, kb.memory, kb.source). An empty or foreign list reads all of them.","items":{"type":"string"},"type":"array"},"limit":{"description":"Limit bounds the hits returned. Default 10, maximum 50.","format":"int64","type":"integer"},"project":{"description":"Project narrows retrieval to one project scope.","type":"string"},"query":{"description":"Query is the natural-language question. Required.","type":"string"}},"type":"object"},"knowledge.searchOut":{"properties":{"degraded":{"description":"Degraded is true when a leg FAILED — the query could not be embedded, or a\nstore could not be read — and Hits are what the other leg found, possibly\nnothing. A RAG caller continues with what it got instead of failing the turn.\nAbsent on a normal answer, including one from a deployment that runs only\none of the legs.","type":"boolean"},"hits":{"description":"Hits are the matching documents, most relevant first: the order is the two\nlegs fused, so a document both the semantic and the keyword leg found comes\nbefore one only a single leg found.","items":{"$ref":"#/components/schemas/knowledge.hit"},"type":"array"}},"type":"object"},"knowledge.sectionBrief":{"properties":{"id":{"description":"ID is the section's number in its file's table of contents; 0 is the\ndocument itself.","format":"int64","type":"integer"},"path":{"description":"Path is the section's place in its document: the titles from the\ndocument's own down to it, joined by \" › \".","type":"string"},"title":{"description":"Title is the section's heading.","type":"string"}},"type":"object"},"knowledge.sectionLink":{"properties":{"file":{"$ref":"#/components/schemas/knowledge.fileBrief","description":"File is the file the linked section is in."},"kind":{"description":"Kind is href, xref, cites, or entity (the two sections name the same\nentities).","type":"string"},"label":{"description":"Label is the link's text, or the entities the two share.","type":"string"},"section":{"$ref":"#/components/schemas/knowledge.sectionBrief","description":"Section is the linked section."}},"type":"object"},"knowledge.sectionOut":{"properties":{"children":{"description":"Children are its subsections, to open next.","items":{"$ref":"#/components/schemas/knowledge.tocEntry"},"type":"array"},"entities":{"description":"Entities are the entities it names.","items":{"$ref":"#/components/schemas/knowledge.fileEntity"},"type":"array"},"file":{"$ref":"#/components/schemas/knowledge.fileBrief","description":"File is the file it is in."},"links":{"description":"Links are the sections the graph reaches from it, strongest first.","items":{"$ref":"#/components/schemas/knowledge.sectionLink"},"type":"array"},"section":{"$ref":"#/components/schemas/knowledge.sectionBrief","description":"Section is where it is."},"summary":{"description":"Summary is its one-line account.","type":"string"},"text":{"description":"Text is its own text — up to its first subsection — at most 64 KB.","type":"string"}},"type":"object"},"knowledge.tocEntry":{"properties":{"id":{"description":"ID is the section's number; 0 is the document itself.","format":"int64","type":"integer"},"level":{"description":"Level is its depth: 0 for the document, 1 for a top-level heading.","format":"int64","type":"integer"},"parent":{"description":"Parent is the id of the section it sits in; -1 for the document.","format":"int64","type":"integer"},"size":{"description":"Size is how many bytes of the document it spans, subsections included.","format":"int64","type":"integer"},"summary":{"description":"Summary is a one-line account of what it covers.","type":"string"},"synthetic":{"description":"Synthetic is true for a section the index cut out of a long run of text\nthe document gave no structure to.","type":"boolean"},"title":{"description":"Title is its heading.","type":"string"}},"type":"object"},"knowledge.tocOut":{"properties":{"file":{"$ref":"#/components/schemas/knowledge.File","description":"File is the file it is of."},"sections":{"description":"Sections are its nodes in document order, the document first; Parent\nmakes them a tree.","items":{"$ref":"#/components/schemas/knowledge.tocEntry"},"type":"array"}},"type":"object"},"kv.bucketRecord":{"properties":{"bucket":{"description":"Bucket is the bucket's name within the org.","type":"string"},"history":{"description":"History is how many revisions each key keeps.","format":"int64","type":"integer"},"ttl":{"description":"TTL is the entry expiry in seconds; 0 means none.","format":"int64","type":"integer"},"values":{"description":"Values is how many values the bucket holds right now.","format":"uint64","type":"integer"}},"type":"object"},"kv.bucketWrite":{"properties":{"bucket":{"description":"Bucket is the bucket's name within the org, from the path: 1–64 of\n[A-Za-z0-9_], no dash.","type":"string"},"history":{"description":"History is how many revisions each key keeps, 1–64. 0 means 1.","format":"int64","type":"integer"},"maxValue":{"description":"MaxValue caps one value's size in bytes. 0 or less means the server's\nceiling.","format":"int64","type":"integer"},"ttl":{"description":"TTL expires entries after this many SECONDS. 0 means no expiry.","format":"int64","type":"integer"}},"type":"object"},"kv.kvAck":{"properties":{"revision":{"description":"Revision is the revision the write created.","format":"uint64","type":"integer"}},"type":"object"},"kv.kvEntry":{"properties":{"created":{"description":"Created is when this revision was written, RFC3339.","type":"string"},"key":{"description":"Key is the entry's key.","type":"string"},"operation":{"description":"Operation is what wrote the revision: put, del or purge.","type":"string"},"revision":{"description":"Revision is the entry's revision in the bucket.","format":"uint64","type":"integer"},"value":{"description":"Value is the value as UTF-8 text; empty for delete and purge markers.","type":"string"}},"type":"object"},"kv.kvPage":{"properties":{"data":{"description":"Data are the key's retained revisions.","items":{"$ref":"#/components/schemas/kv.kvEntry"},"type":"array"}},"type":"object"},"kv.kvWrite":{"properties":{"bucket":{"description":"Bucket is the bucket, from the path.","type":"string"},"key":{"description":"Key is the key, from the path.","type":"string"},"value":{"description":"Value is the value, carried verbatim as UTF-8 text (typically JSON).","type":"string"}},"type":"object"},"label.riskDisposeIn":{"properties":{"before":{"description":"Before disposes of assertions WRITTEN before this instant, RFC 3339. It is\nmeasured against the server clock at the write and not against the event\nor observation times, both of which the asserting caller supplies — a\ntenant that could back-date could delete a compliance record on demand.","type":"string"}},"type":"object"},"label.riskDisposeOut":{"properties":{"before":{"description":"Before echoes the retention boundary that was applied, RFC 3339 in UTC, as\nthis plane parsed it from the request. What was disposed of is every record\nWRITTEN strictly before it and not under litigation hold — written, measured\nagainst the server clock at the write, and not against the event or\nobservation times the asserting caller supplies, because a tenant that could\nback-date could delete a compliance record on demand. A boundary younger than\nthe platform floor of five years is refused before anything is removed.","type":"string"},"disposed":{"description":"Disposed is how many whole records were removed. Records are disposed of\nwhole, never redacted: a partially-erased compliance record is one nobody\ncan attest to.","format":"int64","type":"integer"},"held":{"description":"Held is how many records inside the boundary were kept under litigation\nhold.","format":"int64","type":"integer"},"oldest":{"description":"Oldest is the WRITE time of the oldest assertion this tenant still holds after\nthe sweep, RFC 3339, and it is omitted exactly when nothing remains at all.\nStill older than Before means records survived on purpose and says which\nmechanism kept them: a litigation hold (Held), or the per-call bound with more\nto sweep on the next call (Remaining).","type":"string"},"remaining":{"description":"Remaining is how many disposable records are still older than the\nboundary. A sweep is bounded per call, so a non-zero value here means call\nagain rather than that something failed.","format":"int64","type":"integer"},"restored":{"description":"Restored is how many records this sweep had already removed from the derived\ncolumnar copy and then did NOT dispose of, because a litigation hold arrived\nbetween the identify and the delete — and which were therefore written back\nto the derived copy before this answered.\n\nIt is a NAMED state and not a silent repair. The copy is swept before the\nrecord so nothing is orphaned in the warehouse, which means a record the\ndelete declines to remove is one the warehouse has already lost, with its\nseq behind the delivery cursor and no retry that can reach it. Non-zero here\nsays the collision happened and was repaired; a non-zero that keeps\nrecurring says retention and hold are racing on the same records, which is\nworth an operator's attention rather than a debug line.","format":"int64","type":"integer"},"total":{"description":"Total and Oldest describe what the tenant still holds afterwards, so a\ndisposal that removed nothing is distinguishable from a tenant that had\nnothing.","format":"int64","type":"integer"}},"type":"object"},"label.riskHoldIn":{"properties":{"hold":{"description":"Hold is the state to put them in: true places the hold, false releases it.\nOne op both ways, because a hold that can be placed and not released pins a\ncompliance record past every retention boundary with nothing able to let it\ngo — and an operator who cannot release a hold stops placing them.","type":"boolean"},"ids":{"description":"IDs are the content digests of the records, as returned by the write and\nby the read. They name records in THIS tenant's plane; an id belonging to\nanybody else names nothing here, because the statement runs against this\ntenant's own file and there is no other file it could reach.","items":{"type":"string"},"type":"array"}},"type":"object"},"label.riskHoldOut":{"properties":{"changed":{"description":"Changed is how many records moved into that state. A record already in it\nis not counted and is not an error: the op is idempotent, so a retry after\na network failure is safe.","format":"int64","type":"integer"},"held":{"description":"Held is how many records this tenant is now holding, at any age. Retention\nnever disposes of one.","format":"int64","type":"integer"},"hold":{"description":"Hold echoes the state asked for.","type":"boolean"},"missing":{"description":"Missing is how many of the named ids this tenant does not hold. It is\nreported rather than refused, so a sweep over a list that includes disposed\nrecords still places every hold it can — but it is REPORTED, because a hold\nthat silently did nothing is a compliance control that lies.","format":"int64","type":"integer"}},"type":"object"},"label.riskLabelCoverage":{"properties":{"contested":{"description":"Contested is how many matured events have two visible assertions that\ndisagree. It is the number that says whether the precedence rule is\nload-bearing or decorative, and it is the one to watch after wiring a new\nsource.","format":"int64","type":"integer"},"events":{"description":"Events is how many DISTINCT judged events those assertions name, keyed on\n(kind, subject, at). It counts only events something was ASSERTED about: what\nshare of the whole event stream carries a label is a question about the\nfeature plane's denominator and is not answerable here. Matured + Unmatured is\nEvents.","format":"int64","type":"integer"},"explore":{"description":"Explore is the share of judged events whose winning assertion came from\nthe below-the-line sample. A blocked transaction never produces a\nchargeback, so a training set with no exploration in it is a description of\nthe incumbent block list rather than of the world — and a champion measured\non it is measured on whether it agrees with the incumbent.","format":"double","type":"number"},"facts":{"description":"Facts is how many assertions the window holds; Events is how many distinct\njudged events they cover. The two differ by exactly the corroboration and\nthe conflict in the plane.","format":"int64","type":"integer"},"from":{"description":"From is the INCLUSIVE start of the EVENT window these counts were folded over,\nRFC 3339, echoed with the defaults filled in — the caller's, or 90 days before\nTo. An assertion is in the window when its event time satisfies at \u003e= From.","type":"string"},"horizon":{"description":"Horizon is the maturity horizon these counts were measured under, IN DAYS —\nthe caller's, or 120. It decides Matured (an event is matured when its `at`\nplus this many days is not after now), it sets each event's own as-of and so\nwhich assertions were visible to it, and when the caller bounds nothing it\nalso places the default window's end.","format":"int64","type":"integer"},"judged":{"description":"Judged is how many MATURED events resolve, at their own as-of, to\nsomething other than unjudged.","format":"int64","type":"integer"},"matured":{"description":"Matured is how many of those events have aged past the horizon and may\ntherefore be admitted to a supervised set at all. It counts every matured\nevent, judged or not — it is the DENOMINATOR an operator divides Judged by,\nand a denominator that excluded the unjudged would read 1.0 on a plane with\none label in it.","format":"int64","type":"integer"},"pending":{"description":"Pending is how many of this tenant's assertions the DERIVED columnar copy is\nnot known to hold yet. Every count above is folded from the record, so they\nare right regardless — but a materialiser that joins in the warehouse while\nthis is non-zero is joining against an incomplete answer key, and a missing\nfraud label is indistinguishable from an honest customer. It is reported at\nthe training gate because that is where somebody is deciding whether the\nground truth is good enough to fit on. Counted under a cap, so it saturates\nrather than costing a full scan on every read.","format":"int64","type":"integer"},"productive":{"description":"Productive is how many matured events resolve, at their own as-of, to a\nWINNING assertion of `productive` — the event led somewhere: escalated,\nreported, charged back. It is the positive class a supervised fit would train\non, and a near-zero count is the number that says the fit is not worth\nrunning.","format":"int64","type":"integer"},"sources":{"description":"Sources breaks the judged events down by the source that WON, so a plane\nthat looks labelled because one noisy source dominates is visible as such.","items":{"$ref":"#/components/schemas/label.riskSourceCoverage"},"type":"array"},"to":{"description":"To is the EXCLUSIVE end of that window (at \u003c To). Unstated it is one horizon\nbefore now, never now: a window running to now under a maturity horizon can\nhold no matured event at all, so every count below would read zero however\nmuch ground truth the tenant held.","type":"string"},"unlabelled":{"description":"Unlabelled is how many MATURED events had no assertion knowable by their\nown as-of — including every assertion that arrived after that instant. It\nis the field that says WHY judged is low: a tenant whose ground truth was\nfiled long after the events it judges reads matured=n, judged=0,\nunlabelled=n, which is diagnosable, rather than a bare zero, which is not.","format":"int64","type":"integer"},"unmatured":{"description":"Unmatured is how many events in the window have NOT aged past the horizon.\nThey are not unlabelled — they are not yet askable, and a supervised set\nmust exclude them rather than treat them as negatives. Matured + Unmatured\nis Events.","format":"int64","type":"integer"},"unproductive":{"description":"Unproductive is every OTHER judged event: the winner claimed `unproductive`,\njudged not suspicious. Productive + Unproductive is Judged exactly, because a\nwinner of the explicit unjudged is counted in neither — it is a matured event\nsomebody looked at and could not conclude about, and rolling it into the\nnegatives would hand a model a claim nobody made.","format":"int64","type":"integer"}},"type":"object"},"label.riskLabelEvent":{"properties":{"at":{"description":"At is the event's own instant, RFC 3339. It is part of the event's IDENTITY\nand not a filter: it is matched exactly, to the second, against the `at` the\nassertions were filed under, so an instant a second off names a different\nevent and resolves to nothing. It is also what this event's as-of is measured\nfrom — At plus the horizon.","type":"string"},"kind":{"description":"Kind is the judged entity's type, from the closed set: account, agent,\nmerchant, payout, person, session or transaction. One outside it is refused\nrather than answered `unlabelled`, because it could only ever match nothing\nand the caller would read a real absence into a typo.","type":"string"},"subject":{"description":"Subject is the entity id in the tenant's own namespace, at most 512 bytes. It\nis matched EXACTLY against what was recorded — this is a lookup, not a search,\nand no prefix, pattern or normalisation is applied.","type":"string"}},"type":"object"},"label.riskLabelFact":{"properties":{"at":{"description":"At is when the judged event happened, RFC 3339.","type":"string"},"confidence":{"description":"Confidence in [0,1]. A processor chargeback is 1; an analyst's hunch is\nnot. It breaks a tie WITHIN a precedence rank and can never lift a weak\nsource above a strong one — otherwise every caller would send 1.\n\nA litigation hold is NOT a field here. It is a fact about the record and\nnot about the world, so it is not part of what was asserted, it is not in\nthe content digest, and it has its own op — which is also the only way one\ncan be released. Carried here it was silently a no-op on any record that\nalready existed: the digest was the same, the insert was ignored, and the\ncaller was told `duplicate` while the hold it asked for was never placed.","format":"double","type":"number"},"disposition":{"description":"Disposition is productive, unproductive, or empty for an explicit\nunjudged — the AML engine's own vocabulary, verbatim.","type":"string"},"evidence":{"description":"Evidence points at the record this conclusion came from: a dispute id, a\ncase id, a decision id. Required, because a label with no evidence cannot\nbe defended when the adverse action it fed is challenged.","type":"string"},"kind":{"description":"Kind is what the subject is: account, agent, merchant, payout, person,\nsession or transaction. Closed, because a typo in an open field would shard\na tenant's labels into a partition nothing reads and nothing would say so.","type":"string"},"seen":{"description":"Seen is when this assertion became KNOWABLE, RFC 3339. It is required and\nit is not At: a chargeback lands 30 to 120 days after the transaction it\njudges, and a training set joined on At alone knows the future. Everything\nthis plane does to prevent leakage is computed from Seen.","type":"string"},"source":{"description":"Source is who asserted: chargeoff, dispute, case, refund, review or\nsample. It is the primary term of the precedence rule, so it is closed —\nan unknown source has no rank and a conflict with it could not be resolved.","type":"string"},"subject":{"description":"Subject identifies the thing being judged, in the tenant's own namespace.","type":"string"}},"type":"object"},"label.riskLabelIn":{"properties":{"labels":{"description":"Labels is the batch. Each member is judged on its own: one refusal does\nnot discard the rest, because a webhook redelivering five disputes must\nnot lose four of them to one malformed fifth.","items":{"$ref":"#/components/schemas/label.riskLabelFact"},"type":"array"}},"type":"object"},"label.riskLabelOut":{"properties":{"duplicate":{"description":"Duplicate is how many members this tenant already held, byte for byte. The\nidempotency key is the assertion's CONTENT digest — kind, subject, at, seen,\ndisposition, source, evidence, the asserting identity and confidence, folded\nin length-prefixed — so a webhook redelivering one chargeback is a duplicate\nand costs nothing, while an assertion differing in ANY of those fields is a\nDIFFERENT assertion and is recorded beside the first. Nothing was written and\nnothing was overwritten; it is an outcome, never an error. The asserting\nidentity is in the digest, so the same claim filed by a second credential is\ntwo assertions and not a redelivery.","format":"int64","type":"integer"},"mirror":{"description":"Mirror names why the columnar copy did not take this batch, when it did\nnot. The record is already durable in the tenant's own store by then — the\nwarehouse copy exists to make a training join cheap, and its absence is a\ngap in that join, never a lost label.","type":"string"},"pending":{"description":"Pending is how many assertions the derived copy is still to take. Every\nwrite attempt carries the backlog forward as well as its own batch, so a\nwarehouse that was unreachable closes its gap on the next write rather than\nleaving a hole in a training join nothing would report. It is counted under\na cap and saturates there: zero means caught up, and a large number means a\nbacklog to work through rather than an inventory to reconcile.","format":"int64","type":"integer"},"recorded":{"description":"Recorded is how many members became a NEW row in the tenant's record.\nRecorded + Duplicate + Refused is exactly the number of labels sent, so a\ncaller reconciling a webhook delivery can do it on the counts alone.","format":"int64","type":"integer"},"refused":{"description":"Refused is how many members failed admission and were NOT recorded. Refusal\nis per member and never discards the rest of the batch: an empty or\nover-512-byte subject or evidence, a kind, disposition or source outside the\nclosed vocabulary, an `at` or `seen` that is not RFC 3339, a `seen` before the\n`at` it judges, either instant more than five minutes past the server clock,\nor a confidence outside [0,1]. Results names which member and why, so the\nrefused ones are exactly the ones to fix and resend.","format":"int64","type":"integer"},"results":{"description":"Results is per fact, in the order sent, so a caller can retry exactly the\nmembers that were refused and can log the content digest of the ones that\nlanded.","items":{"$ref":"#/components/schemas/label.riskLabelResult"},"type":"array"}},"type":"object"},"label.riskLabelRecord":{"properties":{"at":{"description":"At is when the judged EVENT happened, RFC 3339 in UTC, truncated to the\nsecond. The filer supplies it, and it is what a maturity horizon measures\nfrom: this event's as-of is At plus the horizon. A resolve names it back\nexactly, to the second.","type":"string"},"by":{"description":"By is the identity that asserted, stamped server-side at the write.","type":"string"},"confidence":{"description":"Confidence is the filer's own confidence in [0,1] — 1 for a processor\nchargeback, less for an analyst's hunch. Zero is the ordinary value for a\nfiler that stated none, and it means the weakest tie-break there is rather\nthan \"unknown\". It breaks a tie only WITHIN one precedence rank and can never\nlift a weak source above a strong one.","format":"double","type":"number"},"disposition":{"description":"Disposition is what was concluded, from the closed set: `productive` — the\nevent led somewhere, escalated, reported or charged back; `unproductive` —\njudged not suspicious; or the empty string for an explicit UNJUDGED, which is\na real assertion (\"we looked and could not say\") and not the absence of one.","type":"string"},"evidence":{"description":"Evidence is the pointer to the record this conclusion came from: a dispute id,\na case id, a decision id. At most 512 bytes, required at the write, and opaque\nto this plane — stored and returned verbatim, never resolved. It is what an\nadverse action is defended with, which is why an assertion carrying none is\nrefused at the endpoint.","type":"string"},"hold":{"description":"Hold is true while a litigation hold is on this record: retention will not\ndispose of it, at any age. False — and it is omitted then — leaves the record\ndisposable once it is older than the boundary a sweep names. It is a fact\nabout the RECORD and not about the world, so it is not folded into ID, no\nwrite path can set it, and the hold op is the one way it moves in either\ndirection.","type":"boolean"},"id":{"description":"ID is the assertion's content digest — SHA-256 over every semantic field,\nrendered hex — computed server-side and never supplied. It is the key a\nredelivery collapses onto, and it is the id the hold op names.","type":"string"},"kind":{"description":"Kind is what the subject IS, from the closed set: account, agent, merchant,\npayout, person, session or transaction. With Subject and At it is the IDENTITY\nof the judged event — the triple a resolve names and the triple assertions are\ngrouped by, so a typo in it would file a label against an event nobody asks\nabout.","type":"string"},"knowable":{"description":"Knowable is when THIS PLANE could first have answered with the assertion:\nthe later of Seen and the server clock at the write, derived server-side.\nIt is the instant the leakage guard compares, so it is published beside the\nclaim it was derived from — an answer whose rule nobody can see is one\nnobody can check.","type":"string"},"seen":{"description":"Seen is when the FILER said the assertion became knowable. It is\nprovenance: it is recorded and published, and it decides nothing.","type":"string"},"source":{"description":"Source is WHO asserted, from the closed set: chargeoff, dispute, case, refund,\nreview or sample. It is the primary term of the precedence rule — an unknown\nsource has no rank and a conflict with it could not be resolved — so it is\nwhat decides which of two disagreeing assertions is in force.","type":"string"},"subject":{"description":"Subject is the entity that was judged, named in the TENANT'S OWN namespace and\nat most 512 bytes. It is opaque here: stored, matched and returned verbatim,\nnever dereferenced. It has no meaning outside this tenant — the record is the\ntenant's own file — so an id lifted from another tenant's response names\nnothing.","type":"string"},"wrote":{"description":"Wrote is the server clock at the write. It is the only time on the record\nthe tenant did not supply, and it is what retention measures against.","type":"string"}},"type":"object"},"label.riskLabelResult":{"properties":{"id":{"description":"ID is the content digest of the assertion — the id a redelivery of the\nsame fact resolves to.","type":"string"},"refusal":{"description":"Refusal states what was wrong, for the refused.","type":"string"},"status":{"description":"Status is recorded, duplicate or refused.","type":"string"}},"type":"object"},"label.riskLabelVocabulary":{"properties":{"dispositions":{"description":"Dispositions is the closed set a write's `disposition` must be drawn from,\npublished in full so a caller can validate a batch before filing it instead of\ndiscovering a refusal per member: \"productive\", \"unproductive\", and \"\" — the\nEMPTY STRING is a member and means an explicit unjudged, so a client that\nfilters empties out of this list drops a third of the vocabulary and can never\nfile \"we looked and could not say\". They are the AML engine's own spelling,\nverbatim, which is what lets a replay there report against these values.","items":{"type":"string"},"type":"array"},"kinds":{"description":"Kinds, Dispositions and Sources are the closed vocabularies. A value\noutside them is refused at the endpoint.","items":{"type":"string"},"type":"array"},"precedence":{"description":"Precedence is the sources in the order that resolves a conflict, strongest\nfirst. It is DERIVED from the same declaration the resolver reads, so the\npublished order is the enforced order and cannot drift from it.","items":{"type":"string"},"type":"array"},"retention":{"description":"Retention is the platform floor in days: no tenant may dispose of a label\nyounger than this, because a label can be the input to an adverse action.","format":"int64","type":"integer"},"rule":{"description":"Rule states the tie-breaks below rank, in order, so a caller reading a\ncontested resolution can reproduce it.","items":{"type":"string"},"type":"array"}},"type":"object"},"label.riskLabelsOut":{"properties":{"count":{"description":"Count is how many this page holds. It is not a total: a total over an\nunbounded append-only log is a full scan of a single-writer file.","format":"int64","type":"integer"},"labels":{"description":"Labels is the page, newest event first.","items":{"$ref":"#/components/schemas/label.riskLabelRecord"},"type":"array"}},"type":"object"},"label.riskResolveIn":{"properties":{"horizon":{"description":"Horizon is how many days an event must age before it may be resolved at\nall, and it is the whole of the no-leakage rule. 120 for the payment lane\n(past the Visa and Mastercard dispute windows), 14 for signup abuse.\nUnstated takes 120.","format":"int64","type":"integer"},"now":{"description":"Now moves the observation instant BACKWARDS, RFC 3339. It exists so a\nBACKTEST can resolve labels as the plane stood at a past moment; without it,\nevery backtest would score a model against knowledge that arrived after the\ndecision it is being scored on. An instant after the server clock is\nrefused: a backtest resolves the past, and a future one would declare\nunmatured events matured and hand a training set negatives for rows whose\nchargeback has not had time to arrive.","type":"string"},"subjects":{"description":"Subjects are the exact events being judged. Each carries its own event\ntime, because the as-of that keeps the future out is derived from that\ninstant plus the horizon — one as-of over a whole batch would give a\nJanuary row six extra months of hindsight.\n\nOne entry per DISTINCT (kind, subject, at): naming an event twice answers\nonce, because an event resolved twice would list its own winner as a\ncontrary claim and would hand a materialiser duplicate training rows.","items":{"$ref":"#/components/schemas/label.riskLabelEvent"},"type":"array"}},"type":"object"},"label.riskResolveOut":{"properties":{"horizon":{"description":"Horizon is the maturity horizon this answer was computed under, IN DAYS — the\ncaller's, or 120 when it stated none. Each event's as-of is its own `at` plus\nthis many days, and that as-of is what decides which assertions were visible\nto it; an event whose as-of falls after Now is not resolved at all and is\ncounted in Unmatured instead.","format":"int64","type":"integer"},"labels":{"description":"Labels is one entry per named event that BOTH matured and had at least one\nassertion knowable by its own as-of, in the order the events were named. The\nthree outcomes partition the ask: len(labels) + Unmatured + Unlabelled is the\nnumber of DISTINCT events named, an event named twice having been answered\nonce.","items":{"$ref":"#/components/schemas/label.riskResolved"},"type":"array"},"now":{"description":"Now and Horizon echo the observation this answer was computed under. A\nresolved label without them is a claim nobody can check.","type":"string"},"unlabelled":{"description":"Unlabelled is how many matured events had no assertion knowable by their\nown as-of. That is the ordinary state of most traffic and it is reported\nrather than answered as unproductive: manufacturing negatives is how a\nfraud model comes to describe the incumbent block list.","format":"int64","type":"integer"},"unmatured":{"description":"Unmatured is how many named events had not aged past the horizon. They are\nnot unlabelled — they are not yet ASKABLE, and a supervised training set\nmust exclude them rather than treat them as negatives.","format":"int64","type":"integer"}},"type":"object"},"label.riskResolved":{"properties":{"asOf":{"description":"AsOf is the instant this answer was true at: the event time plus the\nhorizon. Nothing seen after it was visible to this resolution.","type":"string"},"at":{"description":"At is the event's instant, RFC 3339, echoed. It is what the horizon is\nmeasured from, so At plus the horizon is AsOf.","type":"string"},"by":{"description":"By is the identity that filed the WINNING assertion, `\u003chome org\u003e/\u003cuser\u003e`,\nstamped server-side from the validated principal at the write and never taken\nfrom a body — an attribution the caller chose is not attribution. It is the\nwinner's alone; every losing assertion keeps its own and is returned whole in\nConflicts.","type":"string"},"confidence":{"description":"Confidence is the winning assertion's own confidence in [0,1], zero when its\nfiler stated none. It is reported because it is a term of the rule that picked\nthe winner, and it is the weakest term but one: it breaks a tie inside one\nrank and never lifts a weak source above a strong one.","format":"double","type":"number"},"conflicts":{"description":"Conflicts is every other visible assertion, strongest first, whole. They\nare kept and returned rather than dropped, so an adverse action can show\nthat the plane knew of a contrary claim and say why it lost. They are\nhorizon-filtered exactly like the winner: an assertion that was not\nknowable yet cannot even be named here, because naming it would leak its\nexistence into a past decision.","items":{"$ref":"#/components/schemas/label.riskLabelRecord"},"type":"array"},"contested":{"description":"Contested is true when a visible assertion claimed a DIFFERENT disposition.\nTwo sources agreeing is corroboration, not conflict.","type":"boolean"},"disposition":{"description":"Disposition is the claim IN FORCE at AsOf: productive, unproductive, or the\nempty string for an explicit unjudged. It is the winning assertion's own\nclaim, never a vote or an average — an average of two adjudications is a third\nclaim nobody made. A matured event nobody judged is not answered here at all;\nit is counted in Unlabelled, because manufacturing a negative there is how a\nfraud model comes to describe the incumbent block list.","type":"string"},"evidence":{"description":"Evidence is the winning assertion's pointer to the record behind it — the\ndispute, case or decision id it was filed with, opaque and verbatim. It\ntravels with the answer so an adverse action can name what judged the subject\nwithout a second read.","type":"string"},"id":{"description":"ID is the winning assertion's content digest, so this answer traces to the\nexact record it came from — and that record can be placed under litigation\nhold by naming this id.","type":"string"},"kind":{"description":"Kind is the judged entity's type, echoed from the event that was named. With\nSubject and At it is how a caller joins this answer back onto the training row\nor the decision it asked about.","type":"string"},"source":{"description":"Source is who filed the winning assertion, and it is the PRIMARY term of the\nrule that picked it. Sources rank by adjudication weight — chargeoff,\ndispute, case, refund, review, sample, strongest first — and only inside one\nrank do the tie-breaks run, in order: the assertion that became KNOWABLE\nlatest, then the higher confidence, then the lower id. The vocabulary op\npublishes that order from the same declaration the resolver reads, so a caller\nholding a contested answer can reproduce it.","type":"string"},"subject":{"description":"Subject is the entity id, echoed from the event that was named — the tenant's\nown key, returned verbatim.","type":"string"}},"type":"object"},"label.riskSourceCoverage":{"properties":{"facts":{"description":"Facts is how many assertions this source filed; Won is how many judged\nevents it was the assertion in force for. A source with many facts and few\nwins is one that is being outranked, which is worth knowing before\nconcluding it is wired correctly.","format":"int64","type":"integer"},"source":{"description":"Source is the asserter these two counts are for — chargeoff, dispute, case,\nrefund, review or sample. There is one entry per source that either filed in\nthe window or won in it, in precedence order, strongest first. A source no\nlonger in the vocabulary still has rows and is reported after the known ones\nrather than dropped out of a total that is supposed to add up.","type":"string"},"won":{"description":"Won is how many JUDGED events this source's assertion was the one IN FORCE\nfor, at that event's own as-of — it beat every other visible claim under the\nprecedence rule. Summed over the sources it is Judged. Read against Facts it\nis the ratio that matters: many filed and few won is a source being outranked,\nnot a source that is broken, and one source winning nearly everything is a\nplane that looks labelled because one noisy filer dominates it.","format":"int64","type":"integer"}},"type":"object"},"leaderboard.ActivityPoint":{"properties":{"costCents":{"description":"CostCents is the day's spend in whole US cents. A series is only ever returned\nfor a subject the caller is authorized to see, so this is never withheld: 0 means\nno spend that day.","format":"int64","type":"integer"},"day":{"description":"Day is the UTC calendar day this point covers, \"2006-01-02\".","type":"string"},"requests":{"description":"Requests is the subject's request count on this day. 0 is a real, quiet day: the\nseries is gap-filled, so every day in the range is present whether or not\nanything happened.","format":"int64","type":"integer"},"tokens":{"description":"Tokens is prompt+completion tokens on this day — normally the heatmap's\nintensity, scaled against ActivityTotals.MaxTokens.","format":"int64","type":"integer"}},"type":"object"},"leaderboard.ActivityTotals":{"properties":{"activeDays":{"description":"ActiveDays counts the days with any usage at all — the streak/consistency number.\nCompare it against len(days) for the share of days the subject showed up.","format":"int64","type":"integer"},"costCents":{"description":"CostCents is the window's spend in whole US cents, the sum of Days[].CostCents.","format":"int64","type":"integer"},"maxRequests":{"description":"MaxRequests is the same ceiling for a request-based heatmap — the busiest single\nday's request count, 0 for an idle window.","format":"int64","type":"integer"},"maxTokens":{"description":"MaxTokens is the busiest single day's token count: the ceiling to normalize a\ntoken heatmap against, so the darkest cell is that day. 0 for an idle window,\nwhich a client must not divide by.","format":"int64","type":"integer"},"requests":{"description":"Requests is the sum of Days[].Requests over the whole window.","format":"int64","type":"integer"},"tokens":{"description":"Tokens is the sum of Days[].Tokens over the whole window.","format":"int64","type":"integer"}},"type":"object"},"leaderboard.ActivityView":{"properties":{"available":{"description":"Available is false when nothing could be read: the warehouse is not connected,\nthe rollup is not ready, or the subject is one the ledger cannot attribute (see\nNote). Days is then empty because there is no answer, not because there was no\nactivity.","type":"boolean"},"days":{"description":"Days is the gap-filled series, one point per calendar day from From up to (not\nincluding) To, in ascending order, zero-valued days included. Always a list,\nnever null.","items":{"$ref":"#/components/schemas/leaderboard.ActivityPoint"},"type":"array"},"from":{"description":"From is the first day in Days, \"2006-01-02\" inclusive.","type":"string"},"id":{"description":"ID is the subject the server actually read, after resolving \"me\"/empty to the\ncaller and bounding it to what they may see — a ledger \"owner/name\" for a user,\nan org id for an org. Echoed so a client can confirm whose series it holds.","type":"string"},"note":{"description":"Note explains an empty-but-not-broken answer in plain words — today only\nsubject=project, which the usage ledger records no column for. Present only when\nthere is something to say; show it instead of an empty chart.","type":"string"},"source":{"description":"Source names the table the series was aggregated from (the derived daily rollup,\nhanzo.usage_rollup_daily).","type":"string"},"subject":{"description":"Subject echoes what the series is about: user|org|project.","type":"string"},"to":{"description":"To is the EXCLUSIVE upper bound, \"2006-01-02\" — the day AFTER the last point in\nDays. A request for to=2026-03-31 answers to=2026-04-01 with 2026-03-31 last.","type":"string"},"totals":{"$ref":"#/components/schemas/leaderboard.ActivityTotals","description":"Totals are the window's sums plus the busiest-day ceilings a heatmap scales\nagainst. Derived from Days — nothing here is read separately."}},"type":"object"},"leaderboard.BetaBoard":{"properties":{"of":{"description":"Of is how many people are on the waitlist: every account that applied, and\nevery lead that applied before it had an account.","format":"int64","type":"integer"},"referrals":{"description":"Referrals is whether referrals were counted; false when the referral service\ndid not answer, and no record's score has them then.","type":"boolean"},"rows":{"description":"Rows are the top of the waitlist, best first.","items":{"$ref":"#/components/schemas/leaderboard.BetaRow"},"type":"array"},"tokens":{"description":"Tokens is whether token usage was counted; false when the warehouse did not\nanswer, and no record's score has it then.","type":"boolean"},"you":{"$ref":"#/components/schemas/leaderboard.BetaRow","description":"You is the caller's own row wherever it ranks; null when the caller holds\nno record."}},"type":"object"},"leaderboard.BetaRow":{"properties":{"applied":{"description":"Applied is the day the application began, 2006-01-02: the record's own, or the\nday of the lead it claims when that was earlier.","type":"string"},"name":{"description":"Name is the handle its owner listed under on the public board; null for a\nperson who did not opt in, whom the page calls a builder. The caller's own\nrow is always named.","type":"string"},"qualified":{"description":"Qualified is how many of them have made metered spend.","format":"int64","type":"integer"},"rank":{"description":"Rank is the record's place, 1 first.","format":"int64","type":"integer"},"referrals":{"description":"Referrals is how many orgs signed up with the record's referral code.","format":"int64","type":"integer"},"score":{"description":"Score is what the row is ranked by: points, referrals, qualified referrals\nand tokens, as GET /v1/leaderboard/beta's description states.","format":"int64","type":"integer"},"tokens":{"description":"Tokens is the person's all-time token usage as a range: 0, \u003c1M, 1M-10M,\n10M-100M, 100M-1B or 1B+.","type":"string"},"tokensUsed":{"description":"TokensUsed is the exact count, on a named row and the caller's; absent on\nevery other.","format":"int64","type":"integer"},"you":{"description":"You marks the caller's own row.","type":"boolean"}},"type":"object"},"leaderboard.LeaderboardRow":{"properties":{"anonymous":{"description":"Anonymous is true when this subject's identity was withheld and Handle is the\n\"Anonymous\" placeholder: the metric is real, the name is not. Render it as an\nunnamed row, never as someone actually called Anonymous.","type":"boolean"},"costCents":{"description":"CostCents is this subject's spend in whole US cents (not dollars, not\nmillicents). It is 0 unless the viewer is entitled to this subject's spend —\ntheir own row, an admin looking at their own org, an explicitly cost-ranked\nboard, or a platform admin on the global board — so 0 means \"withheld or zero\",\nand the two are deliberately indistinguishable.","format":"int64","type":"integer"},"handle":{"description":"Handle is the display identity to render: the peer's chosen handle if they opted\ninto public listing, their username if the viewer is an admin of their org, the\norg's chosen display name (or its id) on an org board, and the literal\n\"Anonymous\" when the identity is withheld. Never an email or a raw ledger id.","type":"string"},"metric":{"description":"Metric is the value the board was ranked by, copied from Requests, Tokens or\nCostCents according to the request's metric. It is what a client sizes bars\nagainst without having to know which metric was asked for.","format":"int64","type":"integer"},"rank":{"description":"Rank is this subject's 1-based standing in the window, 1 being the top. Rows are\nordered by the ranked metric descending (ties broken by request count), and a\nboard is always the top of the list — there is no offset paging — so the first\nrow is always rank 1 and rank is also the row's index + 1.","format":"int64","type":"integer"},"requests":{"description":"Requests is how many AI requests this subject made in the window. Volume is not\nsensitive, so it is reported for every row including anonymized ones.","format":"int64","type":"integer"},"self":{"description":"Self marks the caller's own row so a client can highlight it in place. At most\none row carries it, and it is never set on an org board — org rows carry no user\nidentity, so the caller's own org standing arrives in LeaderboardView.Self.","type":"boolean"},"tokens":{"description":"Tokens is prompt+completion tokens this subject spent in the window. Like\nRequests it is reported for every row.","format":"int64","type":"integer"}},"type":"object"},"leaderboard.LeaderboardView":{"properties":{"available":{"description":"Available is false when the usage warehouse is not connected or its rollup is not\nready. Rows is then empty because nothing could be read — not because nobody used\nanything. Show that difference; never render an unavailable board as a real one.","type":"boolean"},"end":{"description":"End is the EXCLUSIVE upper bound of the window, \"2006-01-02\" — the day after the\nlast one counted. A board through today reports tomorrow's date here.","type":"string"},"metric":{"description":"Metric echoes the value ranked: tokens|requests|cost.","type":"string"},"period":{"description":"Period is the window's canonical label: day|week|month|all. The server resolves\naliases (7d, 30d, today, …) to these, so this may differ from what was sent.","type":"string"},"rows":{"description":"Rows are the ranked subjects, best first, at most the requested limit of them.\nAlways a list, never null: an empty one means nothing was read, not an error.","items":{"$ref":"#/components/schemas/leaderboard.LeaderboardRow"},"type":"array"},"scope":{"description":"Scope echoes the board that was served: personal|org|global.","type":"string"},"self":{"$ref":"#/components/schemas/leaderboard.SelfRank","description":"Self is the caller's own standing, reported even when they fall outside Rows.\nAbsent when the caller's ledger identity cannot be resolved, or when the query\nbehind it failed — never faked to keep the shape tidy."},"source":{"description":"Source names the table these numbers were aggregated from (the derived daily\nrollup, hanzo.usage_rollup_daily), so an operator can tell exactly what was read.","type":"string"},"start":{"description":"Start is the first day counted, \"2006-01-02\" inclusive. Empty for period=all,\nwhich has no lower bound at all.","type":"string"},"subject":{"description":"Subject is what the rows stand for — \"user\" on a personal or org board, \"org\" on\nthe global one. It tells a client whether Handle names a person or a company.","type":"string"},"total":{"description":"Total is how many subjects were ranked in the window — the org's active users, or\nthe active/opted-in orgs on the global board. It is the universe the ranks are\nout of, so it is normally larger than len(rows).","format":"int64","type":"integer"}},"type":"object"},"leaderboard.SelfRank":{"properties":{"costCents":{"description":"CostCents is the caller's own spend in whole US cents. Always populated — your\nown spend is never withheld from you — so here 0 really does mean zero.","format":"int64","type":"integer"},"handle":{"description":"Handle is how the caller appears on this board: their chosen handle, falling back\nto their username, on a user board; their org id on the global board. Present\neven when unlisted — this is the caller looking at themselves.","type":"string"},"listed":{"description":"Listed says whether the caller is publicly visible on this board: opted in on a\nuser board, org opted in (or the viewer is a platform admin) on the global one.\nFalse is the prompt to offer the opt-in, and explains an unranked global self.","type":"boolean"},"metric":{"description":"Metric is whichever of the three values above the board was ranked by, so a\nclient can compare the caller against the rows without re-reading the request.\nMetric \u003c= 0 is exactly the case that leaves Ranked false.","format":"int64","type":"integer"},"ofTotal":{"description":"OfTotal is the size of the universe Rank is out of — \"rank N of OfTotal\". On a\nuser board that is the org's users with any usage in the window; on the global\nboard it is every active org for a platform admin, and the count of opted-in\norgs for everyone else.","format":"int64","type":"integer"},"rank":{"description":"Rank is the caller's 1-based standing, computed as (subjects whose windowed\nmetric strictly exceeds the caller's) + 1. It is exact against the whole ranked\nuniverse, not just the returned page, so it can far exceed len(rows). Read it\nonly when Ranked.","format":"int64","type":"integer"},"ranked":{"description":"Ranked is false when the caller holds no position: they had no usage in the\nwindow, or (on the global board) their org has not opted into public listing and\nso is not ranked against a set it never joined. Rank is then 0 and means nothing.","type":"boolean"},"requests":{"description":"Requests is the caller's own request count in the window, 0 if they were idle.","format":"int64","type":"integer"},"tokens":{"description":"Tokens is the caller's own prompt+completion tokens in the window.","format":"int64","type":"integer"}},"type":"object"},"leaderboard.optinView":{"properties":{"org":{"$ref":"#/components/schemas/leaderboard.orgOptinView","description":"Org is the caller's org's listing preference on the cross-org board, and whether\nthis caller is allowed to change it. It is read for every caller — a member sees\nwhere their org stands even though only an admin may edit it."},"user":{"$ref":"#/components/schemas/leaderboard.userOptinView","description":"User is the caller's OWN listing preference, and whether they may change it."}},"type":"object"},"leaderboard.orgOptinReq":{"properties":{"display":{"description":"Display is the name shown for the org on that board: 1-40 characters of\nletters, digits, space, dot, underscore, apostrophe or hyphen. Left empty on a\nlisting opt-in it defaults to the org id.","type":"string"},"listed":{"description":"Listed publishes the org on the cross-org global board when true, and withdraws\nit when false.","type":"boolean"}},"type":"object"},"leaderboard.orgOptinView":{"properties":{"canManage":{"description":"CanManage is true only for an admin of this org (or a platform SuperAdmin) — the\ncallers whose write of the org preference will be accepted.","type":"boolean"},"display":{"description":"Display is the name shown for the org on that board. Empty when none was chosen;\nopting in without one defaults it to the org id.","type":"string"},"listed":{"description":"Listed is true when the org has opted onto the cross-org global board. False —\nthe default — keeps the org off it entirely; the org's own members still see\ntheir own board. Listing consents to publishing usage VOLUME, never spend.","type":"boolean"}},"type":"object"},"leaderboard.userOptinReq":{"properties":{"handle":{"description":"Handle is the display name shown on a listed row: 1-40 characters of letters,\ndigits, space, dot, underscore, apostrophe or hyphen. Left empty on a listing\nopt-in it defaults to the caller's username.","type":"string"},"listed":{"description":"Listed publishes the caller's row to other viewers of the board when true, and\nanonymizes it when false.","type":"boolean"}},"type":"object"},"leaderboard.userOptinView":{"properties":{"canSet":{"description":"CanSet is false when the caller's ledger identity cannot be resolved (no user\nname on the principal). Writing the preference would fail, so hide the control.","type":"boolean"},"handle":{"description":"Handle is the display name on the caller's listed row. Empty when they never\nchose one; opting in without a handle sets it to their username, so a listed row\nis never blank.","type":"string"},"listed":{"description":"Listed is true when the caller's board row is published under Handle to other\nviewers. False — the default for anyone who never opted in — anonymizes the row;\nthe metric still counts, only the name is withheld.","type":"boolean"}},"type":"object"},"legal.Field":{"properties":{"key":{"description":"Key is the identifier the body substitutes ({{.key}}) and the key a\ngeneration's data map must carry. snake_case by convention across the\nbuilt-ins — effective_date, company_name, governing_law. An override whose\nbody references a key no Field declares is refused on save.","type":"string"},"label":{"description":"Label is the human prompt for whoever fills the value in — \"Governing law\n(state)\". It never reaches the rendered document; only Key does.","type":"string"}},"type":"object"},"legal.documentPage":{"properties":{"data":{"description":"Data are the documents, WITHOUT their rendered content — fetch one to read it.","items":{"$ref":"#/components/schemas/legal.documentSummary"},"type":"array"},"disclaimer":{"description":"Disclaimer is the boundary made visible on the wire.","type":"string"}},"type":"object"},"legal.documentReply":{"properties":{"disclaimer":{"description":"Disclaimer is the boundary made visible on the wire.","type":"string"},"document":{"$ref":"#/components/schemas/legal.documentView","description":"Document is the document, rendered content included."}},"type":"object"},"legal.documentSummary":{"properties":{"category":{"description":"Category is the template's category: formation, equity, ops or sales.","type":"string"},"createdAt":{"description":"CreatedAt is when the document was generated, in unix seconds.","format":"int64","type":"integer"},"esignProvider":{"description":"EsignProvider names the e-signature provider handling it, absent until a\nsignature has been requested.","type":"string"},"id":{"description":"ID is the document's server-minted handle, \"doc_\"-prefixed.","type":"string"},"signedAt":{"description":"SignedAt is when the provider reported completion, in unix seconds. Absent\nuntil then.","format":"int64","type":"integer"},"status":{"description":"Status is the lifecycle state: draft, out_for_signature, signed or voided.\nThere is deliberately no \"legally valid\" state — that is counsel's\ndetermination, not the platform's.","type":"string"},"templateId":{"description":"TemplateID is the template it was rendered from.","type":"string"},"templateVersion":{"description":"TemplateVersion is WHICH version of that template rendered it, so the\ndocument is reproducible and auditable.","format":"int64","type":"integer"},"title":{"description":"Title is the document's title, inherited from the template.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it last changed, in unix seconds.","format":"int64","type":"integer"}},"type":"object"},"legal.documentView":{"properties":{"body":{"description":"Body is the rendered document. It is sealed at rest and returned only to the\nowning org. When the template is counsel-review it opens with the counsel\nnotice, which the engine prepends and no caller can suppress.","type":"string"},"category":{"description":"Category is the template's category: formation, equity, ops or sales.","type":"string"},"contentType":{"description":"ContentType is the rendered body's media type — text/markdown.","type":"string"},"createdAt":{"description":"CreatedAt is when the document was generated, in unix seconds.","format":"int64","type":"integer"},"esignProvider":{"description":"EsignProvider names the e-signature provider handling it, absent until a\nsignature has been requested.","type":"string"},"id":{"description":"ID is the document's server-minted handle, \"doc_\"-prefixed.","type":"string"},"signedAt":{"description":"SignedAt is when the provider reported completion, in unix seconds. Absent\nuntil then.","format":"int64","type":"integer"},"status":{"description":"Status is the lifecycle state: draft, out_for_signature, signed or voided.\nThere is deliberately no \"legally valid\" state — that is counsel's\ndetermination, not the platform's.","type":"string"},"templateId":{"description":"TemplateID is the template it was rendered from.","type":"string"},"templateVersion":{"description":"TemplateVersion is WHICH version of that template rendered it, so the\ndocument is reproducible and auditable.","format":"int64","type":"integer"},"title":{"description":"Title is the document's title, inherited from the template.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it last changed, in unix seconds.","format":"int64","type":"integer"}},"type":"object"},"legal.filingPage":{"properties":{"data":{"description":"Data are the filing records.","items":{"$ref":"#/components/schemas/legal.legalFiling"},"type":"array"},"disclaimer":{"description":"Disclaimer is the boundary made visible on the wire.","type":"string"}},"type":"object"},"legal.filingReply":{"properties":{"disclaimer":{"description":"Disclaimer is the boundary made visible on the wire.","type":"string"},"filing":{"$ref":"#/components/schemas/legal.legalFiling","description":"Filing is the tracking record."}},"type":"object"},"legal.filingRequest":{"properties":{"documentIds":{"description":"DocumentIDs are the documents to file. At least one is required, and every\none must belong to the caller's org — a filing can never reach across orgs.","items":{"type":"string"},"type":"array"},"jurisdiction":{"description":"Jurisdiction is the state or agency the filing is for, e.g. \"DE\".","type":"string"}},"type":"object"},"legal.generateRequest":{"properties":{"data":{"additionalProperties":{"type":"string"},"description":"Data supplies every merge field the template declares, keyed by field key.\nEvery declared field is REQUIRED: a missing one is refused with 400 rather\nthan rendered as a blank into a contract.","type":"object"},"templateId":{"description":"TemplateID is the template to render. Required; resolved for the caller's\norg, so an override wins over the built-in.","type":"string"}},"type":"object"},"legal.legalFiling":{"properties":{"createdAt":{"description":"CreatedAt is when the filing was recorded, in unix seconds.","format":"int64","type":"integer"},"documentIds":{"description":"DocumentIDs are the generated documents this filing covers. At least one, and\neach must already belong to Org — a filing can never reach across tenants.","items":{"type":"string"},"type":"array"},"id":{"description":"ID is the filing's server-minted handle, \"filing_\"-prefixed. It is OURS, not\nthe state's — a state file number arrives only from a real filing partner.","type":"string"},"jurisdiction":{"description":"Jurisdiction is the state or agency the filing is for, as the caller wrote it\n(\"DE\"). Free text, not validated against a list. Absent when the caller sent\nnone.","type":"string"},"note":{"description":"Note is the provider's explanation of Status, in prose meant for a person. On\nthe manual default it says the documents were generated for signature and the\norg files them through its registered agent. Absent when the provider offered\nnothing.","type":"string"},"org":{"description":"Org owns the filing. Every query is scoped to it, so another tenant's filing\nis indistinguishable from a missing one.","type":"string"},"provider":{"description":"Provider is the filing partner that took the submission, or \"manual\" when no\npartner is wired on this deployment.","type":"string"},"status":{"description":"Status is where the filing stands: manual (no partner wired — file through\nyour registered agent), submitted (a partner accepted it), filed (the state\naccepted it) or rejected.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it last changed, in unix seconds. Equal to CreatedAt until a\nprovider reports movement.","format":"int64","type":"integer"}},"type":"object"},"legal.legalHealth":{"properties":{"status":{"description":"Status is \"ok\" when the subsystem is serving.","type":"string"},"templates":{"description":"Templates is how many built-in templates the catalog carries.","format":"int64","type":"integer"}},"type":"object"},"legal.legalSigner":{"properties":{"email":{"description":"Email is where the provider sends the request, and the only way the signer is\nreached — a signer is a COUNTERPARTY, not necessarily a member of the org, so\nthere is no account to fall back on.","type":"string"},"name":{"description":"Name is the person as they should appear on the signature request. Passed to\nthe provider verbatim; nothing here matches it against a Hanzo user.","type":"string"}},"type":"object"},"legal.legalTemplate":{"properties":{"body":{"description":"Body is the text/template source, markdown, referencing each declared field as\n{{.key}}. Rendering is pure — no clock, no I/O — so a template version and a\ndata map always produce identical bytes. Only the single-template read carries\nit; the catalog listing does not.","type":"string"},"category":{"description":"Category is the corporate need the template serves: formation, equity, ops or\nsales. Formation and equity are the securities-class categories, which is what\nforces CounselReview.","type":"string"},"counselReview":{"description":"CounselReview marks a template whose rendered documents open with\nCounselNotice. It can be raised but never lowered, and the engine also raises\nit for any formation or equity template whatever the flag says — so no org can\nrender a securities-class document without the notice.","type":"boolean"},"fields":{"description":"Fields declares the merge fields Body consumes, each with its human label.\nEvery one is REQUIRED at generation: a missing or blank value is refused\nrather than rendered as a silent blank into a contract.","items":{"$ref":"#/components/schemas/legal.Field"},"type":"array"},"id":{"description":"ID is the template's stable id and the path segment that addresses it —\n\"nda\", \"msa\", \"safe\". An override keeps the built-in's id, so the id names\nthe DOCUMENT KIND rather than a particular version of it.","type":"string"},"origin":{"description":"Origin is \"builtin\" for a template the platform ships or \"org\" for one this\norg saved. It separates the catalog every tenant sees from this tenant's own.","type":"string"},"title":{"description":"Title is the display name, e.g. \"Mutual Non-Disclosure Agreement\". A generated\ndocument inherits it.","type":"string"},"version":{"description":"Version is which version of this template the caller resolved to, and what a\ngenerated document records so it stays reproducible. A built-in is version 1;\nan org's first override is 2 and each save increments, so an override version\nnever collides with the built-in's.","format":"int64","type":"integer"}},"type":"object"},"legal.signReply":{"properties":{"document":{"$ref":"#/components/schemas/legal.documentSummary","description":"Document is the document, now out for signature. Its rendered body is not\nrepeated here."},"esignRef":{"description":"EsignRef is the provider's own reference for the request — what a webhook or\na status poll quotes.","type":"string"},"provider":{"description":"Provider names the e-signature provider that took the request. \"manual\" means\nno provider is wired on this deployment and the org fulfils it out of band.","type":"string"}},"type":"object"},"legal.signRequest":{"properties":{"id":{"description":"ID is the document to send for signature, from the path.","type":"string"},"signers":{"description":"Signers are the people who must sign, by name and email. At least one is\nrequired.","items":{"$ref":"#/components/schemas/legal.legalSigner"},"type":"array"}},"type":"object"},"legal.templateCatalog":{"properties":{"data":{"description":"Data is the catalog, metadata and merge fields only — never the template\nbodies, which are fetched one at a time.","items":{"$ref":"#/components/schemas/legal.templateView"},"type":"array"},"disclaimer":{"description":"Disclaimer is the boundary made visible on the wire: Hanzo Legal is document\ntooling, not legal advice.","type":"string"}},"type":"object"},"legal.templateOverride":{"properties":{"body":{"description":"Body is the text/template source. Required. Every {{.key}} it references must\nbe declared in Fields, or the save is refused rather than rendering a blank\ninto a contract later.","type":"string"},"category":{"description":"Category groups the template: formation, equity, ops or sales. Optional when\noverriding a built-in, which supplies its own.","type":"string"},"counselReview":{"description":"CounselReview marks a template whose documents must carry the counsel notice.\nIt can be raised but never lowered: a formation or equity template is always\ncounsel-review, and an override of a counsel-review built-in stays one.","type":"boolean"},"fields":{"description":"Fields declares the merge fields the body consumes. Every declared field is\nREQUIRED at generation — the engine fails closed on a missing one.","items":{"$ref":"#/components/schemas/legal.Field"},"type":"array"},"id":{"description":"ID is the template to override, from the path. Overriding a built-in id\ninherits that built-in's category, title and counsel-review posture.","type":"string"},"title":{"description":"Title is the template's display name. Required unless a built-in supplies it.","type":"string"}},"type":"object"},"legal.templateReply":{"properties":{"disclaimer":{"description":"Disclaimer is the boundary made visible on the wire.","type":"string"},"template":{"$ref":"#/components/schemas/legal.legalTemplate","description":"Template is the resolved template — the org's override if it has one, else\nthe built-in."}},"type":"object"},"legal.templateView":{"properties":{"category":{"description":"Category is the corporate need the template serves: formation, equity, ops or\nsales. Formation and equity are the securities-class categories, which is what\nforces counselReview.","type":"string"},"counselReview":{"description":"CounselReview marks a template whose rendered documents open with the counsel\nnotice. True for every formation and equity template whatever an override\nsends: the engine prepends the notice and no caller can suppress it.","type":"boolean"},"fields":{"description":"Fields declares the merge fields the body consumes — every key a generation\nmust supply, each with its human label. All are REQUIRED: a missing one is\nrefused rather than rendered as a blank into a contract.","items":{"$ref":"#/components/schemas/legal.Field"},"type":"array"},"id":{"description":"ID is the template's stable id and the path segment that fetches its body —\n\"nda\", \"msa\", \"safe\". An override keeps the built-in's id.","type":"string"},"origin":{"description":"Origin is \"builtin\" for a template the platform ships or \"org\" for one this\norg saved. It separates the catalog every tenant sees from this tenant's own.","type":"string"},"title":{"description":"Title is the display name, e.g. \"Mutual Non-Disclosure Agreement\". A generated\ndocument inherits it.","type":"string"},"version":{"description":"Version is which version of this template the caller's org resolves to. A\nbuilt-in is version 1; the org's first override is 2 and each save increments,\nso an override version never collides with the built-in's.","format":"int64","type":"integer"}},"type":"object"},"library.LibraryItem":{"properties":{"by":{"description":"By is the owner as a reader names them: the name, else the address, the\nidentity boundary carried when the item was made.","type":"string"},"bytes":{"format":"int64","type":"integer"},"created":{"type":"string"},"download":{"type":"string"},"expires":{"type":"string"},"height":{"format":"int64","type":"integer"},"id":{"type":"string"},"kind":{"type":"string"},"mime":{"type":"string"},"mine":{"type":"boolean"},"name":{"type":"string"},"origin":{"type":"string"},"owner":{"type":"string"},"pages":{"format":"int64","type":"integer"},"preview":{"type":"string"},"project":{"type":"string"},"ref":{"type":"string"},"seconds":{"format":"double","type":"number"},"shared":{"type":"boolean"},"source":{"type":"string"},"updated":{"type":"string"},"url":{"type":"string"},"width":{"format":"int64","type":"integer"}},"type":"object"},"library.itemPage":{"properties":{"data":{"description":"Data are the items, newest first.","items":{"$ref":"#/components/schemas/library.LibraryItem"},"type":"array"},"next":{"description":"Next continues the list as `cursor`; empty at its end.","type":"string"}},"type":"object"},"library.itemPatch":{"properties":{"id":{"description":"ID is the item, from the path.","type":"string"},"name":{"description":"Name renames it.","type":"string"},"project":{"description":"Project moves it to one of the organization's projects; \"\" moves it out.","type":"string"},"shared":{"description":"Shared shows it to every member of your organization, or stops.","type":"boolean"}},"type":"object"},"library.keepIn":{"properties":{"data":{"contentEncoding":"base64","description":"Data is the bytes, base64, at most 10 MiB. Required.","type":"string"},"height":{"format":"int64","type":"integer"},"key":{"description":"Key makes the save idempotent: the same source and key answer the item\nalready kept.","type":"string"},"kind":{"description":"Kind is image, video, audio, document, slides, type, model, code or file;\nabsent derives it from mime.","type":"string"},"mime":{"description":"Mime is its media type. Required.","type":"string"},"name":{"description":"Name is what it is called, a file name. Required.","type":"string"},"origin":{"description":"Origin is the path on this site back to what made it, as /chat?thread=….","type":"string"},"pages":{"format":"int64","type":"integer"},"preview":{"contentEncoding":"base64","description":"Preview is a still that shows it, base64, at most 2 MiB.","type":"string"},"project":{"description":"Project is one of the organization's projects, by slug.","type":"string"},"ref":{"description":"Ref is what made it: the conversation, the run.","type":"string"},"seconds":{"format":"double","type":"number"},"source":{"description":"Source is the product it came from: chat, dev, studio or workflow. Required.","type":"string"},"width":{"description":"Width, Height, Seconds and Pages describe it when known.","format":"int64","type":"integer"}},"type":"object"},"licensing.DeviceSignals":{"properties":{"arch":{"type":"string"},"cpuid":{"description":"CPUID is a CPU/board identifier string.","type":"string"},"disk_serial":{"description":"DiskSerial of the boot/root volume.","type":"string"},"hostname":{"description":"Hostname is a weak signal, used only as a tiebreaker.","type":"string"},"install_id":{"description":"InstallID is a per-install random the agent persists locally on first run.","type":"string"},"machine_id":{"description":"MachineID is a stable per-host id (e.g. /etc/machine-id, IOPlatformUUID,\nMachineGuid). Strongest single signal where present.","type":"string"},"macs":{"description":"MAC addresses of stable interfaces (order-insensitive; we sort).","items":{"type":"string"},"type":"array"},"os":{"description":"OS / Arch coarse platform tags.","type":"string"}},"type":"object"},"licensing.FingerprintRequest":{"properties":{"signals":{"$ref":"#/components/schemas/licensing.DeviceSignals","description":"Signals is the host material the client agent collected. Which fields\nactually participate in the binding is deliberately unspecified — send\neverything available and let the server decide."}},"type":"object"},"licensing.FingerprintResponse":{"properties":{"fingerprint":{"description":"Fingerprint is the OPAQUE binding value to pass to POST /v1/licensing/issue.\nIt is one-way: the raw signals cannot be recovered from it and are never\nechoed back.","type":"string"},"version":{"description":"Version is the binding algorithm revision, so a stored fingerprint stays\nrecognizable across a recipe rotation.","type":"string"}},"type":"object"},"licensing.HealthView":{"properties":{"env":{"description":"Env is the deployment environment (\"dev\" | \"staging\" | \"prod\").","type":"string"},"service":{"description":"Service is always \"licensing\".","type":"string"},"signer":{"description":"Signer names where the signing key lives: \"kms\" or \"local\". \"local\" means\na development key: tokens it mints are not production credentials.","type":"string"},"status":{"description":"Status is \"ok\" whenever the process is up — this is not a dependency probe.","type":"string"}},"type":"object"},"licensing.IssueRequest":{"properties":{"fingerprint":{"description":"Fingerprint is a previously-registered device binding value, as returned by\nPOST /v1/licensing/fingerprint. Leave it empty and pass Signals to bind the\ndevice at issue time instead.","type":"string"},"holder":{"description":"Holder overrides who the token is issued to; defaults to the caller's own\nvalidated subject. It NAMES the token's bearer and grants nothing on its\nown — the entitlement checked is always the caller's org's.","type":"string"},"product":{"description":"Product is the licensed commerce product the caller wants a token for.","type":"string"},"release":{"description":"Release scopes the token to one signed binary release, recorded as a\n\"release:\u003cid\u003e\" feature so a single bad release can be revoked on its own.","type":"string"},"signals":{"$ref":"#/components/schemas/licensing.DeviceSignals","description":"Signals binds the device at issue time, as an alternative to a\npre-registered fingerprint. The raw signals are never stored or echoed —\nthey are folded immediately into the one-way binding value."},"ttl_seconds":{"description":"TTLSeconds requests a token lifetime in seconds. It is clamped to the\ndeployment maximum AND to the entitlement's own expiry — a token never\noutlives the subscription that paid for it.","format":"int64","type":"integer"}},"required":["product"],"type":"object"},"licensing.IssueResponse":{"properties":{"app_id":{"description":"AppID is the brand this token runs under (\"hanzo\" | \"lux\" | \"zoo\"). The\nengine refuses a token whose app_id is not the one it was built for.","type":"string"},"exp":{"description":"Exp is the token's expiry, Unix seconds.","format":"int64","type":"integer"},"features":{"description":"Features are the capability grants copied verbatim from the plan the org\nbought. The engine enforces exactly these.","items":{"type":"string"},"type":"array"},"fingerprint_bound":{"description":"Bound reports whether a device fingerprint was folded into the token. An\nunbound token runs on any machine; a bound one runs only on the machine it\nwas bound to.","type":"boolean"},"holder":{"description":"Holder is who the token was issued to.","type":"string"},"nonce":{"description":"Nonce uniquely identifies this token, and is what a per-token revocation\nnames.","type":"string"},"token":{"description":"Token is the signed license, `base64url(payload).base64url(ed25519_sig)`.\nIt is the credential the engine runs on — treat it as a secret.","type":"string"}},"type":"object"},"licensing.JWK":{"properties":{"crv":{"description":"Crv is always \"Ed25519\".","type":"string"},"kty":{"description":"Kty is always \"OKP\".","type":"string"},"use":{"description":"Use is always \"sig\".","type":"string"},"x":{"description":"X is the public key, base64url (the JWK convention).","type":"string"}},"type":"object"},"licensing.PubkeyView":{"properties":{"alg":{"description":"Alg is always \"Ed25519\".","type":"string"},"keys":{"description":"Keys is the same key as a single-entry JWKS (OKP/Ed25519), for JWKS-shaped\nconsumers.","items":{"$ref":"#/components/schemas/licensing.JWK"},"type":"array"},"provider":{"description":"Provider names where the private half lives: \"kms\" (production) or\n\"local\" (a development key — never trust it in production).","type":"string"},"public_key":{"description":"PublicKey is the 32-byte Ed25519 public key, standard base64. This is the\nform the engine embeds for offline verification.","type":"string"},"schema":{"description":"Schema is the license payload schema version this key signs.","format":"uint8","type":"integer"},"token_format":{"description":"TokenFormat states the wire layout so an implementer can verify a token\nwithout this service's source.","type":"string"}},"type":"object"},"licensing.Release":{"properties":{"app_id":{"description":"AppID scopes the release to an app build (\"hanzo\" | \"lux\" | \"zoo\").","type":"string"},"artifact_ref":{"description":"ArtifactRef is where the binary lives (object-store key / OCI ref / path).","type":"string"},"cosign_cert":{"description":"CosignCert is the cosign/Fulcio cert (keyless) or public key ref used to\nverify CosignSignature. The download response hands this to the client.","type":"string"},"cosign_signature":{"description":"CosignSignature is the base64 cosign signature over the artifact digest.","type":"string"},"created_at":{"format":"int64","type":"integer"},"id":{"description":"ID is the release identifier, e.g. \"engine-rocm-0.4.2-linux-amd64\". The\naccelerator belongs here — one product is built several ways — and never\nin Product below.","type":"string"},"min_features":{"description":"MinFeatures, when set, are features the license must include to download.","items":{"type":"string"},"type":"array"},"platform":{"description":"Platform is \"\u003cos\u003e/\u003carch\u003e\", e.g. \"linux/amd64\".","type":"string"},"product":{"description":"Product is the licensed product this artifact belongs to (commerce SKU):\n\"engine\" for every one of those builds.","type":"string"},"sha256":{"description":"SHA256 is the hex digest of the artifact (integrity + cosign subject).","type":"string"},"version":{"description":"Version is the semantic version of the binary.","type":"string"},"yanked":{"description":"Yanked marks a pulled release (download refused; tokens may be revoked\nrelease-scoped too).","type":"boolean"}},"type":"object"},"licensing.ReleaseAsset":{"properties":{"cosign_cert":{"type":"string"},"cosign_signature":{"type":"string"},"download_url":{"description":"DownloadURL is a short-lived signed URL to the artifact bytes. The\nscaffold returns the ArtifactRef as-is; production issues a signed URL.","type":"string"},"release":{"$ref":"#/components/schemas/licensing.Release"}},"type":"object"},"licensing.ReleaseList":{"properties":{"releases":{"description":"Releases is the published releases, always an array and never null.","items":{"$ref":"#/components/schemas/licensing.Release"},"type":"array"}},"type":"object"},"licensing.VerifyRequest":{"properties":{"app":{"description":"App overrides the app_id the token is expected to carry. Leave it empty and\nthe token's own app_id is used — an online verify is informational, and it\nis the ENGINE that enforces the app at boot.","type":"string"},"token":{"description":"Token is the license token to check.","type":"string"}},"required":["token"],"type":"object"},"licensing.VerifyResponse":{"properties":{"app_id":{"description":"AppID is the brand the token runs under.","type":"string"},"exp":{"description":"Exp is the token's expiry, Unix seconds.","format":"int64","type":"integer"},"features":{"description":"Features are the capability grants the token carries.","items":{"type":"string"},"type":"array"},"fingerprint_bound":{"description":"Bound reports that the token carries a device binding.","type":"boolean"},"holder":{"description":"Holder is who the token was issued to.","type":"string"},"nonce":{"description":"Nonce uniquely identifies the token.","type":"string"},"reason":{"description":"Reason says why an invalid token was rejected. Empty when Valid.","type":"string"},"revoked":{"description":"Revoked reports that the signature was good but the token has been revoked.","type":"boolean"},"valid":{"description":"Valid is the single answer: signature, schema, expiry, app and revocation\nall passed.","type":"boolean"}},"type":"object"},"link.AccountsTotal":{"properties":{"accounts":{"description":"Accounts is how many linked accounts the total folds.","format":"int64","type":"integer"},"completionTokens":{"description":"CompletionTokens is the total completion-token count.","format":"int64","type":"integer"},"costCents":{"description":"CostCents is the total cost in cents.","format":"int64","type":"integer"},"promptTokens":{"description":"PromptTokens is the total prompt-token count.","format":"int64","type":"integer"},"requests":{"description":"Requests is the total request count the gateway routed.","format":"int64","type":"integer"},"totalTokens":{"description":"TotalTokens is the total token count.","format":"int64","type":"integer"}},"type":"object"},"link.AccountsUsage":{"properties":{"accounts":{"description":"Accounts is one row per linked account the gateway actually routed through.","items":{"$ref":"#/components/schemas/link.RoutedUsage"},"type":"array"},"scope":{"description":"Scope is always \"user\": the caller's own linked accounts.","type":"string"},"source":{"description":"Source is always \"routed\": the gateway's own routed ledger.","type":"string"},"total":{"$ref":"#/components/schemas/link.AccountsTotal","description":"Total is the honest sum across the rows."}},"type":"object"},"link.RouteCandidate":{"properties":{"account":{"description":"Account is the provider-side account identifier.","type":"string"},"available":{"description":"Available reports whether the candidate is routable right now.","type":"boolean"},"billing":{"description":"Billing is the cost consequence of dialing this candidate: plan (the\nuser's own subscription) or commerce (the metered gateway path).","type":"string"},"headroomPct":{"description":"HeadroomPct is the remaining rate-limit capacity, 0..100. A link with no\nsnapshot counts as full headroom.","format":"double","type":"number"},"host":{"description":"Host is that machine's hostname label.","type":"string"},"kind":{"description":"Kind is how the account authenticates: subscription or apikey.","type":"string"},"linkId":{"description":"LinkID is the underlying link's opaque handle.","type":"string"},"machine":{"description":"Machine is the machine the account is signed in on.","type":"string"},"plan":{"description":"Plan is the provider plan label the account is on.","type":"string"},"provider":{"description":"Provider is the AI provider the candidate account belongs to.","type":"string"},"reason":{"description":"Reason says why the candidate is not routable, when Available is false.","type":"string"}},"type":"object"},"link.RoutePlan":{"properties":{"candidates":{"description":"Candidates is every linked account in preference order: subscriptions\nfirst, then metered api-key accounts as the backstop.","items":{"$ref":"#/components/schemas/link.RouteCandidate"},"type":"array"},"generatedAt":{"description":"GeneratedAt is when the plan was computed, RFC 3339 UTC.","type":"string"},"primary":{"$ref":"#/components/schemas/link.RouteCandidate","description":"Primary is the first available candidate; absent when every account is\nrate-limited."}},"type":"object"},"link.RoutedUsage":{"properties":{"account":{"description":"Account is the provider-side account identifier.","type":"string"},"billing":{"description":"Billing is how the routed inference bills: plan or commerce.","type":"string"},"completionTokens":{"description":"CompletionTokens is the routed completion-token count.","format":"int64","type":"integer"},"costCents":{"description":"CostCents is the routed cost in cents.","format":"int64","type":"integer"},"kind":{"description":"Kind is how the account authenticates: subscription or apikey.","type":"string"},"promptTokens":{"description":"PromptTokens is the routed prompt-token count.","format":"int64","type":"integer"},"provider":{"description":"Provider is the AI provider the row's account belongs to.","type":"string"},"requests":{"description":"Requests is how many requests the gateway routed through this account.","format":"int64","type":"integer"},"totalTokens":{"description":"TotalTokens is the routed total token count.","format":"int64","type":"integer"}},"type":"object"},"link.boardResp":{"properties":{"account":{"description":"Account is the account the series narrows to, when one was named.","type":"string"},"available":{"description":"Available reports whether the warehouse answered; false is an honest \"we\nhave no data\", NOT zero usage.","type":"boolean"},"current":{"description":"Current is the live state of each lane — the dash headline.","items":{"$ref":"#/components/schemas/link.readingView"},"type":"array"},"from":{"description":"From is when the resolved window opens, RFC 3339 UTC.","type":"string"},"provider":{"description":"Provider is the provider whose meter answered.","type":"string"},"range":{"description":"Range is the resolved period label.","type":"string"},"scope":{"description":"Scope is always \"user\": the caller's own linked accounts.","type":"string"},"source":{"description":"Source is always \"account\": the provider's own meter, not a Hanzo charge.","type":"string"},"to":{"description":"To is where it closes, EXCLUSIVE, RFC 3339 UTC — the instant the read was\nserved, so the window walks forward with the clock and two reads a minute\napart do not cover the same period.","type":"string"},"windows":{"description":"Windows is every window instance in range, newest first.","items":{"$ref":"#/components/schemas/link.readingView"},"type":"array"}},"type":"object"},"link.deviceView":{"properties":{"accounts":{"description":"Accounts is every account the caller has signed in on this machine.","items":{"$ref":"#/components/schemas/link.linkView"},"type":"array"},"activeSessions":{"description":"ActiveSessions is how many agent sessions the caller currently has running\non this machine; 0 where the agent plane is not mounted.","format":"int64","type":"integer"},"host":{"description":"Host is the machine's hostname label, from its most-recently-seen account.","type":"string"},"lastSeen":{"description":"LastSeen is when any account on this machine last reported, RFC 3339 UTC.","type":"string"},"machine":{"description":"Machine is the stable machine identifier.","type":"string"},"os":{"description":"OS is the machine's operating system label.","type":"string"}},"type":"object"},"link.enrollReq":{"properties":{"account":{"description":"Account is the provider-side account identifier.","type":"string"},"host":{"description":"Host is the machine's human hostname label.","type":"string"},"kind":{"description":"Kind decides how the account's inference BILLS and defaults to\nsubscription: a subscription account bills the user's own monthly plan and\nis metered here for visibility only, while an apikey account bills through\ncommerce on the gateway path.","type":"string"},"machine":{"description":"Machine is the stable machine identifier. Required, length-bounded.","type":"string"},"os":{"description":"OS is the machine's operating system label.","type":"string"},"plan":{"description":"Plan is the provider plan label (e.g. \"Claude Max\").","type":"string"},"provider":{"description":"Provider is the AI provider the account belongs to. Required, length-bounded.","type":"string"},"usage":{"description":"Usage is an optional usage snapshot, clamped and re-serialized to known\nfields; omitting it keeps the last good one."}},"type":"object"},"link.ingestReq":{"properties":{"account":{"description":"Account is the provider-side account the sample belongs to.","type":"string"},"cachedInputTokens":{"description":"CachedInputTokens is the window's cached-prompt-token count.","format":"int64","type":"integer"},"confidence":{"description":"Confidence says how real the counters are, as the meter graded itself.","type":"string"},"costCents":{"description":"CostCents is the window's spend in cents, as the provider's meter states it.","format":"int64","type":"integer"},"costLimitCents":{"description":"CostLimitCents is the window's spend cap in cents, when the meter knows one.","format":"int64","type":"integer"},"currency":{"description":"Currency is the ISO currency the cost fields are stated in.","type":"string"},"inputTokens":{"description":"InputTokens is the window's prompt-token count.","format":"int64","type":"integer"},"kind":{"description":"Kind is subscription or apikey; anything else is refused.","type":"string"},"lane":{"description":"Lane names the meter's own lane label for this measurement.","type":"string"},"machine":{"description":"Machine is the machine the collector observed the account on. Required.","type":"string"},"outputTokens":{"description":"OutputTokens is the window's completion-token count.","format":"int64","type":"integer"},"plan":{"description":"Plan is the provider plan label the account is on.","type":"string"},"provider":{"description":"Provider is the AI provider whose meter reported this sample. Required.","type":"string"},"requests":{"description":"Requests is the window's request count.","format":"int64","type":"integer"},"resetsAt":{"description":"ResetsAt is when the window resets, RFC 3339, bounded.","type":"string"},"samples":{"description":"Samples is the batch form, up to 256 samples; leave it empty to send one\nsample inline on the same fields.","items":{"$ref":"#/components/schemas/link.readingReq"},"type":"array"},"synthetic":{"description":"Synthetic marks a sample the collector derived rather than observed.","type":"boolean"},"totalTokens":{"description":"TotalTokens is the window's total token count.","format":"int64","type":"integer"},"usedPct":{"description":"UsedPct is how much of the window's allowance is consumed, clamped 0..100.","format":"double","type":"number"},"window":{"description":"Window is the window class, one of 6h, day, week, month; anything else is\nrefused rather than silently reclassified.","type":"string"},"windowMinutes":{"description":"WindowMinutes is the window's length as the meter reported it.","format":"int32","type":"integer"},"windowStart":{"description":"WindowStart is when the measured window opened, RFC 3339, bounded to a\nsane interval around now.","type":"string"}},"type":"object"},"link.ingestResp":{"properties":{"accepted":{"description":"Accepted is how many samples this report landed.","format":"int64","type":"integer"},"links":{"description":"Links is the link row each distinct (machine, provider, account) in the\nbatch refreshed.","items":{"$ref":"#/components/schemas/link.linkView"},"type":"array"},"stored":{"description":"Stored reports whether history was durably written; false means the\nwarehouse was unavailable and only the link rows were refreshed.","type":"boolean"}},"type":"object"},"link.linkList":{"properties":{"devices":{"description":"Devices is the same rows folded per machine — the cross-machine \"AI\nProviders / Accounts\" view.","items":{"$ref":"#/components/schemas/link.deviceView"},"type":"array"},"links":{"description":"Links is every link the caller registered, newest first. Revoked links are\nINCLUDED rather than dropped, because a logged-out account keeps its usage\nhistory and audit trail.","items":{"$ref":"#/components/schemas/link.linkView"},"type":"array"}},"type":"object"},"link.linkView":{"properties":{"account":{"description":"Account is the provider-side account identifier, when the collector knows it.","type":"string"},"billing":{"description":"Billing is how this account's inference bills — plan (the user's own\nsubscription, metered here for visibility only) or commerce (the gateway\npath). Derived from Kind, never stored.","type":"string"},"createdAt":{"description":"CreatedAt is when the link was first registered, RFC 3339 UTC.","type":"string"},"host":{"description":"Host is the machine's human hostname label, from its most recent report.","type":"string"},"id":{"description":"ID is the link's opaque handle (\"link_\" + 32 hex chars).","type":"string"},"kind":{"description":"Kind is how the account authenticates: subscription or apikey.","type":"string"},"lastSeen":{"description":"LastSeen is when the account last reported, RFC 3339 UTC.","type":"string"},"machine":{"description":"Machine is the stable machine identifier the collector reports.","type":"string"},"os":{"description":"OS is the machine's operating system label.","type":"string"},"plan":{"description":"Plan is the provider plan label (e.g. \"Claude Max\").","type":"string"},"provider":{"description":"Provider is the AI provider this account belongs to (claude, openai, hanzo…).","type":"string"},"status":{"description":"Status is linked or revoked. Revoked rows are retained for history.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the link was last refreshed, RFC 3339 UTC.","type":"string"},"usage":{"description":"Usage is the last good usage snapshot, clamped and re-serialized to known\nfields at ingest."},"user":{"description":"User is the owning subject — the validated caller who registered the link.","type":"string"}},"type":"object"},"link.readingReq":{"properties":{"account":{"description":"Account is the provider-side account the sample belongs to.","type":"string"},"cachedInputTokens":{"description":"CachedInputTokens is the window's cached-prompt-token count.","format":"int64","type":"integer"},"confidence":{"description":"Confidence says how real the counters are, as the meter graded itself.","type":"string"},"costCents":{"description":"CostCents is the window's spend in cents, as the provider's meter states it.","format":"int64","type":"integer"},"costLimitCents":{"description":"CostLimitCents is the window's spend cap in cents, when the meter knows one.","format":"int64","type":"integer"},"currency":{"description":"Currency is the ISO currency the cost fields are stated in.","type":"string"},"inputTokens":{"description":"InputTokens is the window's prompt-token count.","format":"int64","type":"integer"},"kind":{"description":"Kind is subscription or apikey; anything else is refused.","type":"string"},"lane":{"description":"Lane names the meter's own lane label for this measurement.","type":"string"},"machine":{"description":"Machine is the machine the collector observed the account on. Required.","type":"string"},"outputTokens":{"description":"OutputTokens is the window's completion-token count.","format":"int64","type":"integer"},"plan":{"description":"Plan is the provider plan label the account is on.","type":"string"},"provider":{"description":"Provider is the AI provider whose meter reported this sample. Required.","type":"string"},"requests":{"description":"Requests is the window's request count.","format":"int64","type":"integer"},"resetsAt":{"description":"ResetsAt is when the window resets, RFC 3339, bounded.","type":"string"},"synthetic":{"description":"Synthetic marks a sample the collector derived rather than observed.","type":"boolean"},"totalTokens":{"description":"TotalTokens is the window's total token count.","format":"int64","type":"integer"},"usedPct":{"description":"UsedPct is how much of the window's allowance is consumed, clamped 0..100.","format":"double","type":"number"},"window":{"description":"Window is the window class, one of 6h, day, week, month; anything else is\nrefused rather than silently reclassified.","type":"string"},"windowMinutes":{"description":"WindowMinutes is the window's length as the meter reported it.","format":"int32","type":"integer"},"windowStart":{"description":"WindowStart is when the measured window opened, RFC 3339, bounded to a\nsane interval around now.","type":"string"}},"type":"object"},"link.readingView":{"properties":{"account":{"description":"Account is the provider-side account the sample belongs to.","type":"string"},"cachedInputTokens":{"description":"CachedInputTokens is the window's cached-prompt-token count.","format":"int64","type":"integer"},"confidence":{"description":"Confidence says whether the counters that remain mean anything, as the\nmeter graded itself.","type":"string"},"costCents":{"description":"CostCents is the window's spend in cents, as the provider's meter states it.","format":"int64","type":"integer"},"costLimitCents":{"description":"CostLimitCents is the window's spend cap in cents, when the meter knows one.","format":"int64","type":"integer"},"currency":{"description":"Currency is the ISO currency the cost fields are stated in.","type":"string"},"inputTokens":{"description":"InputTokens is the window's prompt-token count.","format":"int64","type":"integer"},"lane":{"description":"Lane names the meter's own lane label for this measurement.","type":"string"},"machine":{"description":"Machine is the machine the collector observed the account on.","type":"string"},"outputTokens":{"description":"OutputTokens is the window's completion-token count.","format":"int64","type":"integer"},"plan":{"description":"Plan is the provider plan label the account is on.","type":"string"},"requests":{"description":"Requests is the window's request count.","format":"int64","type":"integer"},"resetsAt":{"description":"ResetsAt is when the window resets, RFC 3339 UTC.","type":"string"},"synthetic":{"description":"Synthetic marks a sample the collector derived rather than observed.","type":"boolean"},"totalTokens":{"description":"TotalTokens is the window's total token count.","format":"int64","type":"integer"},"usedPct":{"description":"UsedPct is how much of the window's allowance is consumed, 0..100.","format":"double","type":"number"},"window":{"description":"Window is the window class: 6h, day, week or month.","type":"string"},"windowMinutes":{"description":"WindowMinutes is the window's length as the meter reported it.","format":"int32","type":"integer"},"windowStart":{"description":"WindowStart is when the measured window opened, RFC 3339 UTC.","type":"string"}},"type":"object"},"link.revokeResp":{"properties":{"links":{"description":"Links is each revoked row with its new status — retained, not deleted, so\nusage history and the audit trail survive the log-out.","items":{"$ref":"#/components/schemas/link.linkView"},"type":"array"},"revoked":{"description":"Revoked is how many links this call revoked.","format":"int64","type":"integer"},"sessionsStopped":{"description":"SessionsStopped is how many of the caller's own agent sessions stopped. A\nstop that fails does not fail the revoke, so this may honestly report fewer.","format":"int64","type":"integer"}},"type":"object"},"link.sourceState":{"properties":{"available":{"description":"Available reports whether this ledger answered; false is honest\n\"unavailable\", never a zero that would read as no usage.","type":"boolean"},"note":{"description":"Note says in prose what the ledger's numbers mean.","type":"string"},"scope":{"description":"Scope is whose usage the ledger measures: user or org.","type":"string"},"source":{"description":"Source is the table of record behind the ledger.","type":"string"}},"type":"object"},"link.summaryResp":{"properties":{"account":{"$ref":"#/components/schemas/link.sourceState","description":"Account reports the linked-accounts ledger's own availability, so a partial\nanswer never fabricates this half. It is scoped to the CALLER: the accounts\nthey linked, metered from each provider's own login."},"from":{"description":"From is when the window opens, RFC 3339 UTC. ONE resolver fixes it for both\nledgers, so the account rows and the Hanzo rows always cover the same period\n— two resolvers could drift and turn the union into a lie.","type":"string"},"hanzo":{"$ref":"#/components/schemas/link.sourceState","description":"Hanzo reports the same for the Hanzo-routed ledger, which is scoped to the\nORG rather than the caller — a different question over the same window. The\ntwo are independent: either can be unavailable while the other answers, and\nRows then carries only the half that did."},"range":{"description":"Range is the resolved period label.","type":"string"},"rows":{"description":"Rows is the union of both ledgers, each row labelled by source and scope —\nconcatenated, NEVER summed: a plan's percentage is not money.","items":{"$ref":"#/components/schemas/link.totalView"},"type":"array"},"to":{"description":"To is where the window closes, EXCLUSIVE, RFC 3339 UTC — the instant the read\nwas served. Shared by both ledgers, for the reason From gives.","type":"string"}},"type":"object"},"link.totalView":{"properties":{"confidence":{"description":"Confidence says how real the row's numbers are.","type":"string"},"costCents":{"description":"CostCents is the period's spend in cents, in the row's own ledger.","format":"int64","type":"integer"},"provider":{"description":"Provider is the provider the row totals.","type":"string"},"requests":{"description":"Requests is the period's request count.","format":"int64","type":"integer"},"scope":{"description":"Scope is whose usage the row measures: user or org.","type":"string"},"source":{"description":"Source is whose meter the row came from: account or hanzo.","type":"string"},"tokens":{"description":"Tokens is the period's total token count.","format":"int64","type":"integer"},"usedPct":{"description":"UsedPct is the plan consumption percentage, on the account side.","format":"double","type":"number"},"window":{"description":"Window is the window class the row totals, on the account side.","type":"string"},"windows":{"description":"Windows is how many window instances the row folds.","format":"int64","type":"integer"}},"type":"object"},"liveness":{"properties":{"service":{"description":"Service names the answering subsystem; it is always commerce.","type":"string"},"status":{"description":"Status is always ok: mounted is the only state that can answer.","type":"string"}},"type":"object"},"lsp.Answer":{"properties":{"cold":{"description":"Cold reports that this request paid to PREPARE the revision — the tree\nwrite, the dependency fetch and the language server's first index. It is\nthe billed event, surfaced so a caller can see what it was charged for.","type":"boolean"},"completions":{"description":"Completions is complete's answer: the candidates at the position, typed and\nresolved through the repository's dependencies rather than guessed from text.","items":{"$ref":"#/components/schemas/lsp.Completion"},"type":"array"},"diagnostics":{"description":"Diagnostics is diagnostics' answer: every problem the server finds in the\nwhole file, position ignored. Empty means it found none.","items":{"$ref":"#/components/schemas/lsp.Diagnostic"},"type":"array"},"hover":{"description":"Hover is hover's answer: the type and documentation as the language server\nitself renders them, so it is prose meant to be shown, not parsed.","type":"string"},"lang":{"description":"Lang is the language the server that answered speaks (\"go\"), as the daemon\nreports it. Empty when the daemon named none.","type":"string"},"locations":{"description":"Locations is locate's answer: where the symbol is defined, referenced, typed\nor implemented, per the relation asked for. Empty means the server resolved\nnothing there, which is an answer.","items":{"$ref":"#/components/schemas/lsp.Location"},"type":"array"},"op":{"description":"Op is the question that was asked: hover, locate, symbols, diagnostics or\ncomplete. It names which result field below is the populated one.","type":"string"},"path":{"description":"Path is the repo-relative file the question was about, echoed back.","type":"string"},"repo":{"description":"Repo is the repository the question was about, echoed back.","type":"string"},"rev":{"description":"Rev is the RESOLVED commit sha, never the branch or tag that was asked for.\nIt is what makes an answer re-askable: a branch moves, this does not.","type":"string"},"symbols":{"description":"Symbols is symbols' answer: the file's whole outline, position ignored.","items":{"$ref":"#/components/schemas/lsp.Symbol"},"type":"array"}},"type":"object"},"lsp.Completion":{"properties":{"detail":{"description":"Detail is the server's short elaboration, typically the type or signature.","type":"string"},"kind":{"description":"Kind is the LSP CompletionItemKind number (2 method, 3 function, 5 field, 6\nvariable, …), passed through as the protocol spells it.","format":"int64","type":"integer"},"label":{"description":"Label is the text a client would insert, and what an editor lists.","type":"string"}},"type":"object"},"lsp.Diagnostic":{"properties":{"code":{"description":"Code is the checker's own identifier for the rule, a string or a number\ndepending on the server. Absent when it published none."},"message":{"description":"Message is the problem in the server's own words, meant to be shown.","type":"string"},"range":{"$ref":"#/components/schemas/lsp.Range","description":"Range is the span the problem is about."},"severity":{"description":"Severity is the LSP's: 1 error, 2 warning, 3 information, 4 hint. A file with\nonly 3s and 4s still compiles.","format":"int64","type":"integer"},"source":{"description":"Source is which checker reported it (\"compiler\", \"go vet\", a linter's name),\nwhich is what separates a build error from a style opinion.","type":"string"}},"type":"object"},"lsp.Location":{"properties":{"external":{"description":"External is true when the answer left the repository — the case a static index\ncannot answer, and the reason this service resolves through dependencies.","type":"boolean"},"path":{"description":"Path is repo-relative while External is false, and the module coordinate\n(\"golang.org/x/mod@v0.14.0/semver/semver.go\") once it is true.","type":"string"},"range":{"$ref":"#/components/schemas/lsp.Range","description":"Range is the span inside that file, in LSP positions."}},"type":"object"},"lsp.Position":{"properties":{"character":{"description":"Character is a 0-based UTF-16 code-unit offset within Line, per the LSP\nspecification: not a byte offset and not a rune index. An emoji before the\ncursor counts as one here and as two in Go's arithmetic.","format":"int64","type":"integer"},"line":{"description":"Line is 0-BASED, per the LSP specification — one less than the line an editor\nshows a human.","format":"int64","type":"integer"}},"type":"object"},"lsp.Query":{"properties":{"character":{"description":"Character is a 0-based UTF-16 code-unit offset within Line, per the LSP\nspecification — not a byte offset and not a rune index.","format":"int64","type":"integer"},"line":{"description":"Line is 0-based, per the LSP specification.","format":"int64","type":"integer"},"path":{"description":"Path is the repo-relative file, e.g. \"apps/lsp/lsp.go\".","type":"string"},"relation":{"description":"Relation refines locate: definition, reference, type or implementation.\nEmpty means definition. Every other op ignores it.","type":"string"},"repo":{"description":"Repo is the repository NAME within the caller's own org, e.g. \"cloud\".\nNot a URL and not an owner/name pair: the owner is the validated\nprincipal's org, so this names a repository the caller already owns.","type":"string"},"rev":{"description":"Rev is a branch, tag or commit sha. Empty means the default branch. It is\nresolved to a commit before anything else happens, so an answer is always\nabout one immutable tree.","type":"string"}},"type":"object"},"lsp.Range":{"properties":{"end":{"$ref":"#/components/schemas/lsp.Position","description":"End is the position just past the span, excluded — the range is half-open, so\nan empty range has Start equal to End."},"start":{"$ref":"#/components/schemas/lsp.Position","description":"Start is the first position in the span, included."}},"type":"object"},"lsp.Symbol":{"properties":{"detail":{"description":"Detail is the server's short elaboration, typically the signature. Absent when\nit offered none.","type":"string"},"kind":{"description":"Kind is the LSP SymbolKind number (5 class, 6 method, 12 function, 23 struct,\n…), passed through rather than translated to a word — these callers already\nspeak LSP, and inventing a second vocabulary is how the two drift.","format":"int64","type":"integer"},"name":{"description":"Name is the declared identifier.","type":"string"},"range":{"$ref":"#/components/schemas/lsp.Range","description":"Range is the declaration's span in the file."}},"type":"object"},"market.Day":{"properties":{"close":{"type":"string"},"count":{"description":"Count is transactions in the day, where the table keeps one.","format":"int64","type":"integer"},"date":{"description":"Date is the day's start, unix seconds.","format":"int64","type":"integer"},"high":{"type":"string"},"locked":{"type":"string"},"low":{"type":"string"},"open":{"type":"string"},"price":{"type":"string"},"volume":{"type":"string"}},"type":"object"},"market.Figures":{"properties":{"count":{"format":"int64","type":"integer"},"locked":{"type":"string"},"pools":{"format":"int64","type":"integer"},"volume":{"type":"string"}},"type":"object"},"market.History":{"properties":{"at":{"description":"At is the token this is the history of, lowercased.","type":"string"},"chain":{"type":"string"},"days":{"description":"Days is oldest first, which is the order a chart draws. `[]` for a token the\nindexer holds no day for, `null` where the read failed.","items":{"$ref":"#/components/schemas/market.Day"},"type":"array"},"reach":{"$ref":"#/components/schemas/market.Reach"}},"type":"object"},"market.Market":{"properties":{"amm":{"description":"Amm reports whether an automated market maker is deployed on this chain,\nwhich is the registry's factory addresses being present and not the indexer\nhaving rows. The two disagree in exactly the interesting case: a chain with a\nfactory and nothing traded yet is a live venue with no history, and a chain\nwith neither has no venue at all.","type":"boolean"},"coin":{"type":"string"},"day":{"$ref":"#/components/schemas/market.Day"},"factory":{"additionalProperties":{"type":"string"},"description":"Factory is the AMM's factory contracts, by generation, omitted where none is\ndeployed. Addresses come from the registry because that is what the indexer\nitself ingested from; anything else is a second copy free to drift.","type":"object"},"figures":{"$ref":"#/components/schemas/market.Figures","description":"Figures is the chain's whole market maker, and Day its most recent active one.\nBoth are absent unless Reach says Read, so a caller cannot mistake a zero this\nprocess never received for one the indexer computed. Day is also absent on a\nchain that has never traded — which reach reports as Read, so the two absences\nare told apart by the state beside them and never by the gap itself."},"graph":{"description":"Graph is where this chain's indexer answers, empty where it has none.","type":"string"},"id":{"description":"ID is the EVM chain id, which is what a wallet must agree with.","format":"int64","type":"integer"},"name":{"type":"string"},"reach":{"$ref":"#/components/schemas/market.Reach","description":"Reach is how far the read of this chain's FIGURES got — its own, so one\nindexer being down describes one row and leaves the others to answer."},"rpc":{"description":"RPC is the chain's PUBLIC JSON-RPC, empty where the registry names only a\nroute this process happens to have. The registry's own `rpc` field is the\nINDEXER's route to the node and is sometimes inside its cluster — plain HTTP\non a `.svc.cluster.local` name — which is reachable from the indexer, from\nnothing else, and from no browser. Publishing that as the chain's endpoint\nhands every caller an address that cannot answer them. See [endpoint].","type":"string"},"slug":{"description":"Slug is the chain's word in every indexer path — `cchain`, `zoo`. It is the\nvalue a caller passes back as `chain`, and it is NOT the chain id: `96369`,\n`C` and `c-chain` all answer 404 in that position.","type":"string"}},"type":"object"},"market.Pool":{"properties":{"at":{"description":"At is the pool contract's address, lowercase.","type":"string"},"count":{"format":"int64","type":"integer"},"fee":{"description":"Fee is the pool's tier in hundredths of a basis point — 3000 is 0.3%. It is\nthe integer the contract stores, unconverted, so nothing here rounds a rate.","format":"int64","type":"integer"},"locked":{"type":"string"},"token0":{"$ref":"#/components/schemas/market.Token"},"token0Price":{"description":"Token0Price is token1 per token0, and Token1Price its reciprocal, both as the\nindexer computed them. Neither is a price ON anything: it is the ratio the\npool's reserves stand at.","type":"string"},"token1":{"$ref":"#/components/schemas/market.Token"},"token1Price":{"type":"string"},"volume":{"type":"string"}},"type":"object"},"market.Pools":{"properties":{"chain":{"type":"string"},"pools":{"description":"Pools is `[]` where the chain has none and `null` where the read failed.\n\nThe two are different sentences and the wire says which: an empty ARRAY is the\nindexer answering that nothing is deployed there, and `null` is nobody having\nanswered. `omitempty` would collapse both to an absent key — which is the\nexact flattening the reach beside it exists to prevent, reintroduced one\nstruct tag lower down.","items":{"$ref":"#/components/schemas/market.Pool"},"type":"array"},"reach":{"$ref":"#/components/schemas/market.Reach"}},"type":"object"},"market.Precompile":{"properties":{"at":{"type":"string"},"code":{"description":"Code is whether the address carries any. False is an ANSWER — the node\nreplied and there is nothing deployed there — and is not the same as the read\nhaving failed, which the enclosing Reach reports instead.","type":"boolean"},"name":{"type":"string"},"role":{"type":"string"}},"type":"object"},"market.Reach":{"properties":{"at":{"description":"At is `read`, `unconfigured`, `unreachable` or `refused`.\n\nThe four values are written out here because this document cannot carry an\nenum, so the description IS the contract a client reads. Spelling the Go\nconstant names instead would name four identifiers no caller can see.","type":"string"},"why":{"description":"Why is the upstream's own words, on Unreachable and Refused, and empty\notherwise. It is the upstream's and not ours: a failure reported without its\nreason sends the reader to look at the venue, which is the one place the fault\nis not.","type":"string"}},"type":"object"},"market.Roster":{"properties":{"chains":{"description":"Chains is `[]` where the registry answered and named none, and `null` where\nit did not answer — never absent, because a missing key and an empty list\nread alike and only one of them means \"there are none\". Each row carries its\nOWN reach for its figures, so a chain whose indexer is down is one row\nsaying so.","items":{"$ref":"#/components/schemas/market.Market"},"type":"array"},"reach":{"$ref":"#/components/schemas/market.Reach","description":"Reach is how far the read of the REGISTRY got. It governs the list: a\nregistry that did not answer yields no rows, and the reason it did not is\nhere rather than in an empty array a caller would read as \"no chains exist\"."}},"type":"object"},"market.Survey":{"properties":{"carries":{"description":"Carries is all four where the node answered and `null` where it did not. It is\nnever a short list: a partial read reporting three would let a reader count\nthem and conclude the chain is missing one.","items":{"$ref":"#/components/schemas/market.Precompile"},"type":"array"},"chain":{"type":"string"},"reach":{"$ref":"#/components/schemas/market.Reach"},"rpc":{"description":"RPC is the endpoint that was asked, so an answer names where it came from.","type":"string"}},"type":"object"},"market.Token":{"properties":{"at":{"description":"At is the token's contract address, lowercase.","type":"string"},"decimals":{"format":"int64","type":"integer"},"name":{"type":"string"},"symbol":{"type":"string"}},"type":"object"},"market.Tokens":{"properties":{"chain":{"type":"string"},"reach":{"$ref":"#/components/schemas/market.Reach"},"tokens":{"description":"Tokens is `[]` where the indexer holds none and `null` where the read failed.","items":{"$ref":"#/components/schemas/market.Token"},"type":"array"}},"type":"object"},"marketing.Address":{"properties":{"city":{"description":"City is the city. Required.","type":"string"},"country":{"description":"Country is the country. Required.","type":"string"},"postcode":{"description":"Postcode is the postal code. Optional.","type":"string"},"region":{"description":"Region is the state, province or region. Optional.","type":"string"},"street":{"description":"Street is the street address, on one line. Required.","type":"string"}},"type":"object"},"marketing.Answer":{"properties":{"answer":{"description":"Answer is what the person said; options they picked are joined by commas.","type":"string"},"question":{"description":"Question is the question as the form asked it, on one line.","type":"string"}},"type":"object"},"marketing.Audience":{"properties":{"createdAt":{"description":"CreatedAt is unix seconds when the filter was saved, server-assigned.","format":"int64","type":"integer"},"event":{"description":"Event is the analytics event a member must have fired. EMPTY MEANS NO\nFILTER: the audience is then every mailable customer in the org, and no\nwarehouse is consulted.","type":"string"},"id":{"description":"ID is the server-assigned audience id (\"aud_\" + 128 random bits).","type":"string"},"name":{"description":"Name is the audience's label. Required, trimmed, capped at 1024 bytes.","type":"string"},"updatedAt":{"description":"UpdatedAt is unix seconds of the last write, server-assigned, and the key\nthe audience list is ordered by (newest first). A saved audience has no\nupdate route, so in practice it stays equal to CreatedAt: to change a\nfilter you save another one.","format":"int64","type":"integer"},"windowDays":{"description":"WindowDays is how far back the event counts, ending now. 0 means 30 and\nnothing above 3650 is honoured. Ignored when Event is empty.","format":"int64","type":"integer"}},"type":"object"},"marketing.AudienceList":{"properties":{"data":{"description":"Data is the page; an empty array when the org has saved no audience.","items":{"$ref":"#/components/schemas/marketing.Audience"},"type":"array"}},"type":"object"},"marketing.AudiencePreview":{"properties":{"available":{"description":"Available is false when the roster or the warehouse could not be read; the\ncounts are then zero because nothing was measured, not because the cohort\nis empty, and Reason says which read failed.","type":"boolean"},"count":{"description":"Count is the cohort size: distinct warehouse identifiers for an event\naudience, mailable customers for an event-less (whole-org) one.","format":"int64","type":"integer"},"deliverable":{"description":"Deliverable is how many de-duplicated mailboxes a send would reach. Two\ncustomers sharing an address count once, so it is \u003c= Count.","format":"int64","type":"integer"},"reason":{"description":"Reason is the error text of the read that failed: the org's roster could\nnot be loaded (\"identity store unavailable…\"), or the cohort query had no\nwarehouse to run against (\"analytics warehouse not configured\"). Absent\nwhen the evaluation succeeded, so its presence and Available=false are one\nfact seen twice.","type":"string"},"sample":{"description":"Sample is up to 1000 cohort IDENTIFIERS — never addresses, which product\nanalytics does not hold. Empty for an event-less (whole-org) audience.","items":{"type":"string"},"type":"array"},"source":{"description":"Source names where the cohort was read: the events table for an event\naudience, \"iam:\u003corg\u003e\" for the whole-org one.","type":"string"},"unmatched":{"description":"Unmatched is how many cohort identifiers named nobody on the org's roster\nand so have no address to mail. It is reported rather than hidden: it is\nthe honest explanation for a cohort of 500 that mails 3. Always 0 for an\nevent-less (whole-org) audience, which starts from the roster and has\nnothing to match.","format":"int64","type":"integer"}},"type":"object"},"marketing.Beta":{"properties":{"actions":{"description":"Actions are the actions that earned points, oldest first.","items":{"$ref":"#/components/schemas/marketing.BetaAction"},"type":"array"},"answers":{"description":"Answers are the application's answers.","items":{"$ref":"#/components/schemas/marketing.BetaAnswer"},"type":"array"},"applied":{"description":"Applied is whether the account has applied: its record names a program.","type":"boolean"},"betas":{"description":"Betas are the ids of the unreleased products asked for.","items":{"type":"string"},"type":"array"},"github":{"description":"GitHub is the GitHub login the account's stars are counted for.","type":"string"},"lead":{"description":"Lead is the reference the application was filed under as a lead.","type":"string"},"of":{"description":"Of is how many people are on the waitlist, as the board counts them.","format":"int64","type":"integer"},"place":{"description":"Place is the record's place on the waitlist, 1 first; 0 with no record, or\nwhen the board did not answer.","format":"int64","type":"integer"},"points":{"description":"Points is the sum of what Actions earned.","format":"int64","type":"integer"},"program":{"description":"Program is the program applied to: beta, research or partner.","type":"string"},"requested":{"additionalProperties":{"type":"string"},"description":"Requested is when each of Betas was asked for, RFC 3339 in UTC, by id.","type":"object"},"score":{"description":"Score is what the waitlist ranks the record by: Points, the account's\nreferrals and its token usage (GET /v1/leaderboard/beta says how). 0 with no\nrecord, or when the board did not answer.","format":"int64","type":"integer"},"since":{"description":"Since is when the record began, as the CRM stamped it; empty with no record.","type":"string"}},"type":"object"},"marketing.BetaActIn":{"properties":{"action":{"description":"Action is star or follow.","type":"string"},"github":{"description":"GitHub is the person's GitHub login, for a star. Once a star is counted it\nis the record's, and another login is refused.","type":"string"},"target":{"description":"Target is the repository starred (hanzoai/\u003cname\u003e) or the founder's link\nfollowed (antje or zach, then github, linkedin or x: zach/github).","type":"string"}},"type":"object"},"marketing.BetaAction":{"properties":{"action":{"description":"Action is what was done: star, verified on GitHub, or follow, counted on trust.","type":"string"},"at":{"description":"At is when it was counted, RFC 3339 in UTC.","type":"string"},"points":{"description":"Points is what the action earned.","format":"int64","type":"integer"},"target":{"description":"Target is what it was done to: a repository (hanzoai/ai) for a star, a\nfounder's link (zach/github) for a follow.","type":"string"}},"type":"object"},"marketing.BetaAnswer":{"properties":{"answer":{"description":"Answer is what the person answered: one entry for a typed answer or a single\nchoice, one entry per option for several.","items":{"type":"string"},"type":"array"},"id":{"description":"ID is the question's id on the form, such as \"builds\".","type":"string"},"question":{"description":"Question is the question as the form asked it.","type":"string"}},"type":"object"},"marketing.BetaIn":{"properties":{"answers":{"description":"Answers replace the record's answers.","items":{"$ref":"#/components/schemas/marketing.BetaAnswer"},"type":"array"},"betas":{"description":"Betas replace the ids of the unreleased products the account asked for.","items":{"type":"string"},"type":"array"},"lead":{"description":"Lead is the reference the application was filed under as a lead\n(POST /v1/marketing/leads), so the record and the lead are one person's.","type":"string"},"program":{"description":"Program is the program applied to: beta, research or partner.","type":"string"}},"type":"object"},"marketing.BetaInvite":{"properties":{"headers":{"additionalProperties":{"type":"string"},"description":"Headers are the headers the message carries beside its own: the one-click\nunsubscribe (RFC 8058), List-Unsubscribe and List-Unsubscribe-Post.","type":"object"},"html":{"description":"HTML is the same message as HTML.","type":"string"},"id":{"description":"ID is the invite's id: the link's utm_content and what the sent report names.","type":"string"},"link":{"description":"Link is the member's referral link for this invite.","type":"string"},"subject":{"description":"Subject is the message's subject.","type":"string"},"text":{"description":"Text is the message's plain text, its unsubscribe line last.","type":"string"},"to":{"description":"To is the invited address.","type":"string"}},"type":"object"},"marketing.BetaInviteCounts":{"properties":{"joined":{"description":"Joined counts invites whose invitee signed up with the member's code.","format":"int64","type":"integer"},"left":{"description":"Left is how many more the member may invite now.","format":"int64","type":"integer"},"sent":{"description":"Sent counts invites sent, joined ones included.","format":"int64","type":"integer"}},"type":"object"},"marketing.BetaInviteFailure":{"properties":{"id":{"description":"ID is the invite's id.","type":"string"},"why":{"description":"Why is the mailbox's reason, at most 200 characters.","type":"string"}},"type":"object"},"marketing.BetaInviteIn":{"properties":{"to":{"description":"To is the addresses to invite, at most 50. Each is trimmed and lower-cased;\none named twice is one.","items":{"type":"string"},"type":"array"}},"type":"object"},"marketing.BetaInviteList":{"properties":{"counts":{"$ref":"#/components/schemas/marketing.BetaInviteCounts","description":"Counts are the caller's invites, counted."},"invites":{"description":"Invites are the caller's invites, newest first; a reservation that lapsed\nunsent is not among them.","items":{"$ref":"#/components/schemas/marketing.BetaInviteRow"},"type":"array"}},"type":"object"},"marketing.BetaInviteRow":{"properties":{"at":{"description":"At is when it last moved, RFC 3339 in UTC.","type":"string"},"id":{"description":"ID is the invite's id.","type":"string"},"status":{"description":"Status is reserved, sent, failed or joined.","type":"string"},"to":{"description":"To is the invited address.","type":"string"}},"type":"object"},"marketing.BetaInviteRows":{"properties":{"invites":{"description":"Invites are those invites as they stand.","items":{"$ref":"#/components/schemas/marketing.BetaInviteRow"},"type":"array"}},"type":"object"},"marketing.BetaInviteSentIn":{"properties":{"failed":{"description":"Failed are the invites that did not go out.","items":{"$ref":"#/components/schemas/marketing.BetaInviteFailure"},"type":"array"},"ids":{"description":"IDs are the invites sent.","items":{"type":"string"},"type":"array"}},"type":"object"},"marketing.BetaInviteSkip":{"properties":{"to":{"description":"To is the address as given.","type":"string"},"why":{"description":"Why is the reason: not an email address, your own address, this address\ncannot be invited, you already invited this address, daily limit reached,\nmonthly limit reached, or too many in one request.","type":"string"}},"type":"object"},"marketing.BetaInvites":{"properties":{"invites":{"description":"Invites are the reserved invites, each with its message.","items":{"$ref":"#/components/schemas/marketing.BetaInvite"},"type":"array"},"left":{"description":"Left is how many more the member may invite now: the smaller of what is\nleft today and what is left this month.","format":"int64","type":"integer"},"skipped":{"description":"Skipped are the addresses not reserved.","items":{"$ref":"#/components/schemas/marketing.BetaInviteSkip"},"type":"array"}},"type":"object"},"marketing.BetaRequest":{"properties":{"betas":{"description":"Betas are the ids of the unreleased products to add.","items":{"type":"string"},"type":"array"}},"type":"object"},"marketing.CalendarPost":{"properties":{"body":{"description":"Body is the post text. Required.","type":"string"},"channel":{"description":"Channel is the target network: x, facebook, instagram, linkedin, tiktok,\nyoutube or threads. Required — a post must name where it goes.","type":"string"},"createdAt":{"description":"CreatedAt is unix seconds when the post was added, server-assigned and\nnever rewritten.","format":"int64","type":"integer"},"error":{"description":"Error is the exact reason the last publish attempt failed — the honest\nrecord behind a \"failed\" status, never a faked success.","type":"string"},"id":{"description":"ID is the server-assigned post id (\"cal_\" + 128 random bits).","type":"string"},"publishedAt":{"description":"PublishedAt is when the publish succeeded; 0 until it does.","format":"int64","type":"integer"},"scheduledAt":{"description":"ScheduledAt is the unix publish time; 0 leaves the post a draft, and any\nvalue makes it \"scheduled\" for the durable sweep to pick up.","format":"int64","type":"integer"},"status":{"description":"Status is draft, scheduled, published, failed or canceled. Server-owned.","type":"string"},"title":{"description":"Title is the post's internal label, capped at 1024 bytes.","type":"string"},"updatedAt":{"description":"UpdatedAt is unix seconds of the last write, server-assigned. The durable\nsweep writes too — claiming a due post, publishing it and recording a\nfailure each bump it — so this moves without anyone editing the post.","format":"int64","type":"integer"}},"type":"object"},"marketing.Campaign":{"properties":{"budget":{"description":"Budget is what the campaign is allowed to cost, in USD cents. A negative\nvalue is clamped to 0; nothing enforces the ceiling here.","format":"int64","type":"integer"},"channel":{"description":"Channel is the delivery surface: email, sms, social, meta, google or\ntiktok. Empty means email.","type":"string"},"createdAt":{"description":"CreatedAt is unix seconds when the campaign was registered. Server-assigned\nand never rewritten — an update leaves it as it was.","format":"int64","type":"integer"},"id":{"description":"ID is the server-assigned campaign id (\"camp_\" + 128 random bits).","type":"string"},"name":{"description":"Name is the campaign's label. Required, trimmed, capped at 1024 bytes.","type":"string"},"objective":{"description":"Objective is the free-text goal (\"signups\"), capped at 1024 bytes.","type":"string"},"scheduledAt":{"description":"ScheduledAt is the unix send time; 0 means unscheduled. Setting it on a\ncampaign with no explicit status makes that status \"scheduled\".","format":"int64","type":"integer"},"spend":{"description":"Spend is what the campaign has cost so far, in USD cents, clamped to \u003e= 0.\nThe CALLER owns it: no send, ad buy or invoice moves it, so it changes only\nwhen create or update carries a new value. It is summed across the org's\ncampaigns into GET /v1/marketing/summary.","format":"int64","type":"integer"},"status":{"description":"Status is the lifecycle: draft, scheduled, active, paused or completed.\nEmpty means draft.","type":"string"},"updatedAt":{"description":"UpdatedAt is unix seconds of the last write. Server-assigned on create and\non every update or schedule change, and the campaign list is ordered by it,\nnewest first.","format":"int64","type":"integer"}},"type":"object"},"marketing.CampaignList":{"properties":{"data":{"description":"Data is the page; an empty array when the org has no matching campaign.","items":{"$ref":"#/components/schemas/marketing.Campaign"},"type":"array"}},"type":"object"},"marketing.EnrollInput":{"properties":{"address":{"description":"Address is a single recipient, normalized (lower-cased, trimmed) before\nuse. Give this OR audienceId, never both and never neither.","type":"string"},"audienceId":{"description":"AudienceID fans the sequence out over a saved audience, resolved live to\nthe org's mailable customers. Email only.","type":"string"},"channel":{"description":"Channel is the delivery surface; empty means email. An audience resolves\nmailboxes, so an audience enroll must be email.","type":"string"},"id":{"description":"ID is the sequence id from the path.","type":"string"}},"type":"object"},"marketing.EnrollResult":{"properties":{"alreadyEnrolled":{"description":"AlreadyEnrolled is how many this sequence had already taken and were left\nalone.","format":"int64","type":"integer"},"enrolled":{"description":"Enrolled is how many started a walk on this call.","format":"int64","type":"integer"},"enrollmentId":{"description":"EnrollmentID names the walk, and is present ONLY for a single-address\nenroll — a fan-out has many, and reporting one of them would be a lie.","type":"string"},"resolved":{"description":"Resolved is how many addresses the request named — 1 for an address, the\naudience's deliverable count for an audience.","format":"int64","type":"integer"}},"type":"object"},"marketing.Enrollment":{"properties":{"address":{"description":"Address is the normalized (lower-cased, trimmed) recipient.","type":"string"},"channel":{"description":"Channel is the delivery surface the steps go out on.","type":"string"},"currentStep":{"description":"CurrentStep is the index of the step that sends next.","format":"int64","type":"integer"},"enrolledAt":{"description":"EnrolledAt is unix seconds when the contact joined the walk, and orders the\nenrollment list (newest first).","format":"int64","type":"integer"},"id":{"description":"ID is the server-assigned enrollment id (\"enr_\" + 128 random bits).","type":"string"},"nextRunAt":{"description":"NextRunAt is the unix time the current step comes due; 0 once the walk has\nended. It IS the schedule — durable in SQLite, so it survives restarts.","format":"int64","type":"integer"},"sequenceId":{"description":"SequenceID is the sequence being walked.","type":"string"},"status":{"description":"Status is active, completed or canceled.","type":"string"},"updatedAt":{"description":"UpdatedAt is unix seconds of the last move: the drip engine writes it each\ntime it advances the walk a step, completes it or cancels it. Together with\nStatus it says when the walk last did anything, which is how a stalled\nenrollment is told from a finished one.","format":"int64","type":"integer"}},"type":"object"},"marketing.EnrollmentList":{"properties":{"data":{"description":"Data is the page: every contact walking this ONE sequence, in any state —\nactive, completed and canceled walks all appear, since the history of who\nwas reached is the point. An empty array when nobody has been enrolled.","items":{"$ref":"#/components/schemas/marketing.Enrollment"},"type":"array"}},"type":"object"},"marketing.EsignDocument":{"properties":{"externalId":{"description":"ExternalID is the reference the document was made under: the lead's.","type":"string"},"id":{"description":"ID is the document's id in eSign.","format":"int64","type":"integer"},"recipients":{"description":"Recipients are the document's signers.","items":{"$ref":"#/components/schemas/marketing.EsignRecipient"},"type":"array"}},"type":"object"},"marketing.EsignEvent":{"properties":{"event":{"description":"Event is what happened: DOCUMENT_SIGNED (a recipient signed),\nDOCUMENT_COMPLETED, DOCUMENT_REJECTED or DOCUMENT_CANCELLED. Any other event\nchanges nothing.","type":"string"},"payload":{"$ref":"#/components/schemas/marketing.EsignDocument","description":"Payload is the document as it stands after the event."}},"type":"object"},"marketing.EsignRecipient":{"properties":{"signingOrder":{"description":"SigningOrder is the signer's turn: 1 is the investor, 2 the countersigner.","format":"int64","type":"integer"},"signingStatus":{"description":"SigningStatus is NOT_SIGNED, SIGNED or REJECTED.","type":"string"}},"type":"object"},"marketing.Lead":{"properties":{"lead":{"description":"Lead is the reference of what was filed: \"lead_\" and 24 hex characters for a\nlead, \"cand_\" and 24 for a job application. It is random, not a record's id,\nso it says nothing about how many the team has.","type":"string"},"offer":{"description":"Offer says what an application's code did: \"mailed\", a new code went to\nthe address; \"held\", the address already holds one. Absent when no code\nwas given. The code itself is never answered here.","type":"string"},"sent":{"description":"Sent says whether an investor's SAFE went out for signature from Hanzo\neSign: false when the deployment sends none yet, or eSign did not take it, and\nthe investor is filed either way. Absent on every other form.","type":"boolean"},"stage":{"description":"Stage is where the lead stands. Always \"new\" on a fresh lead.","type":"string"}},"type":"object"},"marketing.LeadIn":{"properties":{"address":{"$ref":"#/components/schemas/marketing.Address","description":"Address is where an investor lives, or where the entity they invest\nthrough is: street, city and country required, each at most 200 characters."},"amount":{"description":"Amount is what an investor invests, as a JSON number of whole US dollars: at\nleast 25000, which a smaller amount is refused as \"The minimum investment is\n$25,000.\", and at most 1000000000."},"answers":{"description":"Answers is the application question by question, as the form asked it:\nat most 40, each question clipped at 200 characters and each answer at\n2 KiB. Recorded on the lead as they came; optional.","items":{"$ref":"#/components/schemas/marketing.Answer"},"type":"array"},"campaign":{"$ref":"#/components/schemas/marketing.Tags","description":"Campaign is the utm_* tags of the link the visit arrived on, recorded on\nthe lead. Optional."},"company":{"description":"Company is the person's company. Optional; clipped at 200 characters.","type":"string"},"consent":{"description":"Consent is the applicant ticking \"Keep me posted about roles and news at\nHanzo. Unsubscribe any time.\" Unticked, they hear nothing but the reply to\ntheir application. Read only with Job.","type":"boolean"},"country":{"description":"Country is where the person is. Optional; clipped at 200 characters.","type":"string"},"coupon":{"description":"Coupon is the offer code the visitor's page held: letters, digits, dash and\nunderscore, at most 32. Any other value is recorded as none. Optional.","type":"string"},"department":{"description":"Department is the opening's department. Read only with Job.","type":"string"},"email":{"description":"Email is where sales replies: the person's work email. Required, and it\nmust look like an address. It is not verified.","type":"string"},"entity":{"description":"Entity is the legal name of the entity an investor invests through; empty,\nthey invest in their own name. At most 200 characters. Read only with program\ninvestor, as are Title, Amount, Phone and Address.","type":"string"},"job":{"description":"Job is the opening a careers form applies to, by its id on the careers page\n(senior-backend-engineer). A body naming one is a job application: it is\nfiled as a candidate, never as a lead, so it is offered no call and no code,\nno ad platform hears of it, and the brand's careers mailbox is told instead\nof sales. Name, Email, Role (the opening's title), Country (where the person\nis), Need (what they wrote about themselves), Source and Answers carry over.\nOptional; clipped at 200 characters.","type":"string"},"links":{"description":"Links are https addresses the applicant gave: a portfolio, a profile, a\nsite. At most five, each at most 500 characters; any other value is\ndropped. Read only with Job.","items":{"type":"string"},"type":"array"},"name":{"description":"Name is the person's name. Optional, and clipped at 200 characters, except\nfor an investor, who must give it, in at most 200.","type":"string"},"need":{"description":"Need is what the person wants from sales, in their own words. Optional;\nclipped at 4 KiB.","type":"string"},"phone":{"description":"Phone is an investor's phone number: 3 to 20 digits, an optional leading +,\nand any spaces, dots, dashes or brackets between them. Optional.","type":"string"},"program":{"description":"Program is the program the person applies to: beta, research or partner.\nAny other value is recorded as none. An application is mailed a code for\n50% off the first three months, once per address (offer.go). Optional.\n\"investor\" is an investor's subscription (investor.go): it is mailed no\ncode, it is sent a SAFE, and Name, Amount and Address are required.","type":"string"},"resume":{"description":"Resume is an https address the applicant gave for their resume. Read only\nwith Job; any other value is recorded as none.","type":"string"},"resume_file":{"description":"ResumeFile is the key POST /v1/marketing/leads/resume handed out for the\nresume the applicant uploaded. Any other value is recorded as none. Read\nonly with Job.","type":"string"},"role":{"description":"Role is the person's job title. Optional; clipped at 200 characters.","type":"string"},"size":{"description":"Size is the company's headcount band: 1-49, 50-249, 250-999, 1000-4999 or\n5000+. Any other value is recorded as unstated rather than refused.","type":"string"},"source":{"description":"Source is the page the form was filed from, such as hanzo.ai/contact-sales.\nOptional; clipped at 200 characters.","type":"string"},"title":{"description":"Title is the investor's title at Entity, as the SAFE's signature block\nnames it. At most 200 characters; read only with Entity.","type":"string"},"visit":{"$ref":"#/components/schemas/marketing.Visit","description":"Visit is what the visitor's page knows about the ad click that brought them\nand the consent they gave, so the lead reaches the ad platforms matched to\nthe click and under the visitor's own choice. Optional."}},"type":"object"},"marketing.MailIn":{"properties":{"body":{"description":"Body is the mail as plain text, at most 20000 characters; a blank line\nseparates paragraphs.","type":"string"},"person":{"description":"Person is the CRM person the mail is written to. Empty, the mail goes on the\ntimeline of the person the org holds for the address, if any.","type":"string"},"subject":{"description":"Subject is the subject line, at most 200 characters on one line.","type":"string"},"to":{"description":"To is the one address the mail goes to.","type":"string"}},"type":"object"},"marketing.MailOut":{"properties":{"at":{"description":"At is when it left, RFC 3339 UTC; empty when nothing left.","type":"string"},"sent":{"description":"Sent is false when the address opted out of the org's mail, and nothing left.","type":"boolean"}},"type":"object"},"marketing.PostList":{"properties":{"data":{"description":"Data is the page, ordered by scheduledAt descending — the furthest-out\npost first and unscheduled drafts (scheduledAt 0) last. An empty array\nwhen the org's calendar holds no matching post.","items":{"$ref":"#/components/schemas/marketing.CalendarPost"},"type":"array"}},"type":"object"},"marketing.Promo":{"properties":{"active":{"description":"Active is false for a promo that is no longer offered; an inactive promo\nquotes as ineligible and refuses to redeem.","type":"boolean"},"code":{"description":"Code is the promo id, e.g. \"first1000\".","type":"string"},"createdAt":{"description":"CreatedAt is unix seconds.","format":"int64","type":"integer"},"description":{"description":"Description is the human-readable offer.","type":"string"},"maxRedemptions":{"description":"MaxRedemptions is the hard fleet-wide cap; the redemption past it is\ndeclined.","format":"int64","type":"integer"},"percentOff":{"description":"PercentOff is the discount applied to ONE month's list price.","format":"int64","type":"integer"},"plans":{"description":"Plans is the csv of eligible plan ids (\"dev,max-5x,max-20x,team\").","type":"string"},"teamSeatCap":{"description":"TeamSeatCap is how many Team seats bill at the promo rate; seats beyond it\nbill at list.","format":"int64","type":"integer"}},"type":"object"},"marketing.PromoList":{"properties":{"data":{"description":"Data is every promo in the deployment, oldest first, each with its live\ncounters. The list is fleet-wide rather than per-org. It is normally EMPTY:\nnothing seeds a promo, and the migration purges the one that once shipped\nby accident.","items":{"$ref":"#/components/schemas/marketing.PromoStatus"},"type":"array"}},"type":"object"},"marketing.PromoStatus":{"properties":{"promo":{"$ref":"#/components/schemas/marketing.Promo","description":"Promo is the offer itself. It is fleet-wide, identical for every org — only\nthe two counters beside it move."},"redeemed":{"description":"Redeemed is how many orgs have taken it, Remaining how many are left under\nthe fleet-wide cap.","format":"int64","type":"integer"},"remaining":{"description":"Remaining is MaxRedemptions minus Redeemed, floored at 0. At 0 the next\nredeem is declined, and a quote reports ineligible rather than pricing an\noffer that cannot be taken.","format":"int64","type":"integer"}},"type":"object"},"marketing.Quote":{"properties":{"chargeCents":{"description":"ChargeCents is what month one costs after the discount, in USD cents,\ntotalled over the seats quoted. On team that is a multiple of the seat\ncount, so it is not ListCents minus DiscountCents.","format":"int64","type":"integer"},"code":{"description":"Code is the promo that was priced, as stored.","type":"string"},"discountCents":{"description":"DiscountCents is what the promo takes off month one, in USD cents. The\npromo rate reaches at most TeamSeatCap seats; seats past the cap bill at\nfull list and add nothing here. It is arithmetic only — quoting credits\nnothing, counts nothing and reserves nothing.","format":"int64","type":"integer"},"eligible":{"description":"Eligible says whether a redeem would be accepted right now; Reason says\nwhy not when it would not.","type":"boolean"},"listCents":{"description":"ListCents is the undiscounted month price in USD cents: PER SEAT on team,\nthe whole month on pro and max, 0 for a plan with no list price.","format":"int64","type":"integer"},"plan":{"description":"Plan is the tier priced, lower-cased and trimmed: pro, max or team.\nUnlike a redemption's plan this one comes from the REQUEST — quoting has no\nside effects, so it will happily price a plan the caller does not hold.","type":"string"},"reason":{"description":"Reason is why Eligible is false, drawn from: \"promo redemption is closed\"\n(the subsystem is off, which is how it ships), \"promo redemption cap\nreached\", \"promo is not active\", \"plan is free or unknown; nothing to\ndiscount\", \"promo does not cover plan \u003cplan\u003e\". Absent when Eligible is true.","type":"string"},"remaining":{"description":"Remaining is how many redemptions are left under the fleet-wide cap.","format":"int64","type":"integer"},"seats":{"description":"Seats is the seat count priced; a request of 0 or less was read as 1. It\nonly bites on team, the one per-seat plan — pro and max are single-seat and\nignore it.","format":"int64","type":"integer"}},"type":"object"},"marketing.RedeemInput":{"properties":{"code":{"description":"Code is the promo code from the path.","type":"string"},"instrument":{"description":"Instrument identifies the payment method. It is the anti-farming key: one\nredemption per instrument, fleet-wide, and it is REQUIRED — an absent\ninstrument is refused, never waved through.","type":"string"}},"type":"object"},"marketing.RedeemResult":{"properties":{"alreadyRedeemed":{"description":"AlreadyRedeemed is true when this org had already taken the promo and the\ncall was an idempotent replay.","type":"boolean"},"chargeCents":{"description":"ChargeCents is what month one costs after the discount, DiscountCents the\ndiscount that produced it. Both are quoted figures against the org's\nderived plan — NOTHING WAS CREDITED and no wallet moved.","format":"int64","type":"integer"},"discountCents":{"description":"DiscountCents is the discount claimed for month one, in USD cents, at the\nsingle-seat floor. It is the same figure recorded on the Redemption, and it\nis evidence an admin may later grant against — not a balance.","format":"int64","type":"integer"},"redemption":{"$ref":"#/components/schemas/marketing.Redemption","description":"Redemption is the row that was recorded — the org's claim on this promo,\nwith the server-derived plan and seat count. On a replay it is the ORIGINAL\nrow, so its redeemedAt is when the org first took the promo, not now."}},"type":"object"},"marketing.Redemption":{"properties":{"code":{"description":"Code is the promo redeemed.","type":"string"},"discountCents":{"description":"DiscountCents is the month-one discount this redemption CLAIMS, in USD\ncents. It is a recorded figure, NOT a balance: nothing was credited and no\nwallet moved. An admin granting against this claim is what would make it\nmoney, and that decision happens on the admin surface, not here.","format":"int64","type":"integer"},"plan":{"description":"Plan is the tier redeemed against: pro, max or team. It is DERIVED from the\norg's live ACTIVE/TRIALING subscription, never read from the request, so it\nis what the org actually holds rather than what it claimed.","type":"string"},"redeemedAt":{"description":"RedeemedAt is unix seconds.","format":"int64","type":"integer"},"seats":{"description":"Seats is the seat count the claim was priced at, and it is ALWAYS 1. No\nserver-side authority on this surface answers \"how many seats\", and the\ncaller's own number is exactly the input that once inflated these claims,\nso a redemption records the single-seat floor and an admin resolves the\nreal count against subscription data at grant time.","format":"int64","type":"integer"}},"type":"object"},"marketing.ResumeForm":{"properties":{"expiry":{"description":"Expiry is how long the form is good for, in seconds.","format":"int64","type":"integer"},"fields":{"additionalProperties":{"type":"string"},"description":"Fields go in the form ahead of the file, exactly as given.","type":"object"},"key":{"description":"Key is the object the file becomes, to name as the application's resume_file.","type":"string"},"url":{"description":"URL is where the form posts.","type":"string"}},"type":"object"},"marketing.ResumeIn":{"properties":{"name":{"description":"Name is the file's name; its extension must be .pdf, .doc or .docx.","type":"string"},"size":{"description":"Size is the file's size in bytes, at most 10 MB.","format":"int64","type":"integer"},"type":{"description":"Type is the file's content type, which must be that extension's.","type":"string"}},"type":"object"},"marketing.ScheduleInput":{"properties":{"id":{"description":"ID is the campaign id from the path.","type":"string"},"scheduledAt":{"description":"ScheduledAt is the unix send time. 0 clears the schedule.","format":"int64","type":"integer"}},"type":"object"},"marketing.Sequence":{"properties":{"createdAt":{"description":"CreatedAt is unix seconds when the sequence was registered, server-assigned\nand never rewritten.","format":"int64","type":"integer"},"id":{"description":"ID is the server-assigned sequence id (\"seq_\" + 128 random bits).","type":"string"},"name":{"description":"Name is the sequence's label. Required, trimmed, capped at 1024 bytes.","type":"string"},"status":{"description":"Status is the lifecycle: draft, active or archived. Empty means draft, and\nONLY an active sequence accepts enrollments.","type":"string"},"updatedAt":{"description":"UpdatedAt is unix seconds of the last status flip, server-assigned, and the\nkey the sequence list is ordered by (newest first). Adding a step or\nenrolling a contact does NOT touch it — only draft/active/archived does —\nso it tracks activation rather than activity.","format":"int64","type":"integer"}},"type":"object"},"marketing.SequenceList":{"properties":{"data":{"description":"Data is the page; an empty array when the org has no sequence.","items":{"$ref":"#/components/schemas/marketing.Sequence"},"type":"array"}},"type":"object"},"marketing.SequenceStatus":{"properties":{"id":{"description":"ID is the sequence id from the path.","type":"string"},"status":{"description":"Status is draft, active or archived. Required; there is no default here,\nunlike on create. Only an active sequence accepts enrollments.","type":"string"}},"type":"object"},"marketing.SequenceView":{"properties":{"sequence":{"$ref":"#/components/schemas/marketing.Sequence","description":"Sequence is the definition itself — the same record create and the list\nreturn. Its status is the one that decides whether enroll is accepted."},"steps":{"description":"Steps are in send order (idx ascending); empty for a sequence with no\nmessages yet, which enrolls fine and completes immediately.","items":{"$ref":"#/components/schemas/marketing.Step"},"type":"array"}},"type":"object"},"marketing.Signing":{"properties":{"status":{"description":"Status is where the SAFE stands: submitted, investor signed, countersigned,\ncompleted, declined or voided. Empty when the document is no investor's of\nthis deployment.","type":"string"}},"type":"object"},"marketing.Step":{"properties":{"body":{"description":"Body is the message text. Required. The signed one-click unsubscribe link\nis appended to it at send time, and in an HTML body each \u003ca\u003e to an http(s)\nURL is sent pointing at GET /v1/marketing/click, which counts the click and\nredirects to the URL written here.","type":"string"},"createdAt":{"description":"CreatedAt is unix seconds, server-assigned.","format":"int64","type":"integer"},"delaySeconds":{"description":"DelaySeconds is how long after the previous step this one sends (after\nenrollment, for step 0).","format":"int64","type":"integer"},"id":{"description":"ID is the server-assigned step id (\"step_\" + 128 random bits).","type":"string"},"idx":{"description":"Idx is the step's 0-based position, assigned by appending: a new step\nalways lands after the last one.","format":"int64","type":"integer"},"sequenceId":{"description":"SequenceID is the sequence this step belongs to.","type":"string"},"subject":{"description":"Subject is the email subject line, capped at 1024 bytes.","type":"string"}},"type":"object"},"marketing.StepInput":{"properties":{"body":{"description":"Body is the message text. Required.","type":"string"},"delaySeconds":{"description":"DelaySeconds is how long after the previous step this one sends (after\nenrollment, for the first step). Must be \u003e= 0.","format":"int64","type":"integer"},"id":{"description":"SequenceID is the sequence id from the path (the route's :id).","type":"string"},"subject":{"description":"Subject is the email subject line, capped at 1024 bytes.","type":"string"}},"type":"object"},"marketing.StepList":{"properties":{"data":{"description":"Data is every step of the sequence, idx ascending — the order they send\nin. It is not paged: a sequence's steps are a handful, and a partial list\nwould misstate the drip. An empty array for a sequence with no messages\nyet, which enrolls fine and completes immediately.","items":{"$ref":"#/components/schemas/marketing.Step"},"type":"array"}},"type":"object"},"marketing.Summary":{"properties":{"active":{"description":"Active is how many of them sit in the \"active\" state exactly. A scheduled\nor paused campaign counts in Campaigns and not here, so Active is never a\nshare of anything but the whole.","format":"int64","type":"integer"},"budget":{"description":"Budget is every campaign's budget summed, in USD cents.","format":"int64","type":"integer"},"campaigns":{"description":"Campaigns is how many campaigns the org has, counted in every lifecycle\nstate including draft and completed.","format":"int64","type":"integer"},"spend":{"description":"Spend is every campaign's spend summed, in USD cents. It adds up figures\ncallers wrote on the campaigns themselves — this app meters no delivery\nagainst a budget — so it is a reported total, not an observed one.","format":"int64","type":"integer"}},"type":"object"},"marketing.Suppression":{"properties":{"address":{"description":"Address is the recipient, normalized (lower-cased, trimmed) so an opt-out\ncannot be slipped past on a case or whitespace difference. Required. An\nentry \"@example.com\" opts out everyone at that domain, a company's\nunsubscribe; a free mail provider's domain is refused.","type":"string"},"channel":{"description":"Channel is the surface opted out of: email, sms, social, meta, google or\ntiktok. Empty means email. Opting out of one leaves the others reachable.","type":"string"},"createdAt":{"description":"CreatedAt is unix seconds, server-assigned.","format":"int64","type":"integer"},"reason":{"description":"Reason is a free-text note, capped at 1024 bytes. The public one-click\nendpoint records \"one-click unsubscribe\".","type":"string"}},"type":"object"},"marketing.SuppressionCheck":{"properties":{"reason":{"description":"Reason is what the matching entry was recorded with: \"one-click\nunsubscribe\", a bounce, a complaint, an admin's note. Absent when not\nsuppressed.","type":"string"},"scope":{"description":"Scope is the list that matched: address (the org's, for the address),\ndomain (the org's, for the address's company) or platform (the blocklist,\nwhich every org's gate reads). Absent when not suppressed.","type":"string"},"suppressed":{"description":"Suppressed is true when the send gate refuses the address on the channel.","type":"boolean"}},"type":"object"},"marketing.SuppressionList":{"properties":{"data":{"description":"Data is the page: every (channel, address) this org's send gate refuses,\nnewest opt-out first. Absence from it is not permission to mail someone —\nit only means no opt-out was recorded on that channel.","items":{"$ref":"#/components/schemas/marketing.Suppression"},"type":"array"}},"type":"object"},"marketing.Tags":{"properties":{"utm_campaign":{"description":"Name is utm_campaign: the campaign's own name.","type":"string"},"utm_content":{"description":"Content is utm_content: which link of several in one placement.","type":"string"},"utm_medium":{"description":"Medium is utm_medium: the kind of placement, such as cpc or email.","type":"string"},"utm_source":{"description":"Source is utm_source: where the link was placed, such as google.","type":"string"},"utm_term":{"description":"Term is utm_term: the paid search term.","type":"string"}},"type":"object"},"marketing.Unsubscribed":{"properties":{"address":{"description":"Address is the recipient now opted out, normalized (lower-cased, trimmed)\nto the form the send gate matches on — so it can differ in case from the\naddress the link carried.","type":"string"},"channel":{"description":"Channel is the ONE surface opted out of: email, sms, social, meta, google\nor tiktok. The other channels are untouched, and so is this address in\nevery other org.","type":"string"},"company":{"description":"Company is the domain opted out whole, when the link asked for it.","type":"string"},"offer":{"description":"Offer is the domain the reader may opt out whole by asking again with\ncompany=true: the company's own domain, never a free mail provider's. Absent\nwhen the company is already out, or for free mail.","type":"string"},"unsubscribed":{"description":"Unsubscribed is always true here: the opt-out is idempotent, so a second\nclick on the same link confirms the same thing rather than reporting\nnothing changed. A refused token never reaches this shape — it is a 403.","type":"boolean"}},"type":"object"},"marketing.Visit":{"properties":{"cid":{"description":"Cid is the Google Analytics client id, the last two fields of _ga.","type":"string"},"clicked":{"description":"Clicked is when the page captured the click, in unix seconds.","format":"int64","type":"integer"},"consent":{"description":"Consent is the Cookie Preferences the visitor granted, comma separated:\nany of analytics, marketing and ads. Empty is a visitor who refused them\nall, which is a choice; absent is one who stated none. It counts only from a\nbrowser, and a browser that sends GPC or DNT has allowed nothing.","type":"string"},"fbc":{"description":"Fbc is Meta's click cookie, fb.1.\u003cms\u003e.\u003cfbclid\u003e.","type":"string"},"fbclid":{"description":"Fbclid is the Meta click id the visitor arrived with.","type":"string"},"fbp":{"description":"Fbp is Meta's browser cookie, fb.1.\u003cms\u003e.\u003crandom\u003e.","type":"string"},"gbraid":{"description":"Gbraid is the Google Ads click id for an iOS app click.","type":"string"},"gclid":{"description":"Gclid is the Google Ads click id the visitor arrived with.","type":"string"},"tags":{"description":"Tags is which of the page's ad tags already saw this lead: ga, meta.","type":"string"},"url":{"description":"URL is the page the form was filed from, in full.","type":"string"},"userAgent":{"description":"UserAgent is the visitor's browser, as navigator.userAgent reads.","type":"string"},"wbraid":{"description":"Wbraid is the Google Ads click id for an iOS web click.","type":"string"}},"type":"object"},"marketplace.Delivery":{"properties":{"at":{"description":"At is when, unix seconds.","format":"int64","type":"integer"},"hash":{"description":"Hash commits to what was delivered: the seller's own 32-byte hash, or the\nSHA-256 of the note and URL. It is the escrow's delivery hash on chain.","type":"string"},"note":{"description":"Note says what was delivered.","type":"string"},"url":{"description":"URL is where it is, https.","type":"string"}},"type":"object"},"marketplace.Dispute":{"properties":{"at":{"description":"At is when, unix seconds.","format":"int64","type":"integer"},"by":{"description":"By is the org that disputed.","type":"string"},"contested":{"description":"Contested is the clock's own dispute: the payment stopped clearing when the\nreview window closed. A party's dispute never carries it, whatever the party\nis named.","type":"boolean"},"reason":{"description":"Reason is the disputing party's words.","type":"string"}},"type":"object"},"marketplace.Earnings":{"properties":{"byRail":{"additionalProperties":{},"description":"ByRail sums them by the rail that moved them.","type":"object"},"currency":{"description":"Currency is USD.","type":"string"},"gross":{"description":"Gross is the sum of every payment to the org, exact USD."},"partial":{"description":"Partial is true when the year held more than one read sums.","type":"boolean"},"payments":{"description":"Payments is how many.","format":"int64","type":"integer"},"year":{"description":"Year is the calendar year (UTC).","format":"int64","type":"integer"}},"type":"object"},"marketplace.Escrow":{"properties":{"contract":{"description":"Contract is the contract the money moves through: the token the x402\nauthorization transfers, or the escrow on chain.","type":"string"},"network":{"description":"Network is the CAIP-2 network the payment is signed for.","type":"string"},"payTo":{"description":"PayTo is the seller's payout address.","type":"string"},"rail":{"description":"Rail is x402 — the buyer's balance, settled at release — or chain, the Lux\nescrow contract.","type":"string"},"txHash":{"description":"TxHash is the transaction that paid the seller, once one did: the chain's\nhash, or the x402 settlement id on the ledger.","type":"string"}},"type":"object"},"marketplace.Facets":{"properties":{"category":{"additionalProperties":{"format":"int64","type":"integer"},"description":"Category counts listings in each category; an uncategorized one is not\ncounted.","type":"object"},"kind":{"additionalProperties":{"format":"int64","type":"integer"},"description":"Kind counts listings of each kind.","type":"object"},"price":{"additionalProperties":{"format":"int64","type":"integer"},"description":"Price counts free and priced listings.","type":"object"},"rating":{"additionalProperties":{"format":"int64","type":"integer"},"description":"Rating counts listings by their rounded rating, \"1\" to \"5\", and those with\nno rating yet as \"unrated\".","type":"object"}},"type":"object"},"marketplace.Feedback":{"properties":{"about":{"description":"About is the other party of the job, the org it is about.","type":"string"},"at":{"description":"At is when, unix seconds.","format":"int64","type":"integer"},"comment":{"description":"Comment is the party's words, at most 4096 characters.","type":"string"},"from":{"description":"From is the org that gave it.","type":"string"},"job":{"description":"Job is the job it is about.","type":"string"},"listing":{"description":"Listing is the listing the job was hired through; empty for a direct offer.","type":"string"},"rating":{"description":"Rating is 1 to 5 stars.","format":"int64","type":"integer"}},"type":"object"},"marketplace.Job":{"properties":{"amount":{"description":"Amount is what the job pays, exact USD."},"attempt":{"description":"Attempt is the buyer's own key for the hire that made the job, when it sent\none.","type":"string"},"brief":{"description":"Brief is what the buyer asked for.","type":"string"},"buyerOrg":{"description":"BuyerOrg is the org that pays.","type":"string"},"category":{"description":"Category is what the payment is for — service, goods, transfer or royalty —\nas the buyer declared it and the seller accepted it. It is what the\neconomic event says.","type":"string"},"clearance":{"description":"Clearance is principal's latest decision that the buyer may pay the seller\nthis amount — asked when the job was quoted, again when it was funded, and\nagain when it was released: GET /v1/principal/clearance/{id}.","type":"string"},"createdAt":{"description":"CreatedAt is when the job was quoted, unix seconds.","format":"int64","type":"integer"},"currency":{"description":"Currency labels Amount: USD.","type":"string"},"deadline":{"description":"Deadline is when delivery must land by, unix seconds.","format":"int64","type":"integer"},"delivery":{"$ref":"#/components/schemas/marketplace.Delivery","description":"Delivery is what the seller delivered, once it has."},"dispute":{"$ref":"#/components/schemas/marketplace.Dispute","description":"Dispute is why the job was stopped, once it was."},"ending":{"description":"Ending is the unpaid ending the job was given — declined, cancelled or\nrefunded — while the rail returns the amount it set aside. It takes no other\nstep meanwhile, and Status becomes Ending once the money is back.","type":"string"},"escrow":{"$ref":"#/components/schemas/marketplace.Escrow","description":"Escrow is how the job is paid."},"history":{"description":"History is every step the job took, oldest first.","items":{"$ref":"#/components/schemas/marketplace.Step"},"type":"array"},"id":{"description":"ID is the job, \"job_\"-prefixed.","type":"string"},"listing":{"description":"Listing is the listing it was hired through; empty for a direct offer.","type":"string"},"performed":{"description":"Performed is where the work is performed, ISO 3166-1 alpha-2, when said.","type":"string"},"review":{"description":"Review is how many seconds after delivery the buyer has to release or\ndispute before the job releases itself.","format":"int64","type":"integer"},"sellerOrg":{"description":"SellerOrg is the org that does the work and is paid.","type":"string"},"status":{"description":"Status is where the job stands: quoted or funding, which only its buyer\nsees, then open, accepted, delivered, released, disputed, declined,\ncancelled or refunded.","type":"string"},"title":{"description":"Title names the work: the listing's title, or the offer's own.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it last moved, unix seconds.","format":"int64","type":"integer"}},"type":"object"},"marketplace.JobCounts":{"properties":{"completed":{"description":"Completed is released jobs.","format":"int64","type":"integer"},"disputed":{"description":"Disputed is jobs ever disputed.","format":"int64","type":"integer"}},"type":"object"},"marketplace.Links":{"properties":{"cli":{"description":"CLI is the hanzo command that buys it.","type":"string"},"docs":{"description":"Docs is the listing's documentation, when the seller named one.","type":"string"},"mcp":{"$ref":"#/components/schemas/marketplace.MCPRef","description":"MCP is the MCP tool and operation that buys it."}},"type":"object"},"marketplace.Listing":{"properties":{"category":{"description":"Category groups the listing in the shop window. Free text — no vocabulary,\nnothing validates it — and unlike Description it is silently cut to 4096\nbytes rather than refused. Empty means ungrouped.","type":"string"},"createdAt":{"description":"CreatedAt is when the listing was published, in Unix SECONDS, minted at\ninsert. Every listing read orders by it descending, so it is the shop's\nordering key as well as its age.","format":"int64","type":"integer"},"currency":{"description":"Currency is the ISO 4217 code Price is quoted in; Create defaults it to \"USD\"\nwhen the publisher names none. It is a LABEL that travels to the shop window:\npublish parses Price with money.ParseUSD and the x402 terms carry no\ncurrency, so another code here changes what is displayed, not what is charged.","type":"string"},"description":{"description":"Description is the long copy. Publish REFUSES one past 4096 bytes rather\nthan truncating it, so what is stored is what was sent; empty is allowed.","type":"string"},"docs":{"description":"Docs is where the listing's documentation lives: an https URL, or a path on\ndocs.hanzo.ai. Empty when the seller named none.","type":"string"},"id":{"description":"ID is the listing's id, minted here as \"lst_\" + 16 hex characters. A\npublisher cannot choose it: Create overwrites whatever arrives. It is unique\nwithin PublisherOrg (the primary key is the pair), and it is the path segment\nDELETE /v1/marketplace/listings/:id takes.","type":"string"},"kind":{"description":"Kind is what the listing sells: agent, persona, app, skill, mcp or tool.\nListings published before kinds existed sold tools, and read as tool.","type":"string"},"price":{"description":"Price is the exact price, 18 decimal places of USD: per call for a tool,\nthe price a job is offered at for an agent. Zero is free."},"public":{"description":"Public is whether other orgs can discover the listing. It also decides\nENFORCEMENT: only public rows reach the price table, so a private listing\nwith a price charges nobody. False leaves the row visible to its publisher\nalone.","type":"boolean"},"publisherOrg":{"description":"PublisherOrg is the org that published the listing, taken from the validated\nprincipal and never off the wire. It is also the PAYEE org — Recipient is\nresolved inside it — and the isolation key: a publisher reads and deletes\nonly rows carrying its own org.","type":"string"},"recipient":{"description":"Recipient is the seller's payout WALLET id in PublisherOrg: the wallet x402\npays for a call or a job bought through this listing.","type":"string"},"ref":{"description":"Ref is the id the thing's owning app knows it by, resolved when the listing\nwas published — the agent id for an agent named by its name. A tool's is the\nx402 resource a dispatch of it is priced by: the source it resolves from and\nits name, so a price follows the tool that runs and not a name another org's\nown row may share.","type":"string"},"title":{"description":"Title is the shop-window name, required and refused past 200 bytes. It is\nwhat discovery paints over the tool's registry name.","type":"string"},"tool":{"description":"Tool names the thing sold, as the seller named it: the agent, app, skill or\nMCP server's name or id, or the tool's registry name. It was proved the\nseller's own when the listing was published. For a tool it is what install\nswitches on.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the listing was last edited, unix seconds; its creation\nwhen it never was.","format":"int64","type":"integer"}},"type":"object"},"marketplace.MCPRef":{"properties":{"op":{"description":"Op is the operation within it.","type":"string"},"tool":{"description":"Tool is the MCP tool: marketplace.","type":"string"}},"type":"object"},"marketplace.Onboarding":{"properties":{"credentials":{"description":"Credentials are the TaxPrincipalCredentials signed for the org's agents,\nnewest first.","items":{"$ref":"#/components/schemas/marketplace.Statement"},"type":"array"},"earnings":{"$ref":"#/components/schemas/marketplace.Earnings","description":"Earnings is what the org was paid in Year, from the economic events the rails\nstated."},"entity":{"description":"Entity is the legal entity's formation stage (KYB) — \"company\" once formed\n— or empty when the org began none.","type":"string"},"identity":{"description":"Identity is the founders' identity verification (KYC): verified, pending,\nfailed or none.","type":"string"},"missing":{"description":"Missing names what the org still owes before it is paid without a hitch:\nidentity, sanctions, tax_form, tax_invalid or payout.","items":{"type":"string"},"type":"array"},"org":{"description":"Org is the seller org.","type":"string"},"payout":{"$ref":"#/components/schemas/marketplace.Payout","description":"Payout is the wallet the org proved it is paid into."},"ready":{"description":"Ready is true when nothing is missing.","type":"boolean"},"received":{"description":"Received are the 1099s payers furnished the org for Year.","items":{"$ref":"#/components/schemas/marketplace.Received"},"type":"array"},"sanctions":{"description":"Sanctions is the org's own screening: clear, review, blocked, unscreened or\nunavailable, and why in words.","type":"string"},"sanctionsReason":{"description":"SanctionsReason says why Sanctions is what it is.","type":"string"},"sources":{"description":"Sources names each owning app asked, and whether it answered: ok, absent\n(not run by this deployment) or failed.","items":{"$ref":"#/components/schemas/marketplace.Source"},"type":"array"},"tax":{"$ref":"#/components/schemas/marketplace.TaxStatus","description":"Tax is the org's own tax form, when it has one."}},"type":"object"},"marketplace.Payout":{"properties":{"address":{"description":"Address is its address, recovered from the signature that proved it.","type":"string"},"bound":{"description":"Bound is true once a signature proved it.","type":"boolean"},"boundAt":{"description":"BoundAt is when, unix seconds.","format":"int64","type":"integer"},"wallet":{"description":"Wallet is the wallet id, in the seller's org.","type":"string"}},"type":"object"},"marketplace.PayoutChallenge":{"properties":{"address":{"description":"Address is its address, which the signature must recover to.","type":"string"},"digest":{"description":"Digest is the EIP-191 hash of Message, 0x hex: what POST\n/v1/wallet/{id}/sign signs, for a wallet the platform holds.","type":"string"},"expires":{"description":"Expires is when the challenge may no longer be signed, unix seconds.","format":"int64","type":"integer"},"message":{"description":"Message is the text to sign with the wallet (EIP-191 personal_sign).","type":"string"},"wallet":{"description":"Wallet is the wallet to prove.","type":"string"}},"type":"object"},"marketplace.Price":{"properties":{"amount":{"description":"Amount is what ONE call costs, EXACTLY: an 18-decimal USD value, so a\nper-call price of $0.0025 is $0.0025 and not a cent-floored zero. Cents\ncannot hold a per-token price, and a tool plane is where per-token prices\nlive."},"currency":{"description":"Currency is the ISO 4217 code, e.g. \"USD\". Empty means USD.","type":"string"},"recipient":{"description":"Recipient is the payout wallet ref the marketplace seller is paid at.","type":"string"}},"type":"object"},"marketplace.Received":{"properties":{"corrected":{"description":"Corrected is true for a statement that corrects an earlier one.","type":"boolean"},"furnished":{"description":"Furnished is when it was delivered, unix seconds.","format":"int64","type":"integer"},"id":{"description":"ID is the form id the payer issued it under.","type":"string"},"kind":{"description":"Kind is 1099-NEC or 1099-MISC.","type":"string"},"payer":{"description":"Payer is the org that furnished it.","type":"string"},"superseded":{"description":"Superseded is true for one a later correction replaced.","type":"boolean"},"year":{"description":"Year is the calendar year of the payments.","format":"int64","type":"integer"}},"type":"object"},"marketplace.Reputation":{"properties":{"installs":{"description":"Installs is how many orgs installed a tool listing's tool.","format":"int64","type":"integer"},"jobs":{"$ref":"#/components/schemas/marketplace.JobCounts","description":"Jobs counts the jobs released, and those that were ever disputed."},"rating":{"description":"Rating is the mean stars buyers gave, 1 to 5 to one decimal; null until the\nfirst review.","format":"double","type":"number"},"reviews":{"description":"Reviews is how many buyers rated.","format":"int64","type":"integer"}},"type":"object"},"marketplace.Seller":{"properties":{"documented":{"description":"Documented is true while the seller's tax form is certified and valid —\nwhat its agents' TaxPrincipalCredentials rest on. False as well when that\ncould not be asked just now.","type":"boolean"},"org":{"description":"Org is the seller org.","type":"string"},"reputation":{"$ref":"#/components/schemas/marketplace.Reputation","description":"Reputation is what buyers made of the seller, across its listings."}},"type":"object"},"marketplace.Shop":{"properties":{"facets":{"$ref":"#/components/schemas/marketplace.Facets","description":"Facets counts the matches by kind, category, price and rating, each\ncounted as if its own filter were not applied."},"listings":{"description":"Listings is this page, newest first.","items":{"$ref":"#/components/schemas/marketplace.ShopListing"},"type":"array"},"total":{"description":"Total is how many listings the search matched, past this page.","format":"int64","type":"integer"}},"type":"object"},"marketplace.ShopListing":{"properties":{"category":{"description":"Category groups it; empty is ungrouped.","type":"string"},"createdAt":{"description":"CreatedAt is when it was published, unix seconds.","format":"int64","type":"integer"},"currency":{"description":"Currency labels Price.","type":"string"},"description":{"description":"Description is the long copy.","type":"string"},"docs":{"description":"Docs is where its documentation lives, when the seller said.","type":"string"},"id":{"description":"ID is the listing.","type":"string"},"kind":{"description":"Kind is what it sells: agent, persona, app, skill, mcp or tool.","type":"string"},"links":{"$ref":"#/components/schemas/marketplace.Links","description":"Links are the ways to act on it."},"price":{"description":"Price is the exact USD price — per call for a tool, per job otherwise; \"0\"\nis free."},"public":{"description":"Public is always true here.","type":"boolean"},"publisherOrg":{"description":"PublisherOrg is the org that sells it.","type":"string"},"reputation":{"$ref":"#/components/schemas/marketplace.Reputation","description":"Reputation is what buyers made of this listing."},"seller":{"$ref":"#/components/schemas/marketplace.Seller","description":"Seller is what anyone may know about the seller."},"title":{"description":"Title is the shop-window name.","type":"string"},"tool":{"description":"Tool names the thing sold, as the seller named it.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it was last edited, unix seconds.","format":"int64","type":"integer"}},"type":"object"},"marketplace.Source":{"properties":{"app":{"description":"App is the app.","type":"string"},"status":{"description":"Status is ok, absent or failed.","type":"string"}},"type":"object"},"marketplace.Statement":{"properties":{"agent":{"description":"Agent is the agent it is about.","type":"string"},"expires":{"description":"Expires is when it stops standing, unix seconds; zero for a W-9, which\nstands until the form changes.","format":"int64","type":"integer"},"form":{"description":"Form is the class of tax form it rests on: w9, w8ben or w8bene.","type":"string"},"id":{"description":"ID is the statement's jti.","type":"string"},"issued":{"description":"Issued is when it was signed, unix seconds.","format":"int64","type":"integer"},"jws":{"description":"JWS is the signed statement itself — the credential an agent presents —\nanswered only to the org it is about.","type":"string"},"kind":{"description":"Kind is what it states: tax.","type":"string"},"org":{"description":"Org is the principal the agent answers to.","type":"string"},"revoked":{"description":"Revoked is when it was withdrawn, unix seconds; zero while it stands.","format":"int64","type":"integer"},"status":{"description":"Status is live, expired or revoked.","type":"string"}},"type":"object"},"marketplace.Step":{"properties":{"at":{"description":"At is when, unix seconds.","format":"int64","type":"integer"},"by":{"description":"By is the org whose act it was, or \"marketplace\" for a clock that ran out.","type":"string"},"status":{"description":"Status is the state the job entered.","type":"string"}},"type":"object"},"marketplace.TaxStatus":{"properties":{"certified":{"description":"Certified is whether its signature covers the form as it stands.","type":"boolean"},"expires":{"description":"Expires is when a W-8 lapses, unix seconds; a W-9 does not.","format":"int64","type":"integer"},"form":{"description":"Form is w9, w8ben or w8bene.","type":"string"},"valid":{"description":"Valid is whether it is complete and unexpired.","type":"boolean"}},"type":"object"},"marketplace.declineIn":{"properties":{"id":{"description":"ID is the job, from the path.","type":"string"},"reason":{"description":"Reason is the seller's words to the buyer, at most 4096 characters.","type":"string"}},"type":"object"},"marketplace.deliverIn":{"properties":{"hash":{"description":"Hash is the seller's own commitment to what was delivered, 32 bytes as 0x\nhex; the SHA-256 of the note and URL when empty.","type":"string"},"id":{"description":"ID is the job, from the path.","type":"string"},"note":{"description":"Note says what was delivered. Required, at most 4096 characters.","type":"string"},"url":{"description":"URL is where it is, https.","type":"string"}},"type":"object"},"marketplace.disputeIn":{"properties":{"id":{"description":"ID is the job, from the path.","type":"string"},"reason":{"description":"Reason is the disputing party's words. Required, at most 4096 characters.","type":"string"}},"type":"object"},"marketplace.feedbackIn":{"properties":{"comment":{"description":"Comment is the party's words, at most 4096 characters.","type":"string"},"id":{"description":"ID is the job, from the path.","type":"string"},"rating":{"description":"Rating is 1 to 5 stars. Required.","format":"int64","type":"integer"}},"type":"object"},"marketplace.hireIn":{"properties":{"amount":{"description":"Amount is what the job pays, U.S. dollars to the cent: \"250.00\".","type":"string"},"attempt":{"description":"Attempt is the buyer's own key for this hire: chosen once, when the hire\nstarts — a random id, 1 to 128 letters, digits, dots, colons, dashes or\nunderscores — and sent with every request it makes, the quote and the\npayment alike, with the rest of the request unchanged. The same attempt\nanswers the same job: the quote's terms to sign until it is paid, the job\nonce it opened, whatever it has come to since. Another request under an\nattempt already used is refused (422): a new hire is a new attempt.","type":"string"},"brief":{"description":"Brief is what the buyer asks for, and what delivered looks like. Required,\nat most 4096 characters.","type":"string"},"category":{"description":"Category is what the payment is for: service (the default), goods,\ntransfer or royalty.","type":"string"},"deadline":{"description":"Deadline is when delivery must land by, unix seconds. Without one, it is\nthe latest the payment leaves room for: its expiry, less the review window,\nfourteen days for a ruling on a dispute, and a day for the clock.","format":"int64","type":"integer"},"listing":{"description":"Listing is the public listing the job is hired through. Empty for a direct\noffer, which names Seller instead.","type":"string"},"payment":{"description":"Payment is the buyer's signed x402 authorization for the job — the value\nPAYMENT-SIGNATURE carries, for a caller that sends no headers of its own,\nover MCP or the command line. The header wins when both are sent.","type":"string"},"performed":{"description":"Performed is where the work is performed, ISO 3166-1 alpha-2. It decides\nwhether a foreign seller's pay is U.S.-source.","type":"string"},"rail":{"description":"Rail is x402 (the default) or chain.","type":"string"},"review":{"description":"Review is how many seconds the buyer has after delivery to release or\ndispute: three days by default, thirty at most.","format":"int64","type":"integer"},"seller":{"description":"Seller is the org offered the job directly; only without a listing.","type":"string"},"title":{"description":"Title names a direct offer; a listing's job takes the listing's title.","type":"string"},"wallet":{"description":"Wallet is the buyer's wallet the payment is signed from. When named, the\nauthorization must be signed by its address.","type":"string"}},"type":"object"},"marketplace.installReq":{"properties":{"tool":{"description":"Tool is the registry name of the capability to activate (or deactivate) for\nthe caller's own org and project. Required.","type":"string"}},"type":"object"},"marketplace.installState":{"properties":{"installed":{"description":"Installed is its activation after the write.","type":"boolean"},"tool":{"description":"Tool is the capability the write applied to.","type":"string"}},"type":"object"},"marketplace.jobPage":{"properties":{"jobs":{"description":"Jobs is at most 500 jobs.","items":{"$ref":"#/components/schemas/marketplace.Job"},"type":"array"}},"type":"object"},"marketplace.listingPage":{"properties":{"listings":{"description":"Listings is every listing this org has published, private ones included\n(Public says which are discoverable by others).","items":{"$ref":"#/components/schemas/marketplace.Listing"},"type":"array"}},"type":"object"},"marketplace.marketCatalog":{"properties":{"items":{"description":"Items is every capability the caller can see in their own (org, project),\neach carrying any public listing's shop metadata and whether it is installed.","items":{"$ref":"#/components/schemas/marketplace.marketItem"},"type":"array"}},"type":"object"},"marketplace.marketItem":{"properties":{"activated":{"description":"Activated is filled by the registry from the activation store for the\nrequesting (org,project); providers leave it zero. An unactivated tool is\ndiscoverable but refused 403 at dispatch.","type":"boolean"},"category":{"description":"Category is that same listing's grouping. Free text chosen by the publisher,\nabsent when there is no public listing or the publisher left it blank.","type":"string"},"description":{"description":"Description is the prose a model reads to decide whether to call the tool.","type":"string"},"dispatchable":{"description":"Dispatchable is whether the tool can be CALLED. False for a listing-only\nentry: a skill is activated and attached to an agent, never called.","type":"boolean"},"inputSchema":{"description":"Schema is the JSON Schema of the call arguments — the MCP inputSchema.\nAbsent for a tool that takes none."},"installed":{"description":"Installed is whether the tool is activated for THIS caller's (org, project):\nthe same bit as Activated, under the shop's name for it, which install and\nuninstall are the writes for. It is per caller, so one listing reads\ninstalled for one org and not for another.","type":"boolean"},"name":{"description":"Name is the tool's id in the flat, fleet-wide tool namespace — the value a\ntools/call passes. Unique across sources: a collision is resolved by source\nprecedence before the caller ever sees it.","type":"string"},"price":{"$ref":"#/components/schemas/marketplace.Price","description":"Price is what a call costs and who is paid, absent for a free tool.\nEnforcement is the x402 settlement client; this is the declaration."},"source":{"description":"Source is where the tool comes from: connector, function, zap-service,\nagent, skill or mcp.","type":"string"},"title":{"description":"Title is the shop-window name, painted over the registry Name from the\nCHEAPEST public listing of this very tool — the platform's, for a tool every\norg reaches — the row a call would pay. Absent when the tool is not listed:\nthat row is a plain capability, not an offer.","type":"string"}},"type":"object"},"marketplace.patchReq":{"properties":{"category":{"description":"Category groups the listing in the shop window.","type":"string"},"currency":{"description":"Currency denominates Price.","type":"string"},"description":{"description":"Description is the long copy, at most 4096 characters.","type":"string"},"docs":{"description":"Docs is where the listing's documentation lives; empty clears it.","type":"string"},"id":{"description":"ID is the listing to edit, from the path.","type":"string"},"price":{"description":"Price is the decimal USD price, exact to 18 places; \"0\" makes it free.","type":"string"},"public":{"description":"Public makes the listing discoverable by other orgs, or withdraws it.","type":"boolean"},"recipient":{"description":"Recipient is the payout wallet id, in the publishing org.","type":"string"},"title":{"description":"Title is the shop-window name, 1-200 characters.","type":"string"}},"type":"object"},"marketplace.payoutIn":{"properties":{"wallet":{"description":"Wallet is one of the caller org's wallets. Required.","type":"string"}},"type":"object"},"marketplace.publishReq":{"properties":{"category":{"description":"Category groups the listing in the shop window.","type":"string"},"currency":{"description":"Currency denominates Price.","type":"string"},"description":{"description":"Description is the long copy, at most 4096 characters.","type":"string"},"docs":{"description":"Docs is where the listing's documentation lives: an https URL or a path on\ndocs.hanzo.ai.","type":"string"},"kind":{"description":"Kind is what is sold: agent, persona, app, skill, mcp or tool (the default).\nA tool is a platform tool, sold per call by the platform alone.","type":"string"},"price":{"description":"Price is the price as a decimal USD string, exact to 18 places — per call\nfor a tool, what a job is offered at otherwise. \"0.0025\" is a quarter of a\ncent and stays one. Empty or \"0\" publishes it free; a positive price\nrequires Recipient.","type":"string"},"public":{"description":"Public makes the listing discoverable by other orgs. Private otherwise.","type":"boolean"},"recipient":{"description":"Recipient is the seller's payout wallet id, in the publishing org — the\nwallet x402 pays. Required for a monetized listing.","type":"string"},"title":{"description":"Title is the shop-window name, 1-200 characters. Required.","type":"string"},"tool":{"description":"Tool names the thing sold, in the seller's own org: an agent's name or id,\nan app's project slug or id, a skill's name or id, an MCP server's name or\nid registered by hand, or a platform tool's registry name. It must be the\nseller's — there are no phantom listings.","type":"string"}},"type":"object"},"marketplace.verifyIn":{"properties":{"signature":{"description":"Signature is the wallet's 65-byte signature over the challenge's message\n(EIP-191), 0x hex. Required.","type":"string"}},"type":"object"},"meet.meetHealth":{"properties":{"ready":{"description":"Ready reports whether this deployment can mint join tokens. False is the 503.","type":"boolean"},"service":{"description":"Service names the subsystem answering — always \"meet\".","type":"string"},"status":{"description":"Status is \"ok\" when tokens can be minted and \"degraded\" when they cannot.","type":"string"}},"type":"object"},"meet.recordIn":{"properties":{"room":{"description":"Room is the LiveKit room, named the way the office client names one\n(`\u003cspace\u003e_\u003cname\u003e_\u003cid\u003e`). Its leading segment is what binds the room to a\ntenant, and it is the segment the caller's membership is checked against.","type":"string"}},"required":["room"],"type":"object"},"meet.recording":{"properties":{"bucket":{"description":"Bucket is the object store bucket the recording is written to. It is stated\nbeside the key rather than folded into one URI so a client reads two facts\ninstead of splitting a string.","type":"string"},"error":{"description":"Error is the media server's reason when a recording failed, and empty\notherwise.","type":"string"},"id":{"description":"ID is the media server's egress id — the handle a later read names.","type":"string"},"object":{"description":"Object is the key inside that bucket. Empty only while the media server has\nnot named a file yet.\n\nIt says WHERE the recording is, not how to fetch it. Reading one back is a\nseparate decision this surface deliberately does not make: a link to a\nprivate conversation needs its own answer about who may follow it and for\nhow long, and inventing a short one here would be worse than not having it.","type":"string"},"room":{"description":"Room is the room this recording is of.","type":"string"},"started":{"description":"Started is when the recording began, as the media server reports it: its\nown `started_at`, verbatim and unconverted. LiveKit's egress service sets\nthat field from UnixNano, and a conversion this side cannot check against\nthe running server would be a number that looks right and is wrong by a\nfactor of a billion. 0 means it has not started.","format":"int64","type":"integer"},"status":{"description":"Status is the media server's own state name: EGRESS_STARTING, EGRESS_ACTIVE,\nEGRESS_ENDING, EGRESS_COMPLETE, EGRESS_FAILED, EGRESS_ABORTED or\nEGRESS_LIMIT_REACHED. It is passed through rather than folded into a\nvocabulary of ours, so the answer cannot mean something the media server did\nnot say.","type":"string"}},"type":"object"},"meet.venue":{"properties":{"name":{"description":"Name is the media room to join: the value POST /v1/meet/getToken takes as\nroomName, and the value the media server keys participants on.","type":"string"},"ready":{"description":"Ready reports that this deployment can mint a join token for this room. It\nis false on a deployment holding no media-server key, where Name is still\ncorrect — the name is a property of the room and the key is a property of\nthe deployment, so a caller learns the room's identity either way and\nlearns not to offer a join button.","type":"boolean"},"ws":{"description":"WS is where the media plane is — the address a client opens its own\nbrowser-to-server connection to. Empty when this deployment has not been\ntold where its media server lives, which is reported rather than refused:\na surface can say a call is unavailable without a second request.","type":"string"}},"type":"object"},"ml.mlCreate":{"properties":{"labels":{"additionalProperties":{"type":"string"},"description":"Labels are extra labels to set on the object, merged UNDER the tenancy\nlabels this plane derives from the validated principal — so a label naming\nanother org's scope cannot displace the real one.","type":"object"},"name":{"description":"Name is the resource's name: a DNS-1123 label\n(^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$), lowercased and trimmed. It is the\nname the resource answers to for the life of the caller's org.","type":"string"},"spec":{"description":"Spec is the resource's own spec, passed to Kubernetes unchanged. Required —\nan empty spec is 400 rather than an empty resource."}},"type":"object"},"ml.mlResource":{"properties":{"createdAt":{"description":"CreatedAt is when Kubernetes admitted the object, RFC 3339 in UTC.","type":"string"},"name":{"description":"Name is the object's metadata.name, unique within the caller's namespace.","type":"string"},"spec":{"additionalProperties":{},"description":"Spec is the resource spec, verbatim as Kubernetes stores it. Present on a\nsingle-object read, absent from a list.","type":"object"},"status":{"additionalProperties":{},"description":"Status is the live status kserve owns, verbatim. Absent until kserve has\nwritten one.","type":"object"}},"type":"object"},"ml.mlResourceList":{"properties":{"items":{"description":"Items is one entry per object, newest LAST (the Kubernetes list order).","items":{"$ref":"#/components/schemas/ml.mlResource"},"type":"array"}},"type":"object"},"model.SearchResult":{"properties":{"icon":{"type":"string"},"index":{"type":"integer"},"site_name":{"type":"string"},"title":{"type":"string"},"url":{"type":"string"}},"type":"object"},"model.ToolCall":{"properties":{"arguments":{"type":"string"},"content":{"type":"string"},"name":{"type":"string"}},"type":"object"},"mq.Config":{"properties":{"max_age":{"description":"MaxAge caps message age, e.g. \"24h\" or \"7d\"; \"0\" (default) is unlimited.","type":"string"},"max_bytes":{"description":"MaxBytes caps the stream's total stored bytes; -1 (default) is unlimited.","format":"int64","type":"integer"},"max_msg_size":{"description":"MaxMsgSize caps one message's size in bytes; -1 (default) is the broker's limit.","format":"int32","type":"integer"},"max_msgs":{"description":"MaxMsgs caps the number of stored messages; -1 (default) is unlimited.","format":"int64","type":"integer"},"name":{"description":"Name is the stream name, unique within the org (alphanumeric, hyphens, underscores).","type":"string"},"num_replicas":{"description":"Replicas is the number of stream replicas (1–5); this plane runs 1.","format":"int64","type":"integer"},"retention":{"description":"Retention is the retention policy: limits (default), interest, or workqueue.","type":"string"},"storage":{"description":"Storage is the storage backend: file (default) or memory.","type":"string"},"subjects":{"description":"Subjects are the org-relative subjects bound to this stream (wildcards supported). Default: the stream name.","items":{"type":"string"},"type":"array"}},"type":"object"},"mq.Consumer":{"properties":{"ack_floor":{"$ref":"#/components/schemas/mq.Sequences","description":"AckFloor is the highest contiguously acknowledged sequence pair."},"config":{"$ref":"#/components/schemas/mq.Durable","description":"Config is the consumer's configuration."},"created":{"description":"Created is when the consumer was created.","format":"date-time","type":"string"},"delivered":{"$ref":"#/components/schemas/mq.Sequences","description":"Delivered is the highest delivered sequence pair."},"name":{"description":"Name is the consumer name.","type":"string"},"num_ack_pending":{"description":"AckPending is the number of delivered, not yet acknowledged messages.","format":"int64","type":"integer"},"num_pending":{"description":"Pending is the number of messages yet to be delivered.","format":"uint64","type":"integer"},"num_redelivered":{"description":"Redelivered is the number of messages currently being redelivered.","format":"int64","type":"integer"},"num_waiting":{"description":"Waiting is the number of pull requests waiting for messages.","format":"int64","type":"integer"},"stream_name":{"description":"Stream is the stream this consumer reads.","type":"string"}},"type":"object"},"mq.Delivery":{"properties":{"data":{"description":"Data is the payload, base64-encoded.","type":"string"},"headers":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"description":"Headers are the message headers, when any were published.","type":"object"},"num_delivered":{"description":"Delivered is how many times a consumer has been handed this message (pulls only).","format":"int64","type":"integer"},"num_pending":{"description":"Remaining is how many messages follow this one for the consumer (pulls only).","format":"uint64","type":"integer"},"sequence":{"description":"Sequence is the message's stream sequence.","format":"uint64","type":"integer"},"subject":{"description":"Subject is the org-relative subject the message was stored under.","type":"string"},"timestamp":{"description":"Timestamp is when the broker stored the message.","format":"date-time","type":"string"}},"type":"object"},"mq.Durable":{"properties":{"ack_policy":{"description":"Ack is the acknowledgment policy: explicit (default), all, or none.","type":"string"},"ack_wait":{"description":"AckWait is how long the broker waits for an ack before redelivering, e.g. \"30s\" (default).","type":"string"},"deliver_policy":{"description":"Deliver is where delivery starts: all (default), last, new, by_start_sequence, by_start_time, or last_per_subject.","type":"string"},"description":{"description":"Description says what this consumer is for.","type":"string"},"durable_name":{"description":"Name is the durable consumer name (alphanumeric, hyphens, underscores).","type":"string"},"filter_subject":{"description":"Filter delivers only messages on this org-relative subject (wildcards supported).","type":"string"},"max_ack_pending":{"description":"MaxAckPending caps unacknowledged messages in flight (default 1000).","format":"int64","type":"integer"},"max_deliver":{"description":"MaxDeliver caps delivery attempts per message; -1 (default) is unlimited.","format":"int64","type":"integer"},"opt_start_seq":{"description":"StartSeq is the starting sequence for deliver_policy by_start_sequence.","format":"uint64","type":"integer"},"opt_start_time":{"description":"StartTime is the starting instant for deliver_policy by_start_time.","format":"date-time","type":"string"},"replay_policy":{"description":"Replay is the replay pacing: instant (default) or original.","type":"string"}},"type":"object"},"mq.Health":{"properties":{"status":{"description":"Status is ok when the message plane answers, degraded otherwise.","type":"string"},"uptime":{"description":"Uptime is how long this surface has been mounted.","type":"string"},"version":{"description":"Version is the connected broker's server version; empty while degraded.","type":"string"}},"type":"object"},"mq.Purge":{"properties":{"filter":{"description":"Filter purges only messages on this org-relative subject (wildcards supported).","type":"string"},"keep":{"description":"Keep retains that many newest messages.","format":"uint64","type":"integer"},"name":{"description":"Name is the stream name, from the path.","type":"string"}},"type":"object"},"mq.Sequences":{"properties":{"consumer_seq":{"description":"Consumer is the consumer's own sequence.","format":"uint64","type":"integer"},"stream_seq":{"description":"Stream is the corresponding stream sequence.","format":"uint64","type":"integer"}},"type":"object"},"mq.State":{"properties":{"bytes":{"description":"Bytes is the total stored size.","format":"uint64","type":"integer"},"consumer_count":{"description":"Consumers is the number of consumers attached to this stream.","format":"int64","type":"integer"},"first_seq":{"description":"FirstSeq is the sequence of the first stored message.","format":"uint64","type":"integer"},"first_ts":{"description":"FirstTS is the timestamp of the first stored message.","format":"date-time","type":"string"},"last_seq":{"description":"LastSeq is the sequence of the last stored message.","format":"uint64","type":"integer"},"last_ts":{"description":"LastTS is the timestamp of the last stored message.","format":"date-time","type":"string"},"messages":{"description":"Messages is the number of messages currently stored.","format":"uint64","type":"integer"},"num_deleted":{"description":"Deleted is the number of deleted messages (sequence gaps).","format":"int64","type":"integer"},"num_subjects":{"description":"Subjects is the number of distinct subjects stored.","format":"uint64","type":"integer"}},"type":"object"},"mq.Stream":{"properties":{"config":{"$ref":"#/components/schemas/mq.Config","description":"Config is the stream's configuration."},"created":{"description":"Created is when the stream was created.","format":"date-time","type":"string"},"name":{"description":"Name is the stream name within the org.","type":"string"},"state":{"$ref":"#/components/schemas/mq.State","description":"State is the stream's current state."}},"type":"object"},"mq.Streams":{"properties":{"streams":{"description":"Streams is the page, ordered by name.","items":{"$ref":"#/components/schemas/mq.Stream"},"type":"array"},"total":{"description":"Total is the org's stream count before paging.","format":"int64","type":"integer"}},"type":"object"},"mq.infoOut":{"properties":{"jetstream":{"description":"JetStream is true when durable streams are enabled.","type":"boolean"},"max_payload":{"description":"MaxPayload is the broker's message-size ceiling in bytes.","format":"int64","type":"integer"},"server_id":{"description":"Server is the broker's server id.","type":"string"},"server_name":{"description":"Name is the broker's server name.","type":"string"},"streams":{"description":"Streams is the org's stream count.","format":"int64","type":"integer"},"version":{"description":"Version is the broker's server version.","type":"string"}},"type":"object"},"mq.makeIn":{"properties":{"ack_policy":{"description":"Ack is the acknowledgment policy: explicit (default), all, or none.","type":"string"},"ack_wait":{"description":"AckWait is how long the broker waits for an ack before redelivering, e.g. \"30s\" (default).","type":"string"},"deliver_policy":{"description":"Deliver is where delivery starts: all (default), last, new, by_start_sequence, by_start_time, or last_per_subject.","type":"string"},"description":{"description":"Description says what this consumer is for.","type":"string"},"durable_name":{"description":"Name is the durable consumer name (alphanumeric, hyphens, underscores).","type":"string"},"filter_subject":{"description":"Filter delivers only messages on this org-relative subject (wildcards supported).","type":"string"},"max_ack_pending":{"description":"MaxAckPending caps unacknowledged messages in flight (default 1000).","format":"int64","type":"integer"},"max_deliver":{"description":"MaxDeliver caps delivery attempts per message; -1 (default) is unlimited.","format":"int64","type":"integer"},"opt_start_seq":{"description":"StartSeq is the starting sequence for deliver_policy by_start_sequence.","format":"uint64","type":"integer"},"opt_start_time":{"description":"StartTime is the starting instant for deliver_policy by_start_time.","format":"date-time","type":"string"},"replay_policy":{"description":"Replay is the replay pacing: instant (default) or original.","type":"string"},"stream":{"description":"Stream is the stream name, from the path.","type":"string"}},"type":"object"},"mq.nextIn":{"properties":{"batch":{"description":"Batch is how many messages to pull (1–1000, default 1).","format":"int64","type":"integer"},"expires":{"description":"Expires is how long to wait for messages, e.g. \"5s\" (default \"30s\", max \"60s\").","type":"string"},"name":{"description":"Name is the consumer name, from the path.","type":"string"},"no_wait":{"description":"NoWait answers immediately with whatever is available instead of waiting.","type":"boolean"},"stream":{"description":"Stream is the stream name, from the path.","type":"string"}},"type":"object"},"mq.pickOut":{"properties":{"consumers":{"description":"Consumers is the page, ordered by name.","items":{"$ref":"#/components/schemas/mq.Consumer"},"type":"array"},"total":{"description":"Total is the stream's consumer count before paging.","format":"int64","type":"integer"}},"type":"object"},"mq.purgeOut":{"properties":{"purged":{"description":"Purged is the number of messages removed.","format":"uint64","type":"integer"}},"type":"object"},"mq.readOut":{"properties":{"messages":{"description":"Messages is what was read, stream-ordered.","items":{"$ref":"#/components/schemas/mq.Delivery"},"type":"array"}},"type":"object"},"network.identityIn":{"properties":{"name":{"description":"Name is the identity's name within the org — a DNS label, stored on the\nfabric as \"\u003cname\u003e.\u003corg\u003e\". Absent, the identity is named by the caller's\nIAM subject. It is set when the identity is first made; an identity that\nalready exists keeps its name.","type":"string"},"roles":{"description":"Roles are extra role attributes for the identity, each scoped to the\ncaller's org on the way in (\"k3s-host\" is written as \"k3s-host.\u003corg\u003e\") so\nno caller can claim an attribute another tenant's policy selects. A role\nof the form \"\u003cservice\u003e-host\" makes this identity a HOST of that published\nservice — the bind policy from POST /v1/network/services selects exactly\nthat attribute — and is refused when the org has no such service. Only a\nsteward (an admin of the org or its own machine client) takes roles; a\nplain member asking for one is 403.","items":{"type":"string"},"type":"array"}},"type":"object"},"network.identityList":{"properties":{"identities":{"description":"Identities is one row per fabric identity tagged with the caller's org role.","items":{"$ref":"#/components/schemas/network.identityView"},"type":"array"}},"type":"object"},"network.identityView":{"properties":{"externalId":{"description":"ExternalID is the IAM subject the identity logs in as: the controller\nadmits a bearer whose `sub` equals it.","type":"string"},"id":{"description":"ID is the identity's fabric id — the key DELETE addresses.","type":"string"},"name":{"description":"Name is the identity's name within the org.","type":"string"},"roles":{"description":"Roles are the identity's role attributes as the fabric holds them: the\n\"org-\u003corg\u003e\" of every org it was ensured in, plus any org-scoped roles.","items":{"type":"string"},"type":"array"}},"type":"object"},"network.meshServiceList":{"properties":{"services":{"description":"Services is one row per ZT edge service tagged with the caller's org role.","items":{"$ref":"#/components/schemas/network.meshView"},"type":"array"}},"type":"object"},"network.meshView":{"properties":{"id":{"description":"ID is the ZT edge service's id.","type":"string"},"mtls":{"description":"Mtls is \"required\" when the service mandates end-to-end encryption, else\n\"enabled\" — the fabric mutually authenticates every link, so it is never\ntruly off.","type":"string"},"service":{"description":"Service is the edge service's name.","type":"string"},"status":{"description":"Status is \"active\": a listed service is a configured, dialable mesh entry.","type":"string"}},"type":"object"},"network.networkList":{"properties":{"networks":{"description":"Networks holds the org's overlay network, or is empty when the org has no\nedge-routers on the fabric (no nodes → no network, never a fabricated one).","items":{"$ref":"#/components/schemas/network.networkView"},"type":"array"}},"type":"object"},"network.networkView":{"properties":{"id":{"description":"ID is the org-derived id of the overlay network — the key\nGET /v1/network/{id} addresses.","type":"string"},"name":{"description":"Name is the org the overlay belongs to.","type":"string"},"nodes":{"description":"Nodes is how many edge-routers the org has on the fabric.","format":"int64","type":"integer"},"status":{"description":"Status is \"connected\" once at least one of the org's edge-routers is\nonline, else \"provisioning\" (routers exist but none has dialed home).","type":"string"}},"type":"object"},"network.publishedView":{"properties":{"dns":{"description":"DNS is the name the fabric answers for this service — what a kubeconfig\nserver, or any client on the org's overlay, dials.","type":"string"},"id":{"description":"ID is the fabric service's id.","type":"string"},"name":{"description":"Name is the service's name within the org.","type":"string"}},"type":"object"},"network.routerList":{"properties":{"routers":{"description":"Routers is one row per ZT edge-router tagged with the caller's org role.","items":{"$ref":"#/components/schemas/network.routerView"},"type":"array"}},"type":"object"},"network.routerView":{"properties":{"id":{"description":"ID is the ZT edge-router's id.","type":"string"},"name":{"description":"Name is the edge-router's name, falling back to its id when it has none.","type":"string"},"region":{"description":"Region comes from a \"region-\u003cslug\u003e\" role attribute and is omitted when the\nrouter carries none, so the column renders \"—\" rather than a guess.","type":"string"},"status":{"description":"Status is the controller's own health signal: \"online\" when connected,\n\"disabled\" when administratively disabled, \"offline\" otherwise.","type":"string"}},"type":"object"},"network.serviceIn":{"properties":{"host":{"description":"Host is where the HOSTING identity forwards a connection — an address the\nhost device itself can reach, \"127.0.0.1\" for a server on the device.","type":"string"},"name":{"description":"Name is the service's name within the org — a DNS label. The fabric knows\nthe service as \"\u003cname\u003e.\u003corg\u003e\" and answers for it at \"\u003cname\u003e.\u003corg\u003e.zt\".","type":"string"},"port":{"description":"Port is the port beside Host, and the one the DNS name intercepts.","format":"int64","type":"integer"}},"type":"object"},"node.nodeView":{"properties":{"caps":{"description":"Caps is the capability list the node reported. It is a self-report, useful\nto SHOW and never load-bearing: what a node may actually be asked to do is\ndecided at the socket by the deployment's allowlist.","items":{"type":"string"},"type":"array"},"commands":{"description":"Commands is the command list the node reported. Same standing as Caps: a\nself-report, checked again at the socket before anything runs.","items":{"type":"string"},"type":"array"},"connectedAt":{"description":"ConnectedAt is when this node's socket was established, RFC3339 UTC.","type":"string"},"displayName":{"description":"DisplayName is the human name the node reported for itself.","type":"string"},"id":{"description":"ID is the node's own identifier within the org — the value\nPOST /v1/node/{id}/invoke addresses it by.","type":"string"},"platform":{"description":"Platform is the operating system and architecture the node reported.","type":"string"},"version":{"description":"Version is the node agent's own version string.","type":"string"}},"type":"object"},"node.nodesView":{"properties":{"nodes":{"description":"Nodes is every node of the caller's org with a live socket to THIS replica,\nordered by id. A node connected to a different replica is not in it.","items":{"$ref":"#/components/schemas/node.nodeView"},"type":"array"}},"type":"object"},"notify.notifyCredential":{"properties":{"key":{"description":"Key is one of the credentials that provider reads, such as auth-token or\nsmtp-host. A key the provider does not read is refused.","type":"string"},"provider":{"description":"Provider is the delivery provider the credential is for: twilio, plivo,\ntwilio_email or mail.","type":"string"},"value":{"description":"Value is sealed in KMS and never answered, logged or echoed. It is never\nread from a query string, because a URL is logged in more places than a\nbody is.","type":"string"}},"type":"object"},"notify.notifyHealth":{"properties":{"service":{"description":"Service names the subsystem answering — always \"notify\".","type":"string"},"status":{"description":"Status is \"ok\"; the route answers 200 whenever the subsystem is mounted.","type":"string"}},"type":"object"},"notify.notifySend":{"properties":{"body":{"description":"Body is the message text, sent verbatim when present — the no-template path.","type":"string"},"channel":{"description":"Channel selects the delivery channel, sms or email. The per-channel routes\n(/send/sms, /send/email) pin it, overriding whatever the body names; on the\ngeneric route it is required.","type":"string"},"event":{"description":"Event is the event name, which doubles as the template id when TemplateID is\nempty — the IAM OTP path sends event=iam.otp_sent and nothing else.","type":"string"},"provider":{"description":"Provider pins a provider service name (twilio, plivo, twilio_email, mail).\nEmpty picks the one whose org credentials are actually configured in KMS.","type":"string"},"subject":{"description":"Subject is the message subject, carried on the email channel only.","type":"string"},"sync":{"description":"Sync must be exactly \"true\": delivery here is synchronous, and anything else\nanswers 503 because the queue plane that would run an async dispatch is owned\nelsewhere. Over REST it rides as ?sync=true (the URL binds over the body); a\nby-name call states it in its arguments.","type":"string"},"template_id":{"description":"TemplateID selects a built-in template when Body is empty.","type":"string"},"template_vars":{"description":"TemplateVars carries the values the selected template renders against, as\na raw JSON object. Raw on purpose: the by-name call plane computes an\ninput's layout before reading any payload and refuses a map field\noutright, which would make every typed call to these ops fail — and that\ncall is the reason they are typed at all (IAM's OTP sender). deliver\ndecodes it right before the template renders, so REST bodies decode\nbyte-identically to the map this replaced."},"to":{"description":"To is the destination address per recipient — a phone number for sms, an\nemail address for email. Several recipients fan out into one provider call\neach, and the response shape follows the count (see the items field).","items":{"type":"string"},"type":"array"}},"type":"object"},"notify.notifyStored":{"properties":{"key":{"description":"Key is the credential that was set.","type":"string"},"provider":{"description":"Provider is the provider the credential was set for.","type":"string"},"stored":{"description":"Stored is true: the value is sealed and the next send reads it.","type":"boolean"}},"type":"object"},"o11y.AWSAccountConfig":{"properties":{"regions":{"items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.AWSCloudWatchLogsSubscription":{"properties":{"filterPattern":{"description":"https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/FilterAndPatternSyntax.html\n\"\" implies no filtering is required","type":"string"},"logGroupNamePrefix":{"description":"subscribe to all logs groups with specified prefix.\neg: `/aws/rds/`","type":"string"}},"type":"object"},"o11y.AWSCloudWatchMetricStreamFilter":{"properties":{"metricNames":{"items":{"type":"string"},"type":"array"},"namespace":{"description":"https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudwatch-metricstream-metricstreamfilter.html","type":"string"}},"type":"object"},"o11y.AWSConnectionArtifact":{"properties":{"connectionUrl":{"type":"string"}},"type":"object"},"o11y.AWSIntegrationConfig":{"properties":{"enabledRegions":{"items":{"type":"string"},"type":"array"},"telemetryCollectionStrategy":{"$ref":"#/components/schemas/o11y.AWSTelemetryCollectionStrategy"}},"type":"object"},"o11y.AWSLogsCollectionStrategy":{"properties":{"subscriptions":{"items":{"$ref":"#/components/schemas/o11y.AWSCloudWatchLogsSubscription"},"type":"array"}},"type":"object"},"o11y.AWSMetricsCollectionStrategy":{"properties":{"streamFilters":{"description":"to be used as https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudwatch-metricstream.html#cfn-cloudwatch-metricstream-includefilters","items":{"$ref":"#/components/schemas/o11y.AWSCloudWatchMetricStreamFilter"},"type":"array"}},"type":"object"},"o11y.AWSPostableAccountConfig":{"properties":{"deploymentRegion":{"type":"string"},"regions":{"items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.AWSServiceConfig":{"properties":{"logs":{"$ref":"#/components/schemas/o11y.AWSServiceLogsConfig"},"metrics":{"$ref":"#/components/schemas/o11y.AWSServiceMetricsConfig"}},"type":"object"},"o11y.AWSServiceLogsConfig":{"properties":{"enabled":{"type":"boolean"},"s3Buckets":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"}},"type":"object"},"o11y.AWSServiceMetricsConfig":{"properties":{"enabled":{"type":"boolean"}},"type":"object"},"o11y.AWSTelemetryCollectionStrategy":{"properties":{"logs":{"$ref":"#/components/schemas/o11y.AWSLogsCollectionStrategy"},"metrics":{"$ref":"#/components/schemas/o11y.AWSMetricsCollectionStrategy"},"s3Buckets":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"description":"Only available in S3 Sync Service Type in AWS","type":"object"}},"type":"object"},"o11y.Account":{"properties":{"agentReport":{"$ref":"#/components/schemas/o11y.AgentReport"},"config":{"$ref":"#/components/schemas/o11y.AccountConfig"},"createdAt":{"format":"date-time","type":"string"},"id":{},"orgId":{},"provider":{},"providerAccountId":{"type":"string"},"removedAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"o11y.AccountConfig":{"properties":{"aws":{"$ref":"#/components/schemas/o11y.AWSAccountConfig"},"azure":{"$ref":"#/components/schemas/o11y.AzureAccountConfig"},"gcp":{"$ref":"#/components/schemas/o11y.GCPAccountConfig"}},"type":"object"},"o11y.AgentReport":{"properties":{"data":{"additionalProperties":{},"type":"object"},"timestampMillis":{"format":"int64","type":"integer"}},"type":"object"},"o11y.AggregateAttributeResponse":{"properties":{"attributeKeys":{"items":{"$ref":"#/components/schemas/o11y.AttributeKey"},"type":"array"}},"type":"object"},"o11y.Alert":{"properties":{"annotations":{"additionalProperties":{"type":"string"},"type":"object"},"endsAt":{"format":"date-time","type":"string"},"generatorURL":{"type":"string"},"labels":{"additionalProperties":{"type":"string"},"type":"object"},"startsAt":{"format":"date-time","type":"string"}},"type":"object"},"o11y.AlertStatus":{"properties":{"inhibitedBy":{"items":{"type":"string"},"type":"array"},"silencedBy":{"items":{"type":"string"},"type":"array"},"state":{"type":"string"}},"type":"object"},"o11y.AssociatedComponent":{"properties":{"name":{"type":"string"},"type":{}},"type":"object"},"o11y.AttributeKey":{"properties":{"dataType":{"type":"string"},"isColumn":{"type":"boolean"},"isJSON":{"type":"boolean"},"key":{"type":"string"},"type":{"type":"string"}},"type":"object"},"o11y.AttributesComponentEntry":{"properties":{"associatedComponent":{"$ref":"#/components/schemas/o11y.AssociatedComponent"},"attributes":{"items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.Authorization":{"properties":{"credentials":{},"credentials_file":{"type":"string"},"credentials_ref":{"description":"CredentialsRef is the name of the secret within the secret manager to use as credentials.","type":"string"},"type":{"type":"string"}},"type":"object"},"o11y.AzureAccountConfig":{"properties":{"deploymentRegion":{"type":"string"},"resourceGroups":{"items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.AzureConnectionArtifact":{"properties":{"cliCommand":{"type":"string"},"cloudPowerShellCommand":{"type":"string"}},"type":"object"},"o11y.AzureIntegrationConfig":{"properties":{"deploymentRegion":{"type":"string"},"resourceGroups":{"items":{"type":"string"},"type":"array"},"telemetryCollectionStrategy":{"items":{"$ref":"#/components/schemas/o11y.AzureTelemetryCollectionStrategy"},"type":"array"}},"type":"object"},"o11y.AzureLogsCollectionStrategy":{"properties":{"categoryGroups":{"description":"List of categories to enable for diagnostic settings, to start with it will have 'allLogs' and no filtering.","items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.AzureMetricsCollectionStrategy":{"properties":{},"type":"object"},"o11y.AzureServiceConfig":{"properties":{"logs":{"$ref":"#/components/schemas/o11y.AzureServiceLogsConfig"},"metrics":{"$ref":"#/components/schemas/o11y.AzureServiceMetricsConfig"}},"type":"object"},"o11y.AzureServiceLogsConfig":{"properties":{"enabled":{"type":"boolean"}},"type":"object"},"o11y.AzureServiceMetricsConfig":{"properties":{"enabled":{"type":"boolean"}},"type":"object"},"o11y.AzureTelemetryCollectionStrategy":{"properties":{"logs":{"$ref":"#/components/schemas/o11y.AzureLogsCollectionStrategy"},"metrics":{"$ref":"#/components/schemas/o11y.AzureMetricsCollectionStrategy"},"resourceProvider":{"description":"https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-providers-and-types","type":"string"},"resourceType":{"type":"string"}},"type":"object"},"o11y.BasicAuth":{"properties":{"password":{},"password_file":{"type":"string"},"password_ref":{"description":"PasswordRef is the name of the secret within the secret manager to use as the password.","type":"string"},"username":{"type":"string"},"username_file":{"type":"string"},"username_ref":{"description":"UsernameRef is the name of the secret within the secret manager to use as the username.","type":"string"}},"type":"object"},"o11y.BuilderQuery":{"properties":{"IsAnomaly":{"type":"boolean"},"QueriesUsedInFormula":{"items":{"type":"string"},"type":"array"},"ShiftBy":{"format":"int64","type":"integer"},"aggregateAttribute":{"$ref":"#/components/schemas/o11y.AttributeKey"},"aggregateOperator":{"type":"string"},"dataSource":{"type":"string"},"disabled":{"type":"boolean"},"expression":{"type":"string"},"filters":{"$ref":"#/components/schemas/o11y.FilterSet"},"functions":{"items":{"$ref":"#/components/schemas/o11y.Function"},"type":"array"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.AttributeKey"},"type":"array"},"having":{"items":{"$ref":"#/components/schemas/o11y.Having"},"type":"array"},"legend":{"type":"string"},"limit":{"format":"uint64","type":"integer"},"offset":{"format":"uint64","type":"integer"},"orderBy":{"items":{"$ref":"#/components/schemas/o11y.OrderBy"},"type":"array"},"pageSize":{"format":"uint64","type":"integer"},"queryName":{"type":"string"},"reduceTo":{"type":"string"},"selectColumns":{"items":{"$ref":"#/components/schemas/o11y.AttributeKey"},"type":"array"},"seriesAggregation":{"type":"string"},"spaceAggregation":{"type":"string"},"stepInterval":{"format":"int64","type":"integer"},"temporality":{"type":"string"},"timeAggregation":{"type":"string"}},"type":"object"},"o11y.Channel":{"properties":{"createdAt":{"format":"date-time","type":"string"},"data":{"type":"string"},"id":{},"name":{"type":"string"},"orgId":{"type":"string"},"type":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"o11y.Checks":{"properties":{"missingDefaultEnabledMetrics":{"items":{"$ref":"#/components/schemas/o11y.MissingMetricsComponentEntry"},"type":"array"},"missingOptionalMetrics":{"items":{"$ref":"#/components/schemas/o11y.MissingMetricsComponentEntry"},"type":"array"},"missingRequiredAttributes":{"items":{"$ref":"#/components/schemas/o11y.MissingAttributesComponentEntry"},"type":"array"},"presentDefaultEnabledMetrics":{"items":{"$ref":"#/components/schemas/o11y.MetricsComponentEntry"},"type":"array"},"presentOptionalMetrics":{"items":{"$ref":"#/components/schemas/o11y.MetricsComponentEntry"},"type":"array"},"presentRequiredAttributes":{"items":{"$ref":"#/components/schemas/o11y.AttributesComponentEntry"},"type":"array"},"ready":{"type":"boolean"},"type":{}},"type":"object"},"o11y.CloudIntegrationService":{"properties":{"cloudIntegrationId":{},"config":{"$ref":"#/components/schemas/o11y.ServiceConfig"},"createdAt":{"format":"date-time","type":"string"},"id":{},"type":{},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"o11y.ClusterListRecord":{"properties":{"clusterUID":{"type":"string"},"cpuAllocatable":{"format":"double","type":"number"},"cpuUsage":{"format":"double","type":"number"},"memoryAllocatable":{"format":"double","type":"number"},"memoryUsage":{"format":"double","type":"number"},"meta":{"additionalProperties":{"type":"string"},"type":"object"}},"type":"object"},"o11y.ClusterListRequest":{"properties":{"end":{"description":"epoch time in ms","format":"int64","type":"integer"},"filters":{"$ref":"#/components/schemas/o11y.FilterSet"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.AttributeKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.OrderBy"},"start":{"description":"epoch time in ms","format":"int64","type":"integer"}},"type":"object"},"o11y.ClusterListResponse":{"properties":{"records":{"items":{"$ref":"#/components/schemas/o11y.ClusterListRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{"type":"string"}},"type":"object"},"o11y.ClusterRecord":{"properties":{"clusterCPU":{"format":"double","type":"number"},"clusterCPUAllocatable":{"format":"double","type":"number"},"clusterMemory":{"format":"double","type":"number"},"clusterMemoryAllocatable":{"format":"double","type":"number"},"clusterName":{"description":"TODO(nikhilmantri0902): once the underlying attr key is migrated to\nk8s.cluster.uid (see ClusterNameAttrKey), surface ClusterUID alongside\n(or replace) ClusterName.","type":"string"},"meta":{"additionalProperties":{"type":"string"},"type":"object"},"nodeCountsByReadiness":{"$ref":"#/components/schemas/o11y.NodeCountsByReadiness"},"podCountsByPhase":{"$ref":"#/components/schemas/o11y.PodCountsByPhase"}},"type":"object"},"o11y.Clusters":{"properties":{"endTimeBeforeRetention":{"type":"boolean"},"records":{"items":{"$ref":"#/components/schemas/o11y.ClusterRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{},"warning":{"$ref":"#/components/schemas/o11y.QueryWarnData"}},"type":"object"},"o11y.CollectedLogAttribute":{"properties":{"name":{"type":"string"},"path":{"type":"string"},"type":{"type":"string"}},"type":"object"},"o11y.CollectedMetric":{"properties":{"description":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"unit":{"type":"string"}},"type":"object"},"o11y.CompositeQuery":{"properties":{"queries":{"description":"Queries is the queries to use for the request.","items":{"$ref":"#/components/schemas/o11y.QueryEnvelope"},"type":"array"}},"type":"object"},"o11y.ConnectionArtifact":{"properties":{"aws":{"$ref":"#/components/schemas/o11y.AWSConnectionArtifact","description":"required till new providers are added"},"azure":{"$ref":"#/components/schemas/o11y.AzureConnectionArtifact"},"gcp":{"$ref":"#/components/schemas/o11y.GCPConnectionArtifact"}},"type":"object"},"o11y.Credentials":{"properties":{"ingestionKey":{"type":"string"},"ingestionUrl":{"type":"string"},"o11yApiKey":{"description":"PAT","type":"string"},"o11yApiUrl":{"type":"string"}},"type":"object"},"o11y.DaemonSetListRecord":{"properties":{"availableNodes":{"format":"int64","type":"integer"},"cpuLimit":{"format":"double","type":"number"},"cpuRequest":{"format":"double","type":"number"},"cpuUsage":{"format":"double","type":"number"},"daemonSetName":{"type":"string"},"desiredNodes":{"format":"int64","type":"integer"},"memoryLimit":{"format":"double","type":"number"},"memoryRequest":{"format":"double","type":"number"},"memoryUsage":{"format":"double","type":"number"},"meta":{"additionalProperties":{"type":"string"},"type":"object"},"restarts":{"format":"int64","type":"integer"}},"type":"object"},"o11y.DaemonSetListRequest":{"properties":{"end":{"description":"epoch time in ms","format":"int64","type":"integer"},"filters":{"$ref":"#/components/schemas/o11y.FilterSet"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.AttributeKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.OrderBy"},"start":{"description":"epoch time in ms","format":"int64","type":"integer"}},"type":"object"},"o11y.DaemonSetListResponse":{"properties":{"records":{"items":{"$ref":"#/components/schemas/o11y.DaemonSetListRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{"type":"string"}},"type":"object"},"o11y.DaemonSetRecord":{"properties":{"currentNodes":{"format":"int64","type":"integer"},"daemonSetCPU":{"format":"double","type":"number"},"daemonSetCPULimit":{"format":"double","type":"number"},"daemonSetCPURequest":{"format":"double","type":"number"},"daemonSetMemory":{"format":"double","type":"number"},"daemonSetMemoryLimit":{"format":"double","type":"number"},"daemonSetMemoryRequest":{"format":"double","type":"number"},"daemonSetName":{"type":"string"},"desiredNodes":{"format":"int64","type":"integer"},"meta":{"additionalProperties":{"type":"string"},"type":"object"},"podCountsByPhase":{"$ref":"#/components/schemas/o11y.PodCountsByPhase"}},"type":"object"},"o11y.DaemonSets":{"properties":{"endTimeBeforeRetention":{"type":"boolean"},"records":{"items":{"$ref":"#/components/schemas/o11y.DaemonSetRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{},"warning":{"$ref":"#/components/schemas/o11y.QueryWarnData"}},"type":"object"},"o11y.DataCollected":{"properties":{"logs":{"items":{"$ref":"#/components/schemas/o11y.cloudintegrationtypes.CollectedLogAttribute"},"type":"array"},"metrics":{"items":{"$ref":"#/components/schemas/o11y.cloudintegrationtypes.CollectedMetric"},"type":"array"}},"type":"object"},"o11y.DataCollectedForIntegration":{"properties":{"logs":{"items":{"$ref":"#/components/schemas/o11y.CollectedLogAttribute"},"type":"array"},"metrics":{"items":{"$ref":"#/components/schemas/o11y.CollectedMetric"},"type":"array"}},"type":"object"},"o11y.DatastoreQuery":{"properties":{"disabled":{"type":"boolean"},"legend":{"type":"string"},"query":{"type":"string"}},"type":"object"},"o11y.DeploymentListRecord":{"properties":{"availablePods":{"format":"int64","type":"integer"},"cpuLimit":{"format":"double","type":"number"},"cpuRequest":{"format":"double","type":"number"},"cpuUsage":{"format":"double","type":"number"},"deploymentName":{"type":"string"},"desiredPods":{"format":"int64","type":"integer"},"memoryLimit":{"format":"double","type":"number"},"memoryRequest":{"format":"double","type":"number"},"memoryUsage":{"format":"double","type":"number"},"meta":{"additionalProperties":{"type":"string"},"type":"object"},"restarts":{"format":"int64","type":"integer"}},"type":"object"},"o11y.DeploymentListRequest":{"properties":{"end":{"description":"epoch time in ms","format":"int64","type":"integer"},"filters":{"$ref":"#/components/schemas/o11y.FilterSet"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.AttributeKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.OrderBy"},"start":{"description":"epoch time in ms","format":"int64","type":"integer"}},"type":"object"},"o11y.DeploymentListResponse":{"properties":{"records":{"items":{"$ref":"#/components/schemas/o11y.DeploymentListRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{"type":"string"}},"type":"object"},"o11y.DeploymentRecord":{"properties":{"availablePods":{"format":"int64","type":"integer"},"deploymentCPU":{"format":"double","type":"number"},"deploymentCPULimit":{"format":"double","type":"number"},"deploymentCPURequest":{"format":"double","type":"number"},"deploymentMemory":{"format":"double","type":"number"},"deploymentMemoryLimit":{"format":"double","type":"number"},"deploymentMemoryRequest":{"format":"double","type":"number"},"deploymentName":{"type":"string"},"desiredPods":{"format":"int64","type":"integer"},"meta":{"additionalProperties":{"type":"string"},"type":"object"},"podCountsByPhase":{"$ref":"#/components/schemas/o11y.PodCountsByPhase"}},"type":"object"},"o11y.Deployments":{"properties":{"endTimeBeforeRetention":{"type":"boolean"},"records":{"items":{"$ref":"#/components/schemas/o11y.DeploymentRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{},"warning":{"$ref":"#/components/schemas/o11y.QueryWarnData"}},"type":"object"},"o11y.DeprecatedGettableAlert":{"properties":{"Alert":{"$ref":"#/components/schemas/o11y.Alert"},"fingerprint":{"type":"string"},"receivers":{"items":{"type":"string"},"type":"array"},"status":{"$ref":"#/components/schemas/o11y.AlertStatus"}},"type":"object"},"o11y.DiscordConfig":{"properties":{"NotifierConfig":{"$ref":"#/components/schemas/o11y.NotifierConfig"},"avatar_url":{"type":"string"},"content":{"type":"string"},"http_config":{"$ref":"#/components/schemas/o11y.HTTPClientConfig"},"message":{"type":"string"},"title":{"type":"string"},"username":{"type":"string"},"webhook_url":{},"webhook_url_file":{"type":"string"}},"type":"object"},"o11y.EmailConfig":{"properties":{"NotifierConfig":{"$ref":"#/components/schemas/o11y.NotifierConfig"},"auth_identity":{"type":"string"},"auth_password":{},"auth_password_file":{"type":"string"},"auth_secret":{},"auth_secret_file":{"type":"string"},"auth_username":{"type":"string"},"force_implicit_tls":{"description":"ForceImplicitTLS controls whether to use implicit TLS (direct TLS connection).\ntrue: force use of implicit TLS (direct TLS connection)\nfalse: force disable implicit TLS (use explicit TLS/STARTTLS if required)\nnil (default): auto-detect based on port (465=implicit, other=explicit) for backward compatibility","type":"boolean"},"from":{"type":"string"},"headers":{"additionalProperties":{"type":"string"},"type":"object"},"hello":{"type":"string"},"html":{"type":"string"},"require_tls":{"type":"boolean"},"smarthost":{},"text":{"type":"string"},"threading":{"$ref":"#/components/schemas/o11y.ThreadingConfig"},"tls_config":{"$ref":"#/components/schemas/o11y.TLSConfig"},"to":{"description":"Email address to notify.","type":"string"}},"type":"object"},"o11y.Event":{"properties":{"attributeMap":{"additionalProperties":{},"type":"object"},"isError":{"type":"boolean"},"name":{"type":"string"},"timeUnixNano":{"format":"uint64","type":"integer"}},"type":"object"},"o11y.Filter":{"properties":{"expression":{"description":"expression to filter by following the filter syntax","type":"string"}},"type":"object"},"o11y.FilterAttributeKeyResponse":{"properties":{"attributeKeys":{"items":{"$ref":"#/components/schemas/o11y.AttributeKey"},"type":"array"}},"type":"object"},"o11y.FilterAttributeValueRequest":{"properties":{"aggregateAttribute":{"type":"string"},"aggregateOperator":{"type":"string"},"dataSource":{"type":"string"},"endTimeMillis":{"format":"int64","type":"integer"},"existingFilterItems":{"items":{"$ref":"#/components/schemas/o11y.FilterItem"},"type":"array"},"filterAttributeKey":{"type":"string"},"filterAttributeKeyDataType":{"type":"string"},"includeRelated":{"type":"boolean"},"limit":{"format":"int64","type":"integer"},"metricNames":{"items":{"type":"string"},"type":"array"},"searchText":{"type":"string"},"startTimeMillis":{"format":"int64","type":"integer"},"tagType":{"type":"string"}},"type":"object"},"o11y.FilterAttributeValueResponse":{"properties":{"boolAttributeValues":{"items":{"type":"boolean"},"type":"array"},"numberAttributeValues":{"items":{},"type":"array"},"relatedValues":{"$ref":"#/components/schemas/o11y.FilterAttributeValueResponse"},"stringAttributeValues":{"items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.FilterItem":{"properties":{"key":{"$ref":"#/components/schemas/o11y.AttributeKey"},"op":{"type":"string"},"value":{}},"type":"object"},"o11y.FilterSet":{"properties":{"items":{"items":{"$ref":"#/components/schemas/o11y.FilterItem"},"type":"array"},"op":{"type":"string"}},"type":"object"},"o11y.FlamegraphSpan":{"properties":{"attributes":{"additionalProperties":{},"type":"object"},"durationNano":{"format":"uint64","type":"integer"},"event":{"items":{"$ref":"#/components/schemas/o11y.Event"},"type":"array"},"hasError":{"type":"boolean"},"level":{"format":"int64","type":"integer"},"name":{"type":"string"},"parentSpanId":{"type":"string"},"resource":{"additionalProperties":{"type":"string"},"type":"object"},"spanId":{"type":"string"},"timestamp":{"format":"uint64","type":"integer"}},"type":"object"},"o11y.FormatOptions":{"properties":{"fillGaps":{"type":"boolean"},"formatTableResultForUI":{"type":"boolean"}},"type":"object"},"o11y.Function":{"properties":{"args":{"items":{},"type":"array"},"name":{"type":"string"},"namedArgs":{"additionalProperties":{},"type":"object"}},"type":"object"},"o11y.FunnelStep":{"properties":{"description":{"description":"step description","type":"string"},"filters":{"$ref":"#/components/schemas/o11y.FilterSet"},"has_errors":{"type":"boolean"},"id":{},"latency_pointer":{"type":"string"},"latency_type":{"type":"string"},"name":{"description":"step name","type":"string"},"service_name":{"type":"string"},"span_name":{"type":"string"},"step_order":{"format":"int64","type":"integer"}},"type":"object"},"o11y.GCPAccountConfig":{"properties":{"deploymentProjectId":{"description":"Project ID where central pub/sub for logs exist","type":"string"},"deploymentRegion":{"description":"Project ID where otel collector will be deployed","type":"string"},"projectIds":{"description":"List of project IDs to monitor","items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.GCPConnectionArtifact":{"properties":{},"type":"object"},"o11y.GCPIntegrationConfig":{"properties":{},"type":"object"},"o11y.GCPServiceConfig":{"properties":{"logs":{"$ref":"#/components/schemas/o11y.GCPServiceLogsConfig"},"metrics":{"$ref":"#/components/schemas/o11y.GCPServiceMetricsConfig"}},"type":"object"},"o11y.GCPServiceLogsConfig":{"properties":{"enabled":{"type":"boolean"}},"type":"object"},"o11y.GCPServiceMetricsConfig":{"properties":{"enabled":{"type":"boolean"}},"type":"object"},"o11y.GettableAccountWithConnectionArtifact":{"properties":{"connectionArtifact":{"$ref":"#/components/schemas/o11y.ConnectionArtifact"},"id":{}},"type":"object"},"o11y.GettableAccounts":{"properties":{"accounts":{"items":{"$ref":"#/components/schemas/o11y.Account"},"type":"array"}},"type":"object"},"o11y.GettableAgentCheckIn":{"properties":{"account_id":{"description":"Older fields for backward compatibility with existing AWS agents","type":"string"},"cloudIntegrationId":{"type":"string"},"cloud_account_id":{"type":"string"},"integrationConfig":{"$ref":"#/components/schemas/o11y.ProviderIntegrationConfig"},"integration_config":{"$ref":"#/components/schemas/o11y.IntegrationConfig"},"providerAccountId":{"type":"string"},"removedAt":{"format":"date-time","type":"string"},"removed_at":{"format":"date-time","type":"string"}},"type":"object"},"o11y.GettableCreatedIngestionKey":{"properties":{"id":{"type":"string"},"value":{"type":"string"}},"type":"object"},"o11y.GettableCreatedIngestionKeyLimit":{"properties":{"id":{"type":"string"}},"type":"object"},"o11y.GettableFieldKeys":{"properties":{"complete":{"type":"boolean"},"keys":{"additionalProperties":{"items":{"$ref":"#/components/schemas/o11y.TelemetryFieldKey"},"type":"array"},"type":"object"}},"type":"object"},"o11y.GettableFieldValues":{"properties":{"complete":{"type":"boolean"},"values":{"$ref":"#/components/schemas/o11y.TelemetryFieldValues"}},"type":"object"},"o11y.GettableFlamegraphTrace":{"properties":{"endTimestampMillis":{"format":"int64","type":"integer"},"hasMore":{"type":"boolean"},"spans":{"items":{"items":{"$ref":"#/components/schemas/o11y.FlamegraphSpan"},"type":"array"},"type":"array"},"startTimestampMillis":{"format":"int64","type":"integer"}},"type":"object"},"o11y.GettableFunnel":{"properties":{"created_at":{"format":"int64","type":"integer"},"created_by":{"type":"string"},"description":{"type":"string"},"funnel":{"$ref":"#/components/schemas/o11y.StorableFunnel"},"funnel_id":{"type":"string"},"funnel_name":{"type":"string"},"org_id":{"type":"string"},"steps":{"items":{"$ref":"#/components/schemas/o11y.FunnelStep"},"type":"array"},"updated_at":{"format":"int64","type":"integer"},"updated_by":{"type":"string"},"user_email":{"type":"string"}},"type":"object"},"o11y.GettableHost":{"properties":{"hosts":{"items":{"$ref":"#/components/schemas/o11y.Host"},"type":"array"},"name":{"type":"string"},"state":{"type":"string"},"tier":{"type":"string"}},"type":"object"},"o11y.GettableIngestionKeys":{"properties":{"_pagination":{"$ref":"#/components/schemas/o11y.Pagination"},"keys":{"items":{"$ref":"#/components/schemas/o11y.IngestionKey"},"type":"array"}},"type":"object"},"o11y.GettableRoutePolicy":{"properties":{"channels":{"items":{"type":"string"},"type":"array"},"createdAt":{"format":"date-time","type":"string"},"createdBy":{"type":"string"},"description":{"type":"string"},"expression":{"type":"string"},"id":{"type":"string"},"kind":{},"name":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"},"updatedAt":{"format":"date-time","type":"string"},"updatedBy":{"type":"string"}},"type":"object"},"o11y.GettableRuleStateHistory":{"properties":{"fingerprint":{"format":"uint64","type":"integer"},"labels":{"items":{"$ref":"#/components/schemas/o11y.Label"},"type":"array"},"overallState":{},"overallStateChanged":{"type":"boolean"},"ruleId":{"type":"string"},"ruleName":{"type":"string"},"state":{},"stateChanged":{"type":"boolean"},"unixMilli":{"format":"int64","type":"integer"},"value":{"format":"double","type":"number"}},"type":"object"},"o11y.GettableRuleStateHistoryContributor":{"properties":{"count":{"format":"uint64","type":"integer"},"fingerprint":{"format":"uint64","type":"integer"},"labels":{"items":{"$ref":"#/components/schemas/o11y.Label"},"type":"array"},"relatedLogsLink":{"type":"string"},"relatedTracesLink":{"type":"string"}},"type":"object"},"o11y.GettableRuleStateHistoryStats":{"properties":{"currentAvgResolutionTime":{"format":"double","type":"number"},"currentAvgResolutionTimeSeries":{"$ref":"#/components/schemas/o11y.TimeSeries"},"currentTriggersSeries":{"$ref":"#/components/schemas/o11y.TimeSeries"},"pastAvgResolutionTime":{"format":"double","type":"number"},"pastAvgResolutionTimeSeries":{"$ref":"#/components/schemas/o11y.TimeSeries"},"pastTriggersSeries":{"$ref":"#/components/schemas/o11y.TimeSeries"},"totalCurrentTriggers":{"format":"uint64","type":"integer"},"totalPastTriggers":{"format":"uint64","type":"integer"}},"type":"object"},"o11y.GettableRuleStateTimeline":{"properties":{"items":{"items":{"$ref":"#/components/schemas/o11y.GettableRuleStateHistory"},"type":"array"},"nextCursor":{"type":"string"},"total":{"format":"uint64","type":"integer"}},"type":"object"},"o11y.GettableRuleStateWindow":{"properties":{"end":{"format":"int64","type":"integer"},"start":{"format":"int64","type":"integer"},"state":{}},"type":"object"},"o11y.GettableServicesMetadata":{"properties":{"services":{"items":{"$ref":"#/components/schemas/o11y.ServiceMetadata"},"type":"array"}},"type":"object"},"o11y.GettableSpanMapperGroups":{"properties":{"items":{"items":{"$ref":"#/components/schemas/o11y.SpanMapperGroup"},"type":"array"}},"type":"object"},"o11y.GettableSpanMappers":{"properties":{"items":{"items":{"$ref":"#/components/schemas/o11y.SpanMapper"},"type":"array"}},"type":"object"},"o11y.GettableTestRule":{"properties":{"alertCount":{"format":"int64","type":"integer"},"message":{"type":"string"}},"type":"object"},"o11y.GettableTraceAggregations":{"properties":{"aggregations":{"items":{"$ref":"#/components/schemas/o11y.SpanAggregationResult"},"type":"array"}},"type":"object"},"o11y.GettableWaterfallTrace":{"properties":{"endTimestampMillis":{"format":"uint64","type":"integer"},"hasMissingSpans":{"type":"boolean"},"hasMore":{"type":"boolean"},"rootServiceEntryPoint":{"type":"string"},"rootServiceName":{"type":"string"},"spans":{"items":{"$ref":"#/components/schemas/o11y.WaterfallSpan"},"type":"array"},"startTimestampMillis":{"format":"uint64","type":"integer"},"totalErrorSpansCount":{"format":"uint64","type":"integer"},"totalSpansCount":{"format":"uint64","type":"integer"},"uncollapsedSpans":{"items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.GoogleChatReceiverConfig":{"properties":{"NotifierConfig":{"$ref":"#/components/schemas/o11y.NotifierConfig"},"http_config":{"$ref":"#/components/schemas/o11y.HTTPClientConfig"},"text":{"type":"string"},"title":{"type":"string"},"webhook_url":{}},"type":"object"},"o11y.GroupByKey":{"properties":{"description":{"type":"string"},"fieldContext":{},"fieldDataType":{},"name":{"type":"string"},"signal":{},"unit":{"type":"string"}},"required":["name"],"type":"object"},"o11y.HTTPClientConfig":{"properties":{"authorization":{"$ref":"#/components/schemas/o11y.Authorization","description":"The HTTP authorization credentials for the targets."},"basic_auth":{"$ref":"#/components/schemas/o11y.BasicAuth","description":"The HTTP basic authentication credentials for the targets."},"bearer_token":{"description":"The bearer token for the targets. Deprecated in favour of\nAuthorization.Credentials."},"bearer_token_file":{"description":"The bearer token file for the targets. Deprecated in favour of\nAuthorization.CredentialsFile.","type":"string"},"enable_http2":{"description":"EnableHTTP2 specifies whether the client should configure HTTP2.\nThe omitempty flag is not set, because it would be hidden from the\nmarshalled configuration when set to false.","type":"boolean"},"follow_redirects":{"description":"FollowRedirects specifies whether the client should follow HTTP 3xx redirects.\nThe omitempty flag is not set, because it would be hidden from the\nmarshalled configuration when set to false.","type":"boolean"},"http_headers":{"description":"HTTPHeaders specify headers to inject in the requests. Those headers\ncould be marshalled back to the users."},"no_proxy":{"description":"NoProxy contains addresses that should not use a proxy.","type":"string"},"oauth2":{"$ref":"#/components/schemas/o11y.OAuth2","description":"The OAuth2 client credentials used to fetch a token for the targets."},"proxy_connect_header":{"additionalProperties":{"items":{},"type":"array"},"description":"ProxyConnectHeader optionally specifies headers to send to\nproxies during CONNECT requests. Assume that at least _some_ of\nthese headers are going to contain secrets and use Secret as the\nvalue type instead of string.","type":"object"},"proxy_from_environment":{"description":"ProxyFromEnvironment makes use of net/http ProxyFromEnvironment function\nto determine proxies.","type":"boolean"},"proxy_url":{"description":"HTTP proxy server to use to connect to the targets."},"tls_config":{"$ref":"#/components/schemas/o11y.TLSConfig","description":"TLSConfig to use to connect to the targets."}},"type":"object"},"o11y.Having":{"properties":{"columnName":{"type":"string"},"op":{"type":"string"},"value":{}},"type":"object"},"o11y.Heartbeat":{"properties":{"ageSeconds":{"description":"AgeSeconds is how long ago the last heartbeat arrived — or this process\nstarted, before its first.","format":"int64","type":"integer"},"limitSeconds":{"description":"LimitSeconds is how old the heartbeat may get before this answers 503.","format":"int64","type":"integer"}},"type":"object"},"o11y.Host":{"properties":{"is_default":{"type":"boolean"},"name":{"type":"string"},"url":{"type":"string"}},"type":"object"},"o11y.HostFilter":{"properties":{"Filter":{"$ref":"#/components/schemas/o11y.Filter"},"filterByStatus":{}},"type":"object"},"o11y.HostListRecord":{"properties":{"active":{"type":"boolean"},"cpu":{"format":"double","type":"number"},"hostName":{"type":"string"},"load15":{"format":"double","type":"number"},"memory":{"format":"double","type":"number"},"meta":{"additionalProperties":{"type":"string"},"type":"object"},"os":{"type":"string"},"wait":{"format":"double","type":"number"}},"type":"object"},"o11y.HostListRequest":{"properties":{"end":{"description":"epoch time in ms","format":"int64","type":"integer"},"filters":{"$ref":"#/components/schemas/o11y.FilterSet"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.AttributeKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.OrderBy"},"start":{"description":"epoch time in ms","format":"int64","type":"integer"}},"type":"object"},"o11y.HostListResponse":{"properties":{"clusterNames":{"items":{"type":"string"},"type":"array"},"endTimeBeforeRetention":{"type":"boolean"},"isSendingK8SAgentMetrics":{"type":"boolean"},"nodeNames":{"items":{"type":"string"},"type":"array"},"records":{"items":{"$ref":"#/components/schemas/o11y.HostListRecord"},"type":"array"},"sentAnyHostMetricsData":{"type":"boolean"},"total":{"format":"int64","type":"integer"},"type":{"type":"string"}},"type":"object"},"o11y.HostRecord":{"properties":{"activeHostCount":{"format":"int64","type":"integer"},"cpu":{"format":"double","type":"number"},"diskUsage":{"format":"double","type":"number"},"hostName":{"type":"string"},"inactiveHostCount":{"format":"int64","type":"integer"},"load15":{"format":"double","type":"number"},"memory":{"format":"double","type":"number"},"meta":{"additionalProperties":{"type":"string"},"type":"object"},"status":{},"wait":{"format":"double","type":"number"}},"type":"object"},"o11y.Hosts":{"properties":{"endTimeBeforeRetention":{"type":"boolean"},"records":{"items":{"$ref":"#/components/schemas/o11y.HostRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{},"warning":{"$ref":"#/components/schemas/o11y.QueryWarnData"}},"type":"object"},"o11y.IncidentioConfig":{"properties":{"NotifierConfig":{"$ref":"#/components/schemas/o11y.NotifierConfig"},"alert_source_token":{"description":"AlertSourceToken is the key used to authenticate with the alert source in incident.io."},"alert_source_token_file":{"type":"string"},"http_config":{"$ref":"#/components/schemas/o11y.HTTPClientConfig"},"max_alerts":{"description":"MaxAlerts is the maximum number of alerts to be sent per incident.io message.\nAlerts exceeding this threshold will be truncated. Setting this to 0\nallows an unlimited number of alerts. Note that if the payload exceeds\nincident.io's size limits, you will receive a 429 response and alerts\nwill not be ingested.","format":"uint64","type":"integer"},"timeout":{"description":"Timeout is the maximum time allowed to invoke incident.io. Setting this to 0\ndoes not impose a timeout.","format":"int64","type":"integer"},"url":{"description":"URL to send POST request to."},"url_file":{"type":"string"}},"type":"object"},"o11y.IngestionKey":{"properties":{"created_at":{"format":"date-time","type":"string"},"expires_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"limits":{"items":{"$ref":"#/components/schemas/o11y.Limit"},"type":"array"},"name":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"},"updated_at":{"format":"date-time","type":"string"},"value":{"type":"string"},"workspace_id":{"type":"string"}},"type":"object"},"o11y.InstallIntegrationRequest":{"properties":{"config":{"additionalProperties":{},"type":"object"},"integration_id":{"type":"string"}},"type":"object"},"o11y.InstalledIntegration":{"properties":{"config":{"additionalProperties":{},"type":"object"},"id":{},"installed_at":{"format":"date-time","type":"string"},"org_id":{"type":"string"},"type":{"type":"string"}},"type":"object"},"o11y.Integration":{"properties":{"assets":{"$ref":"#/components/schemas/o11y.IntegrationAssets"},"author":{"$ref":"#/components/schemas/o11y.IntegrationAuthor"},"categories":{"items":{"type":"string"},"type":"array"},"configuration":{"items":{"$ref":"#/components/schemas/o11y.IntegrationConfigStep"},"type":"array"},"connection_tests":{"$ref":"#/components/schemas/o11y.IntegrationConnectionTests"},"data_collected":{"$ref":"#/components/schemas/o11y.DataCollectedForIntegration"},"description":{"description":"A short description","type":"string"},"icon":{"type":"string"},"id":{"type":"string"},"installation":{"$ref":"#/components/schemas/o11y.InstalledIntegration"},"overview":{"description":"markdown","type":"string"},"title":{"type":"string"}},"type":"object"},"o11y.IntegrationAssets":{"properties":{"alerts":{"items":{},"type":"array"},"dashboards":{"items":{"additionalProperties":{},"type":"object"},"type":"array"},"logs":{"$ref":"#/components/schemas/o11y.LogsAssets"}},"type":"object"},"o11y.IntegrationAuthor":{"properties":{"email":{"type":"string"},"homepage":{"type":"string"},"name":{"type":"string"}},"type":"object"},"o11y.IntegrationConfig":{"properties":{"enabled_regions":{"description":"backward compatible","items":{"type":"string"},"type":"array"},"telemetry":{"$ref":"#/components/schemas/o11y.OldAWSCollectionStrategy","description":"backward compatible"}},"type":"object"},"o11y.IntegrationConfigStep":{"properties":{"instructions":{"type":"string"},"title":{"type":"string"}},"type":"object"},"o11y.IntegrationConnectionStatus":{"properties":{"logs":{"$ref":"#/components/schemas/o11y.SignalConnectionStatus"},"metrics":{"$ref":"#/components/schemas/o11y.SignalConnectionStatus"}},"type":"object"},"o11y.IntegrationConnectionTests":{"properties":{"logs":{"$ref":"#/components/schemas/o11y.LogsConnectionTest"},"metrics":{"description":"Metric names expected to have been received for the integration.","items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.IntegrationsListItem":{"properties":{"author":{"$ref":"#/components/schemas/o11y.IntegrationAuthor"},"description":{"description":"A short description","type":"string"},"icon":{"type":"string"},"id":{"type":"string"},"is_installed":{"type":"boolean"},"title":{"type":"string"}},"type":"object"},"o11y.IntegrationsListResponse":{"properties":{"integrations":{"items":{"$ref":"#/components/schemas/o11y.IntegrationsListItem"},"type":"array"}},"type":"object"},"o11y.JiraConfig":{"properties":{"NotifierConfig":{"$ref":"#/components/schemas/o11y.NotifierConfig"},"api_type":{"type":"string"},"api_url":{},"custom_fields":{"additionalProperties":{},"type":"object"},"description":{"$ref":"#/components/schemas/o11y.JiraFieldConfig"},"http_config":{"$ref":"#/components/schemas/o11y.HTTPClientConfig"},"issue_type":{"type":"string"},"labels":{"items":{"type":"string"},"type":"array"},"priority":{"type":"string"},"project":{"type":"string"},"reopen_duration":{},"reopen_transition":{"type":"string"},"resolve_transition":{"type":"string"},"summary":{"$ref":"#/components/schemas/o11y.JiraFieldConfig"},"wont_fix_resolution":{"type":"string"}},"type":"object"},"o11y.JiraFieldConfig":{"properties":{"enable_update":{"description":"EnableUpdate indicates whether this field should be omitted when updating an existing issue.","type":"boolean"},"template":{"description":"Template is the template string used to render the field.","type":"string"}},"type":"object"},"o11y.JobListRecord":{"properties":{"activePods":{"format":"int64","type":"integer"},"cpuLimit":{"format":"double","type":"number"},"cpuRequest":{"format":"double","type":"number"},"cpuUsage":{"format":"double","type":"number"},"desiredSuccessfulPods":{"format":"int64","type":"integer"},"failedPods":{"format":"int64","type":"integer"},"jobName":{"type":"string"},"memoryLimit":{"format":"double","type":"number"},"memoryRequest":{"format":"double","type":"number"},"memoryUsage":{"format":"double","type":"number"},"meta":{"additionalProperties":{"type":"string"},"type":"object"},"restarts":{"format":"int64","type":"integer"},"successfulPods":{"format":"int64","type":"integer"}},"type":"object"},"o11y.JobListRequest":{"properties":{"end":{"description":"epoch time in ms","format":"int64","type":"integer"},"filters":{"$ref":"#/components/schemas/o11y.FilterSet"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.AttributeKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.OrderBy"},"start":{"description":"epoch time in ms","format":"int64","type":"integer"}},"type":"object"},"o11y.JobListResponse":{"properties":{"records":{"items":{"$ref":"#/components/schemas/o11y.JobListRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{"type":"string"}},"type":"object"},"o11y.JobRecord":{"properties":{"activePods":{"format":"int64","type":"integer"},"desiredSuccessfulPods":{"format":"int64","type":"integer"},"failedPods":{"format":"int64","type":"integer"},"jobCPU":{"format":"double","type":"number"},"jobCPULimit":{"format":"double","type":"number"},"jobCPURequest":{"format":"double","type":"number"},"jobMemory":{"format":"double","type":"number"},"jobMemoryLimit":{"format":"double","type":"number"},"jobMemoryRequest":{"format":"double","type":"number"},"jobName":{"type":"string"},"meta":{"additionalProperties":{"type":"string"},"type":"object"},"podCountsByPhase":{"$ref":"#/components/schemas/o11y.PodCountsByPhase"},"successfulPods":{"format":"int64","type":"integer"}},"type":"object"},"o11y.Jobs":{"properties":{"endTimeBeforeRetention":{"type":"boolean"},"records":{"items":{"$ref":"#/components/schemas/o11y.JobRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{},"warning":{"$ref":"#/components/schemas/o11y.QueryWarnData"}},"type":"object"},"o11y.Label":{"properties":{"key":{"$ref":"#/components/schemas/o11y.TelemetryFieldKey"},"value":{}},"type":"object"},"o11y.Limit":{"properties":{"config":{"$ref":"#/components/schemas/o11y.LimitConfig"},"created_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"key_id":{"type":"string"},"metric":{"$ref":"#/components/schemas/o11y.LimitMetric"},"signal":{"description":"\"logs\", \"traces\", \"metrics\"","type":"string"},"tags":{"items":{"type":"string"},"type":"array"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"o11y.LimitConfig":{"properties":{"day":{"$ref":"#/components/schemas/o11y.LimitValue"},"second":{"$ref":"#/components/schemas/o11y.LimitValue"}},"type":"object"},"o11y.LimitMetric":{"properties":{"day":{"$ref":"#/components/schemas/o11y.LimitMetricValue"},"second":{"$ref":"#/components/schemas/o11y.LimitMetricValue"}},"type":"object"},"o11y.LimitMetricValue":{"properties":{"count":{"format":"int64","type":"integer"},"size":{"format":"int64","type":"integer"}},"type":"object"},"o11y.LimitValue":{"properties":{"count":{"format":"int64","type":"integer"},"size":{"format":"int64","type":"integer"}},"type":"object"},"o11y.LogsAssets":{"properties":{"pipelines":{"items":{"$ref":"#/components/schemas/o11y.PostablePipeline"},"type":"array"}},"type":"object"},"o11y.LogsConnectionTest":{"properties":{"attribute_key":{"type":"string"},"attribute_value":{"type":"string"}},"type":"object"},"o11y.MSTeamsConfig":{"properties":{"NotifierConfig":{"$ref":"#/components/schemas/o11y.NotifierConfig"},"http_config":{"$ref":"#/components/schemas/o11y.HTTPClientConfig"},"summary":{"type":"string"},"text":{"type":"string"},"title":{"type":"string"},"webhook_url":{},"webhook_url_file":{"type":"string"}},"type":"object"},"o11y.MSTeamsV2Config":{"properties":{"NotifierConfig":{"$ref":"#/components/schemas/o11y.NotifierConfig"},"http_config":{"$ref":"#/components/schemas/o11y.HTTPClientConfig"},"text":{"type":"string"},"title":{"type":"string"},"webhook_url":{},"webhook_url_file":{"type":"string"}},"type":"object"},"o11y.MattermostAttachment":{"properties":{"author_icon":{"type":"string"},"author_link":{"type":"string"},"author_name":{"type":"string"},"color":{"type":"string"},"fallback":{"type":"string"},"fields":{"items":{"$ref":"#/components/schemas/o11y.MattermostField"},"type":"array"},"footer":{"type":"string"},"footer_icon":{"type":"string"},"image_url":{"type":"string"},"pretext":{"type":"string"},"text":{"type":"string"},"thumb_url":{"type":"string"},"title":{"type":"string"},"title_link":{"type":"string"}},"type":"object"},"o11y.MattermostConfig":{"properties":{"NotifierConfig":{"$ref":"#/components/schemas/o11y.NotifierConfig"},"attachments":{"items":{"$ref":"#/components/schemas/o11y.MattermostAttachment"},"type":"array"},"channel":{"type":"string"},"http_config":{"$ref":"#/components/schemas/o11y.HTTPClientConfig"},"icon_emoji":{"type":"string"},"icon_url":{"type":"string"},"priority":{"$ref":"#/components/schemas/o11y.MattermostPriority"},"props":{"$ref":"#/components/schemas/o11y.MattermostProps"},"text":{"type":"string"},"type":{"type":"string"},"username":{"type":"string"},"webhook_url":{},"webhook_url_file":{"type":"string"}},"type":"object"},"o11y.MattermostField":{"properties":{"short":{"type":"boolean"},"title":{"type":"string"},"value":{"type":"string"}},"type":"object"},"o11y.MattermostPriority":{"properties":{"persistent_notifications":{"type":"boolean"},"priority":{"type":"string"},"requested_ack":{"type":"boolean"}},"type":"object"},"o11y.MattermostProps":{"properties":{"card":{"type":"string"}},"type":"object"},"o11y.MetricsComponentEntry":{"properties":{"associatedComponent":{"$ref":"#/components/schemas/o11y.AssociatedComponent"},"metrics":{"items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.MissingAttributesComponentEntry":{"properties":{"associatedComponent":{"$ref":"#/components/schemas/o11y.AssociatedComponent"},"attributes":{"items":{"type":"string"},"type":"array"},"documentationLink":{"type":"string"},"message":{"type":"string"}},"type":"object"},"o11y.MissingMetricsComponentEntry":{"properties":{"associatedComponent":{"$ref":"#/components/schemas/o11y.AssociatedComponent"},"documentationLink":{"type":"string"},"message":{"type":"string"},"metrics":{"items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.NamespaceListRecord":{"properties":{"countByPhase":{"$ref":"#/components/schemas/o11y.PodCountByPhase"},"cpuUsage":{"format":"double","type":"number"},"memoryUsage":{"format":"double","type":"number"},"meta":{"additionalProperties":{"type":"string"},"type":"object"},"namespaceName":{"type":"string"}},"type":"object"},"o11y.NamespaceListRequest":{"properties":{"end":{"description":"epoch time in ms","format":"int64","type":"integer"},"filters":{"$ref":"#/components/schemas/o11y.FilterSet"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.AttributeKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.OrderBy"},"start":{"description":"epoch time in ms","format":"int64","type":"integer"}},"type":"object"},"o11y.NamespaceListResponse":{"properties":{"records":{"items":{"$ref":"#/components/schemas/o11y.NamespaceListRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{"type":"string"}},"type":"object"},"o11y.NamespaceRecord":{"properties":{"meta":{"additionalProperties":{"type":"string"},"type":"object"},"namespaceCPU":{"format":"double","type":"number"},"namespaceMemory":{"format":"double","type":"number"},"namespaceName":{"type":"string"},"podCountsByPhase":{"$ref":"#/components/schemas/o11y.PodCountsByPhase"}},"type":"object"},"o11y.Namespaces":{"properties":{"endTimeBeforeRetention":{"type":"boolean"},"records":{"items":{"$ref":"#/components/schemas/o11y.NamespaceRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{},"warning":{"$ref":"#/components/schemas/o11y.QueryWarnData"}},"type":"object"},"o11y.NodeCountByCondition":{"properties":{"notReady":{"format":"int64","type":"integer"},"ready":{"format":"int64","type":"integer"},"unknown":{"format":"int64","type":"integer"}},"type":"object"},"o11y.NodeCountsByReadiness":{"properties":{"notReady":{"format":"int64","type":"integer"},"ready":{"format":"int64","type":"integer"}},"type":"object"},"o11y.NodeListRecord":{"properties":{"countByCondition":{"$ref":"#/components/schemas/o11y.NodeCountByCondition"},"meta":{"additionalProperties":{"type":"string"},"type":"object"},"nodeCPUAllocatable":{"format":"double","type":"number"},"nodeCPUUsage":{"format":"double","type":"number"},"nodeMemoryAllocatable":{"format":"double","type":"number"},"nodeMemoryUsage":{"format":"double","type":"number"},"nodeUID":{"type":"string"}},"type":"object"},"o11y.NodeListRequest":{"properties":{"end":{"description":"epoch time in ms","format":"int64","type":"integer"},"filters":{"$ref":"#/components/schemas/o11y.FilterSet"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.AttributeKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.OrderBy"},"start":{"description":"epoch time in ms","format":"int64","type":"integer"}},"type":"object"},"o11y.NodeListResponse":{"properties":{"records":{"items":{"$ref":"#/components/schemas/o11y.NodeListRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{"type":"string"}},"type":"object"},"o11y.NodeRecord":{"properties":{"condition":{},"meta":{"additionalProperties":{"type":"string"},"type":"object"},"nodeCPU":{"format":"double","type":"number"},"nodeCPUAllocatable":{"format":"double","type":"number"},"nodeCountsByReadiness":{"$ref":"#/components/schemas/o11y.NodeCountsByReadiness"},"nodeMemory":{"format":"double","type":"number"},"nodeMemoryAllocatable":{"format":"double","type":"number"},"nodeName":{"type":"string"},"podCountsByPhase":{"$ref":"#/components/schemas/o11y.PodCountsByPhase"}},"type":"object"},"o11y.Nodes":{"properties":{"endTimeBeforeRetention":{"type":"boolean"},"records":{"items":{"$ref":"#/components/schemas/o11y.NodeRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{},"warning":{"$ref":"#/components/schemas/o11y.QueryWarnData"}},"type":"object"},"o11y.NotifierConfig":{"properties":{"send_resolved":{"type":"boolean"}},"type":"object"},"o11y.O11yAPIKey":{"properties":{"createdAt":{"description":"CreatedAt is when the key was minted.","format":"date-time","type":"string"},"expiresAt":{"description":"ExpiresAt is when the key stops working, as a unix timestamp in seconds;\nzero means never.","format":"uint64","type":"integer"},"id":{"description":"ID is the key id.","type":"string"},"lastObservedAt":{"description":"LastObservedAt is when the key was last seen authenticating.","format":"date-time","type":"string"},"name":{"description":"Name is the key's name.","type":"string"},"serviceAccountId":{"description":"ServiceAccountID is the account the key belongs to.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it last changed.","format":"date-time","type":"string"}},"type":"object"},"o11y.O11yAPIKeyCreateIn":{"properties":{"expiresAt":{"description":"ExpiresAt is when the key stops working, as a unix timestamp in seconds.\nZero means it never expires; a past timestamp is refused.","format":"uint64","type":"integer"},"name":{"description":"Name is the key's name: a lowercase letter followed by lowercase letters,\ndigits or hyphens, at most 80 characters. Required.","type":"string"}},"type":"object"},"o11y.O11yAPIKeyCreateOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yAPIKeySecret","description":"Data carries the key's id and secret."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yAPIKeySecret":{"properties":{"id":{"description":"ID is the key id.","type":"string"},"key":{"description":"Key is the secret the service account authenticates with.","type":"string"}},"type":"object"},"o11y.O11yAPIKeyUpdateIn":{"properties":{"expiresAt":{"description":"ExpiresAt is when the key stops working, as a unix timestamp in seconds.\nZero means it never expires; a past timestamp is refused.","format":"uint64","type":"integer"},"name":{"description":"Name is the key's new name, under the same rules it was created with.\nRequired.","type":"string"}},"type":"object"},"o11y.O11yAPIKeysOut":{"properties":{"data":{"description":"Data holds the keys.","items":{"$ref":"#/components/schemas/o11y.O11yAPIKey"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yAccountOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.Account","description":"Data holds the account."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yAccountsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableAccounts","description":"Data holds the connected accounts."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yAffectedAsset":{"properties":{"id":{"description":"ID is the asset's id.","type":"string"},"impactedLabels":{"description":"ImpactedLabels are the rule labels the asset uses.","items":{"type":"string"},"type":"array"},"name":{"description":"Name is the asset's name.","type":"string"},"type":{"description":"Type is dashboard or alert_rule.","type":"string"},"widget":{"$ref":"#/components/schemas/o11y.O11yAffectedWidget","description":"Widget is the affected panel, for a dashboard."}},"type":"object"},"o11y.O11yAffectedWidget":{"properties":{"id":{"description":"ID is the panel's id.","type":"string"},"name":{"description":"Name is the panel's name.","type":"string"}},"type":"object"},"o11y.O11yAgentCheckInIn":{"properties":{"account_id":{"description":"following are backward compatible fields for older running agents, hence snake case JSON keys.\nWhich get mapped to new fields in AgentCheckInRequest","type":"string"},"cloudIntegrationId":{},"cloud_account_id":{"description":"=\u003e ProviderAccountID","type":"string"},"data":{"additionalProperties":{},"type":"object"},"providerAccountId":{"type":"string"}},"type":"object"},"o11y.O11yAgentCheckInOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableAgentCheckIn","description":"Data holds the check-in result."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yAggregateAttributesOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.AggregateAttributeResponse","description":"Data holds the attribute keys."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yAggregation":{"properties":{"alias":{"description":"Alias is the aggregation's alias.","type":"string"},"anomalyScores":{"description":"AnomalyScores are anomaly overlays.","items":{"$ref":"#/components/schemas/o11y.O11yMetricSeries"},"type":"array"},"index":{"description":"Index is the aggregation's position in the query.","format":"int64","type":"integer"},"lowerBoundSeries":{"description":"LowerBoundSeries are forecast lower bounds.","items":{"$ref":"#/components/schemas/o11y.O11yMetricSeries"},"type":"array"},"meta":{"$ref":"#/components/schemas/o11y.O11yAggregationMeta","description":"Meta describes the aggregation."},"predictedSeries":{"description":"PredictedSeries are forecast overlays, when the query asked for them.","items":{"$ref":"#/components/schemas/o11y.O11yMetricSeries"},"type":"array"},"series":{"description":"Series are the aggregated time series.","items":{"$ref":"#/components/schemas/o11y.O11yMetricSeries"},"type":"array"},"upperBoundSeries":{"description":"UpperBoundSeries are forecast upper bounds.","items":{"$ref":"#/components/schemas/o11y.O11yMetricSeries"},"type":"array"}},"type":"object"},"o11y.O11yAggregationMeta":{"properties":{"unit":{"description":"Unit is the aggregation's unit.","type":"string"}},"type":"object"},"o11y.O11yAlertsOut":{"properties":{"data":{"description":"Data holds the alerts.","items":{"$ref":"#/components/schemas/o11y.DeprecatedGettableAlert"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yAnalyzeIn":{"properties":{"query":{"description":"Query is the query text. Required.","type":"string"},"queryType":{"description":"QueryType says which language the query is in — promql or the datastore's\nSQL dialect. Required.","type":"string"}},"required":["query","queryType"],"type":"object"},"o11y.O11yAnalyzeOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yQueryFilterAnalysis","description":"Data is the analysis."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yApdexOut":{"properties":{"data":{"description":"Data holds one settings row per service.","items":{"$ref":"#/components/schemas/o11y.O11yApdexSettings"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yApdexSetIn":{"properties":{"excludeStatusCodes":{"description":"ExcludeStatusCodes are status codes excluded from the score, comma\nseparated.","type":"string"},"serviceName":{"description":"ServiceName is the service the threshold applies to.","type":"string"},"threshold":{"description":"Threshold is the satisfied-response time in seconds.","format":"double","type":"number"}},"type":"object"},"o11y.O11yApdexSetOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yMessage","description":"Data is the acknowledgment."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yApdexSettings":{"properties":{"excludeStatusCodes":{"description":"ExcludeStatusCodes are status codes excluded from the score, comma\nseparated.","type":"string"},"id":{"description":"ID is the settings row's id.","type":"string"},"orgId":{"description":"OrgID is the org the settings belong to.","type":"string"},"serviceName":{"description":"ServiceName is the service.","type":"string"},"threshold":{"description":"Threshold is the satisfied-response time in seconds.","format":"double","type":"number"}},"type":"object"},"o11y.O11yAttributeKey":{"properties":{"dataType":{"description":"DataType is the attribute's value type — string, int64, float64 or bool.","type":"string"},"isColumn":{"description":"IsColumn marks an attribute materialized as its own column.","type":"boolean"},"isJSON":{"description":"IsJSON marks an attribute extracted from a JSON body.","type":"boolean"},"key":{"description":"Key is the attribute's name.","type":"string"},"type":{"description":"Type says where the attribute lives: tag or resource.","type":"string"}},"type":"object"},"o11y.O11yAttributeKeysOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.FilterAttributeKeyResponse","description":"Data holds the attribute keys."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yAttributeValuesOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.FilterAttributeValueResponse","description":"Data holds the values, split by data type."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yChannelOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.Channel","description":"Data holds the channel."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yChannelUpdateIn":{"properties":{"Receiver":{"$ref":"#/components/schemas/o11y.Receiver"},"googlechat_configs":{"items":{"$ref":"#/components/schemas/o11y.GoogleChatReceiverConfig"},"type":"array"}},"type":"object"},"o11y.O11yChannelsOut":{"properties":{"data":{"description":"Data holds the channels.","items":{"$ref":"#/components/schemas/o11y.Channel"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yCheckOut":{"properties":{"data":{"description":"Data holds the verdicts.","items":{"$ref":"#/components/schemas/o11y.O11yTransactionResult"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yClusterListOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.ClusterListResponse","description":"Data holds the cluster records."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yColumnInfo":{"properties":{"columnAlias":{"description":"Alias is the column's alias in the query, when it has one.","type":"string"},"columnName":{"description":"Name is the column's name.","type":"string"}},"type":"object"},"o11y.O11yConnectionStatusOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.IntegrationConnectionStatus","description":"Data holds the logs and metrics connection status."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yCreateAccountIn":{"properties":{"config":{"$ref":"#/components/schemas/o11y.PostableAccountConfig"},"credentials":{"$ref":"#/components/schemas/o11y.Credentials"}},"type":"object"},"o11y.O11yCreateAccountOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableAccountWithConnectionArtifact","description":"Data holds the account and the connection artifact."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yCreateLimitIn":{"properties":{"config":{"$ref":"#/components/schemas/o11y.LimitConfig"},"signal":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.O11yCreated":{"properties":{"id":{"description":"ID is the new record's id.","type":"string"}},"type":"object"},"o11y.O11yCreatedIngestionKeyOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableCreatedIngestionKey","description":"Data holds the created ingestion key."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yCreatedLimitOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableCreatedIngestionKeyLimit","description":"Data holds the created limit."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yCredentialsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.Credentials","description":"Data holds the connection credentials."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yDaemonSetListOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.DaemonSetListResponse","description":"Data holds the daemonset records."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yDashboard":{"properties":{"createdAt":{"description":"CreatedAt is when the dashboard was created.","format":"date-time","type":"string"},"createdBy":{"description":"CreatedBy is who created it.","type":"string"},"id":{"description":"ID is the dashboard's id.","type":"string"},"image":{"description":"Image is an optional cover image reference.","type":"string"},"locked":{"description":"Locked reports whether the dashboard is locked against edits.","type":"boolean"},"name":{"description":"Name is the dashboard's unique internal name.","type":"string"},"orgId":{"description":"OrgID is the org the dashboard belongs to.","type":"string"},"schemaVersion":{"description":"SchemaVersion is the dashboard schema version.","type":"string"},"source":{"description":"Source is where the dashboard came from: user, system or integration.","type":"string"},"spec":{"description":"Spec is the Perses dashboard spec, carried verbatim as open JSON."},"tags":{"description":"Tags are the dashboard's tags.","items":{"$ref":"#/components/schemas/o11y.O11yDashboardTag"},"type":"array"},"updatedAt":{"description":"UpdatedAt is when it last changed.","format":"date-time","type":"string"},"updatedBy":{"description":"UpdatedBy is who last changed it.","type":"string"}},"type":"object"},"o11y.O11yDashboardDisplay":{"properties":{"description":{"description":"Description says what the dashboard is for.","type":"string"},"name":{"description":"Name is the human-facing dashboard name.","type":"string"}},"type":"object"},"o11y.O11yDashboardList":{"properties":{"dashboards":{"description":"Dashboards are the rows for this page.","items":{"$ref":"#/components/schemas/o11y.O11yDashboardListItem"},"type":"array"},"tags":{"description":"Tags are all tags in use across the org's dashboards.","items":{"$ref":"#/components/schemas/o11y.O11yDashboardTag"},"type":"array"},"total":{"description":"Total is the count across all pages.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yDashboardListForUser":{"properties":{"dashboards":{"description":"Dashboards are the rows for this page, each with the caller's pin state.","items":{"$ref":"#/components/schemas/o11y.O11yDashboardListItemForUser"},"type":"array"},"tags":{"description":"Tags are all tags in use across the org's dashboards.","items":{"$ref":"#/components/schemas/o11y.O11yDashboardTag"},"type":"array"},"total":{"description":"Total is the count across all pages.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yDashboardListForUserOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yDashboardListForUser","description":"Data is the list page with pins."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yDashboardListItem":{"properties":{"createdAt":{"description":"CreatedAt is when the dashboard was created.","format":"date-time","type":"string"},"createdBy":{"description":"CreatedBy is who created it.","type":"string"},"id":{"description":"ID is the dashboard's id.","type":"string"},"image":{"description":"Image is an optional cover image reference.","type":"string"},"locked":{"description":"Locked reports whether the dashboard is locked against edits.","type":"boolean"},"name":{"description":"Name is the dashboard's unique internal name.","type":"string"},"orgId":{"description":"OrgID is the org the dashboard belongs to.","type":"string"},"schemaVersion":{"description":"SchemaVersion is the dashboard schema version.","type":"string"},"source":{"description":"Source is where the dashboard came from: user, system or integration.","type":"string"},"spec":{"$ref":"#/components/schemas/o11y.O11yDashboardListSpec","description":"Spec is the display-only slice of the dashboard spec."},"tags":{"description":"Tags are the dashboard's tags.","items":{"$ref":"#/components/schemas/o11y.O11yDashboardTag"},"type":"array"},"updatedAt":{"description":"UpdatedAt is when it last changed.","format":"date-time","type":"string"},"updatedBy":{"description":"UpdatedBy is who last changed it.","type":"string"}},"type":"object"},"o11y.O11yDashboardListItemForUser":{"properties":{"createdAt":{"description":"CreatedAt is when the dashboard was created.","format":"date-time","type":"string"},"createdBy":{"description":"CreatedBy is who created it.","type":"string"},"id":{"description":"ID is the dashboard's id.","type":"string"},"image":{"description":"Image is an optional cover image reference.","type":"string"},"locked":{"description":"Locked reports whether the dashboard is locked against edits.","type":"boolean"},"name":{"description":"Name is the dashboard's unique internal name.","type":"string"},"orgId":{"description":"OrgID is the org the dashboard belongs to.","type":"string"},"pinned":{"description":"Pinned reports whether the calling user has pinned this dashboard.","type":"boolean"},"schemaVersion":{"description":"SchemaVersion is the dashboard schema version.","type":"string"},"source":{"description":"Source is where the dashboard came from: user, system or integration.","type":"string"},"spec":{"$ref":"#/components/schemas/o11y.O11yDashboardListSpec","description":"Spec is the display-only slice of the dashboard spec."},"tags":{"description":"Tags are the dashboard's tags.","items":{"$ref":"#/components/schemas/o11y.O11yDashboardTag"},"type":"array"},"updatedAt":{"description":"UpdatedAt is when it last changed.","format":"date-time","type":"string"},"updatedBy":{"description":"UpdatedBy is who last changed it.","type":"string"}},"type":"object"},"o11y.O11yDashboardListOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yDashboardList","description":"Data is the list page."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yDashboardListSpec":{"properties":{"display":{"$ref":"#/components/schemas/o11y.O11yDashboardDisplay","description":"Display is the dashboard's display metadata."}},"type":"object"},"o11y.O11yDashboardOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yDashboard","description":"Data is the dashboard."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yDashboardPatchIn":{"properties":{"id":{"description":"ID is the dashboard id from the path.","type":"string"},"ops":{"description":"Ops are the JSON Patch operations, applied in order. On the wire this IS the\nrequest body — a bare array, not an object.","items":{"$ref":"#/components/schemas/o11y.O11yDashboardPatchOp"},"type":"array"}},"type":"object"},"o11y.O11yDashboardPatchOp":{"properties":{"from":{"description":"From is the source JSON Pointer for move and copy; ignored otherwise.","type":"string"},"op":{"description":"Op is the verb: add, remove, replace, move, copy or test.","type":"string"},"path":{"description":"Path is a JSON Pointer into the postable dashboard, e.g.\n/spec/display/name, /spec/panels/\u003cid\u003e, /tags/-.","type":"string"},"value":{"description":"Value is the value to add/replace/test; its type depends on Path. Required\nfor add, replace and test; ignored otherwise."}},"type":"object"},"o11y.O11yDashboardPostable":{"properties":{"generateName":{"description":"GenerateName derives a fresh unique name from spec.display.name instead of\ntaking Name.","type":"boolean"},"image":{"description":"Image is an optional cover image reference.","type":"string"},"name":{"description":"Name is the dashboard's unique internal name (a DNS-1123 label). Omit it\nwith generateName to derive one from the display name.","type":"string"},"schemaVersion":{"description":"SchemaVersion is the dashboard schema version; must be the current v6.","type":"string"},"spec":{"description":"Spec is the Perses dashboard spec (display, variables, panels, layouts,\ndatasources). Its plugin-defined leaves are open JSON, carried verbatim."},"tags":{"description":"Tags are the dashboard's tags; at most ten, and none may use a reserved DSL\nkey.","items":{"$ref":"#/components/schemas/o11y.O11yDashboardPostableTag"},"type":"array"}},"type":"object"},"o11y.O11yDashboardPostableTag":{"properties":{"key":{"description":"Key is the tag key.","type":"string"},"value":{"description":"Value is the tag value.","type":"string"}},"type":"object"},"o11y.O11yDashboardTag":{"properties":{"key":{"description":"Key is the tag key.","type":"string"},"value":{"description":"Value is the tag value.","type":"string"}},"type":"object"},"o11y.O11yDashboardUpdateIn":{"properties":{"id":{"description":"ID is the dashboard id from the path.","type":"string"},"image":{"description":"Image is an optional cover image reference.","type":"string"},"name":{"description":"Name must equal the dashboard's existing name — it is immutable.","type":"string"},"schemaVersion":{"description":"SchemaVersion is the dashboard schema version; must be the current v6.","type":"string"},"spec":{"description":"Spec is the replacement Perses spec, carried verbatim as open JSON."},"tags":{"description":"Tags replace the dashboard's tags; at most ten.","items":{"$ref":"#/components/schemas/o11y.O11yDashboardPostableTag"},"type":"array"}},"type":"object"},"o11y.O11yDashboardVarValues":{"properties":{"variableValues":{"description":"VariableValues are the values, in the order the query produced them.","items":{},"type":"array"}},"type":"object"},"o11y.O11yDashboardVarsIn":{"properties":{"query":{"description":"Query is the variable query to evaluate. Required.","type":"string"},"variables":{"additionalProperties":{},"description":"Variables are the current values of the other dashboard variables, for\nqueries that reference them.","type":"object"}},"required":["query"],"type":"object"},"o11y.O11yDashboardVarsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yDashboardVarValues","description":"Data holds the values."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yDashboardView":{"properties":{"createdAt":{"description":"CreatedAt is when the view was created.","format":"date-time","type":"string"},"data":{"$ref":"#/components/schemas/o11y.O11yDashboardViewData","description":"Data is the listing state the view captures."},"id":{"description":"ID is the saved view's id.","type":"string"},"name":{"description":"Name is the saved view's name.","type":"string"},"orgId":{"description":"OrgID is the org the view belongs to.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it last changed.","format":"date-time","type":"string"}},"type":"object"},"o11y.O11yDashboardViewData":{"properties":{"order":{"description":"Order is the captured sort direction.","type":"string"},"query":{"description":"Query is the captured filter DSL.","type":"string"},"sort":{"description":"Sort is the captured sort field.","type":"string"},"version":{"description":"Version is the saved-view schema version; must be v1.","type":"string"}},"type":"object"},"o11y.O11yDashboardViewList":{"properties":{"views":{"description":"Views are the saved views, shared org-wide.","items":{"$ref":"#/components/schemas/o11y.O11yDashboardView"},"type":"array"}},"type":"object"},"o11y.O11yDashboardViewListOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yDashboardViewList","description":"Data is the saved views."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yDashboardViewOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yDashboardView","description":"Data is the saved view."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yDashboardViewPostable":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yDashboardViewData","description":"Data is the listing state the view captures."},"name":{"description":"Name is the saved view's name; at most 32 characters, no surrounding space.","type":"string"}},"type":"object"},"o11y.O11yDashboardViewUpdateIn":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yDashboardViewData","description":"Data is the listing state the view captures."},"id":{"description":"ID is the saved view id from the path.","type":"string"},"name":{"description":"Name is the saved view's name; at most 32 characters, no surrounding space.","type":"string"}},"type":"object"},"o11y.O11yDependency":{"properties":{"callCount":{"description":"CallCount is how many calls crossed the edge in the window.","format":"uint64","type":"integer"},"callRate":{"description":"CallRate is calls per second.","format":"double","type":"number"},"child":{"description":"Child is the called service.","type":"string"},"errorRate":{"description":"ErrorRate is the percentage of calls that erred.","format":"double","type":"number"},"p50":{"description":"P50 is the median call duration, in nanoseconds.","format":"double","type":"number"},"p75":{"description":"P75 is the 75th-percentile call duration, in nanoseconds.","format":"double","type":"number"},"p90":{"description":"P90 is the 90th-percentile call duration, in nanoseconds.","format":"double","type":"number"},"p95":{"description":"P95 is the 95th-percentile call duration, in nanoseconds.","format":"double","type":"number"},"p99":{"description":"P99 is the 99th-percentile call duration, in nanoseconds.","format":"double","type":"number"},"parent":{"description":"Parent is the calling service.","type":"string"}},"type":"object"},"o11y.O11yDependencyGraphIn":{"properties":{"end":{"description":"End is the window end, as epoch nanoseconds. Required.","type":"string"},"start":{"description":"Start is the window start, as epoch nanoseconds. Required.","type":"string"},"tags":{"description":"Tags narrow the graph to spans matching every condition.","items":{"$ref":"#/components/schemas/o11y.O11yTagFilter"},"type":"array"}},"required":["start","end"],"type":"object"},"o11y.O11yDeploymentListOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.DeploymentListResponse","description":"Data holds the deployment records."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yDiscoverIn":{"properties":{"aggregations":{"description":"Aggregations are the measures to compute per group. Empty means a count.","items":{"type":"string"},"type":"array"},"filters":{"description":"Filters narrow the scan; each is a field, an operator (eq, neq, like) and\na value, and they combine with AND.","items":{"$ref":"#/components/schemas/o11y.O11yFilter"},"type":"array"},"groupBy":{"description":"GroupBy are the columns to group the rows by.","items":{"type":"string"},"type":"array"},"limit":{"description":"Limit caps how many rows come back.","format":"int64","type":"integer"},"orderBy":{"description":"OrderBy is the column or aggregation to sort the rows on.","type":"string"},"orderDir":{"description":"OrderDir is asc or desc.","type":"string"},"period":{"description":"Period is the window to read, relative to now — 1h, 24h, 7d, 14d, 30d.","type":"string"},"project":{"description":"Project is the project to read, as its id. Required.","type":"string"}},"required":["project"],"type":"object"},"o11y.O11yDiscoverOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yTable","description":"Data is the table."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yDisk":{"properties":{"name":{"description":"Name is the disk's name.","type":"string"},"type":{"description":"Type is the disk's type, e.g. local or s3.","type":"string"}},"type":"object"},"o11y.O11yDomainFilter":{"properties":{"expression":{"description":"Expression is the predicate, e.g. `http.status_code \u003e= 500`.","type":"string"}},"type":"object"},"o11y.O11yDomainGroupBy":{"properties":{"description":{"description":"Description describes the field, when known.","type":"string"},"fieldContext":{"description":"FieldContext says which plane the field lives on, e.g. attribute,\nresource, span.","type":"string"},"fieldDataType":{"description":"FieldDataType is the field's type: string, int64, float64 or bool.","type":"string"},"name":{"description":"Name is the field's name. Required.","type":"string"},"signal":{"description":"Signal is the telemetry signal the field belongs to, e.g. traces.","type":"string"},"unit":{"description":"Unit is the field's unit, when known.","type":"string"}},"type":"object"},"o11y.O11yDomainsAnswer":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yDomainsData","description":"Data holds the per-query results, emitted LAST — see the field-order note\non the type."},"meta":{"$ref":"#/components/schemas/o11y.O11yQueryStats","description":"Meta reports what the read cost."},"type":{"description":"Type names the result shape: scalar, time_series or raw.","type":"string"},"warning":{"$ref":"#/components/schemas/o11y.O11yQueryWarning","description":"Warning carries the store's warning for this read, when it raised one."}},"type":"object"},"o11y.O11yDomainsData":{"properties":{"results":{"description":"Results is one entry per query. Each entry's shape follows the answer's\ntype — time-series data, scalar data or raw rows — so the bytes pass\nthrough verbatim.","items":{},"type":"array"}},"type":"object"},"o11y.O11yDomainsIn":{"properties":{"domain":{"description":"Domain narrows the read to one external domain (the domain view requires\nit).","type":"string"},"end":{"description":"End is the window's end, epoch milliseconds.","format":"uint64","type":"integer"},"endpoint":{"description":"Endpoint narrows the domain view to one endpoint.","type":"string"},"filter":{"$ref":"#/components/schemas/o11y.O11yDomainFilter","description":"Filter is an additional predicate in the query-builder filter syntax."},"groupBy":{"description":"GroupBy adds grouping columns to the result.","items":{"$ref":"#/components/schemas/o11y.O11yDomainGroupBy"},"type":"array"},"show_ip":{"description":"ShowIP keeps rows whose domain is a bare IP address; they are dropped\notherwise.","type":"boolean"},"start":{"description":"Start is the window's start, epoch milliseconds.","format":"uint64","type":"integer"}},"type":"object"},"o11y.O11yDomainsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yDomainsAnswer","description":"Data holds the result."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yDowntimeScheduleOut":{"properties":{"data":{"description":"Data holds the schedule."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yDowntimeSchedulesOut":{"properties":{"data":{"description":"Data holds the schedules.","items":{},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yDowntimeUpdateIn":{"properties":{"alertIds":{"items":{"type":"string"},"type":"array"},"description":{"type":"string"},"name":{"type":"string"},"schedule":{},"scope":{"type":"string"}},"type":"object"},"o11y.O11yDraftFunnelIn":{"properties":{"end_time":{"description":"EndTime is the end of the window, as a millisecond epoch.","format":"int64","type":"integer"},"start_time":{"description":"StartTime is the start of the window, as a millisecond epoch.","format":"int64","type":"integer"},"step_end":{"description":"StepEnd is the step the transition runs to, 1-based.","format":"int64","type":"integer"},"step_start":{"description":"StepStart is the step the transition runs from, 1-based. Ignored by the\nreads that span the whole funnel.","format":"int64","type":"integer"},"steps":{"description":"Steps are the funnel's steps, in order. At least two are needed.","items":{"$ref":"#/components/schemas/o11y.FunnelStep"},"type":"array"}},"type":"object"},"o11y.O11yErrorGettableIssue":{"properties":{"issue":{"$ref":"#/components/schemas/o11y.O11yErrorIssue","description":"Issue is the lifecycle row."},"latestEvent":{"$ref":"#/components/schemas/o11y.O11yOccurrence","description":"LatestEvent is the most recent occurrence that landed on the issue."}},"type":"object"},"o11y.O11yErrorGettableIssueOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yErrorGettableIssue","description":"Data is the issue and its latest occurrence."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yErrorIssue":{"properties":{"assignee":{"description":"Assignee is who the issue is assigned to.","type":"string"},"count":{"description":"Count is how many occurrences have landed on the issue.","format":"int64","type":"integer"},"createdAt":{"description":"CreatedAt is when the issue was first recorded.","format":"date-time","type":"string"},"culprit":{"description":"Culprit is where it came from — the function or route blamed for it.","type":"string"},"environment":{"description":"Environment is the deployment the issue was seen in.","type":"string"},"fingerprint":{"description":"Fingerprint is the grouping key that puts like errors in one issue.","type":"string"},"firstSeen":{"description":"FirstSeen is when the earliest occurrence was recorded.","format":"date-time","type":"string"},"id":{"description":"ID is the issue id.","type":"string"},"lastSeen":{"description":"LastSeen is when the latest was.","format":"date-time","type":"string"},"level":{"description":"Level is the issue's severity, e.g. error, warning, info.","type":"string"},"platform":{"description":"Platform is the reporting runtime, e.g. go, python, javascript.","type":"string"},"regressed":{"description":"Regressed marks an issue that reopened after being resolved.","type":"boolean"},"release":{"description":"Release is the version that produced it.","type":"string"},"resolvedAt":{"description":"ResolvedAt is when the issue was resolved, if it is.","format":"date-time","type":"string"},"serviceName":{"description":"ServiceName is the service that reported it.","type":"string"},"status":{"description":"Status is the lifecycle state: unresolved, resolved or ignored.","type":"string"},"type":{"description":"Type is the exception type.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the issue last changed.","format":"date-time","type":"string"},"value":{"description":"Value is the exception value.","type":"string"}},"type":"object"},"o11y.O11yErrorIssueOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yErrorIssue","description":"Data is the issue."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yErrorIssues":{"properties":{"items":{"description":"Items are the issues.","items":{"$ref":"#/components/schemas/o11y.O11yErrorIssue"},"type":"array"},"limit":{"description":"Limit is the page cap that was applied.","format":"int64","type":"integer"},"offset":{"description":"Offset is how many were skipped.","format":"int64","type":"integer"},"total":{"description":"Total is how many matched the filter.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yErrorIssuesOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yErrorIssues","description":"Data holds the issues."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yErrorUpdateIssueIn":{"properties":{"assignee":{"description":"Assignee is who the issue is assigned to.","type":"string"},"id":{"description":"ID is the issue id.","type":"string"},"status":{"description":"Status is the new lifecycle state: unresolved, resolved or ignored.","type":"string"}},"required":["id"],"type":"object"},"o11y.O11yErrorWithSpan":{"properties":{"errorId":{"description":"ErrorID is the exception instance id.","type":"string"},"exceptionEscaped":{"description":"ExceptionEscaped marks an exception that escaped its span uncaught.","type":"boolean"},"exceptionMessage":{"description":"ExceptionMsg is the exception's message.","type":"string"},"exceptionStacktrace":{"description":"ExceptionStacktrace is the captured stack trace.","type":"string"},"exceptionType":{"description":"ExceptionType is the exception's type.","type":"string"},"groupID":{"description":"GroupID is the exception group it belongs to.","type":"string"},"serviceName":{"description":"ServiceName is the service that reported it.","type":"string"},"spanID":{"description":"SpanID is the span it happened on.","type":"string"},"timestamp":{"description":"Timestamp is when it happened.","format":"date-time","type":"string"},"traceID":{"description":"TraceID is the trace the span belonged to.","type":"string"}},"type":"object"},"o11y.O11yErrorsCountIn":{"properties":{"end":{"description":"End is the window end, as a nanosecond epoch spelled as a string.","type":"string"},"exceptionType":{"description":"ExceptionType narrows to one exception type.","type":"string"},"serviceName":{"description":"ServiceName narrows to one reporting service.","type":"string"},"start":{"description":"Start is the window start, as a nanosecond epoch spelled as a string.","type":"string"},"tags":{"description":"Tags narrow the scan to spans carrying the given tag values.","items":{"$ref":"#/components/schemas/o11y.O11yTagQuery"},"type":"array"}},"type":"object"},"o11y.O11yErrorsListIn":{"properties":{"end":{"description":"End is the window end, as a nanosecond epoch spelled as a string.","type":"string"},"exceptionType":{"description":"ExceptionType narrows to one exception type.","type":"string"},"limit":{"description":"Limit caps how many exception groups come back. Required, non-zero.","format":"int64","type":"integer"},"offset":{"description":"Offset is how many groups to skip.","format":"int64","type":"integer"},"order":{"description":"Order is the direction: ascending or descending.","type":"string"},"orderParam":{"description":"OrderParam is the column to order by, e.g. exceptionCount, lastSeen.","type":"string"},"serviceName":{"description":"ServiceName narrows to one reporting service.","type":"string"},"start":{"description":"Start is the window start, as a nanosecond epoch spelled as a string.","type":"string"},"tags":{"description":"Tags narrow the scan to spans carrying the given tag values.","items":{"$ref":"#/components/schemas/o11y.O11yTagQuery"},"type":"array"}},"type":"object"},"o11y.O11yEvent":{"properties":{"culprit":{"description":"Culprit is where it came from — the function or route blamed for it.","type":"string"},"environment":{"description":"Environment is the deployment it happened in.","type":"string"},"eventId":{"description":"EventID is its own id.","type":"string"},"fingerprint":{"description":"Fingerprint is the grouping key that puts like errors in one issue.","type":"string"},"frames":{"description":"Frames are the stack, innermost first.","items":{"$ref":"#/components/schemas/o11y.O11yFrame"},"type":"array"},"handled":{"description":"Handled says whether the application caught it.","type":"boolean"},"level":{"description":"Level is its severity, e.g. error, warning, info.","type":"string"},"message":{"description":"Message is the human-readable message.","type":"string"},"orgId":{"description":"OrgID is the org that owns it.","type":"string"},"platform":{"description":"Platform is the reporting runtime, e.g. go, python, javascript.","type":"string"},"projectId":{"description":"ProjectID is the project it was captured for.","type":"string"},"receivedAt":{"description":"ReceivedAt is when it arrived here.","format":"date-time","type":"string"},"release":{"description":"Release is the version that produced it.","type":"string"},"serverName":{"description":"ServerName is the host that reported it.","type":"string"},"serviceName":{"description":"ServiceName is the service that reported it.","type":"string"},"spanId":{"description":"SpanID is the span it belonged to.","type":"string"},"tags":{"additionalProperties":{"type":"string"},"description":"Tags are the reporter's own key/value labels.","type":"object"},"timestamp":{"description":"Timestamp is when the error happened, as the reporter recorded it.","format":"date-time","type":"string"},"traceId":{"description":"TraceID is the trace it belonged to.","type":"string"},"transaction":{"description":"Transaction is the operation it happened in.","type":"string"},"type":{"description":"Type is the exception type.","type":"string"},"userEmail":{"description":"UserEmail is that user's email, when attached.","type":"string"},"userId":{"description":"UserID identifies the affected end user, when the reporter attached one.","type":"string"},"userIp":{"description":"UserIP is that user's address, when attached.","type":"string"},"value":{"description":"Value is the exception value.","type":"string"}},"type":"object"},"o11y.O11yEventIn":{"properties":{"attributes":{"additionalProperties":{},"description":"Attributes are free-form event properties.","type":"object"},"eventName":{"description":"EventName names the event; required for track events.","type":"string"},"eventType":{"description":"EventType is the kind of event — track, identify or group. Required.","type":"string"},"rateLimited":{"description":"RateLimited marks an event the reporting client rate-limited.","type":"boolean"}},"required":["eventType"],"type":"object"},"o11y.O11yEventUser":{"properties":{"email":{"description":"Email is that user's email.","type":"string"},"id":{"description":"ID identifies the affected end user.","type":"string"},"ipAddress":{"description":"IP is that user's address.","type":"string"},"username":{"description":"Username is that user's name.","type":"string"}},"type":"object"},"o11y.O11yEvents":{"properties":{"items":{"description":"Items are the events, newest first.","items":{"$ref":"#/components/schemas/o11y.O11yEvent"},"type":"array"}},"type":"object"},"o11y.O11yFeature":{"properties":{"defaultVariant":{"description":"DefaultVariant is the variant used when nothing overrides it.","type":"string"},"description":{"description":"Description says what the flag gates.","type":"string"},"kind":{"description":"Kind is the flag's value kind, e.g. boolean.","type":"string"},"name":{"description":"Name is the flag's name.","type":"string"},"resolvedValue":{"description":"ResolvedValue is the value resolved for the caller's org."},"stage":{"description":"Stage is the flag's lifecycle stage, e.g. stable.","type":"string"},"variants":{"additionalProperties":{},"description":"Variants are the flag's possible values, by variant name.","type":"object"}},"type":"object"},"o11y.O11yFeaturesOut":{"properties":{"data":{"description":"Data are the features.","items":{"$ref":"#/components/schemas/o11y.O11yFeature"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yFieldCatalogOut":{"properties":{"interesting":{"description":"Interesting are fields seen in the data that could be selected.","items":{"$ref":"#/components/schemas/o11y.O11yTelemetryField"},"type":"array"},"selected":{"description":"Selected are the fields materialized as their own columns.","items":{"$ref":"#/components/schemas/o11y.O11yTelemetryField"},"type":"array"}},"type":"object"},"o11y.O11yFieldKeysOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableFieldKeys","description":"Data holds the field keys grouped by name, and whether the catalog is\ncomplete."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yFieldSetting":{"properties":{"dataType":{"description":"DataType is the field's data type, e.g. string, int64, float64, bool.\nRequired.","type":"string"},"index":{"description":"Index is the index expression to put on the column, e.g. minmax,\nset(N), bloom_filter(P), tokenbf_v1(S,H,SEED). Empty keeps the default.","type":"string"},"indexGranularity":{"description":"IndexGranularity is the index granularity in rows.","format":"int64","type":"integer"},"name":{"description":"Name is the field to tune. Required.","type":"string"},"selected":{"description":"Selected materializes the field as its own column when true.","type":"boolean"},"type":{"description":"Type is where the field lives: attributes or resources. Required.","type":"string"}},"required":["name","dataType","type"],"type":"object"},"o11y.O11yFieldValuesOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableFieldValues","description":"Data holds the values by data type, and whether the value list is complete."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yFilter":{"properties":{"field":{"description":"Field is the column to test.","type":"string"},"op":{"description":"Op is how to test it: eq, neq or like.","type":"string"},"value":{"description":"Value is what to test it against.","type":"string"}},"type":"object"},"o11y.O11yFilterItem":{"properties":{"key":{"$ref":"#/components/schemas/o11y.O11yAttributeKey","description":"Key is the attribute tested."},"op":{"description":"Operator is the comparison, e.g. =, !=, in, contains.","type":"string"},"value":{"description":"Value is what it is tested against; its type follows the attribute's."}},"type":"object"},"o11y.O11yFilterKey":{"properties":{"dataType":{"description":"DataType is the attribute's value type — string, int64, float64 or bool.","type":"string"},"isColumn":{"description":"IsColumn marks an attribute stored as its own column.","type":"boolean"},"isJSON":{"description":"IsJSON marks an attribute read out of a JSON body.","type":"boolean"},"key":{"description":"Key is the attribute name.","type":"string"},"type":{"description":"Type says where the attribute lives — tag or resource.","type":"string"}},"type":"object"},"o11y.O11yFilterSet":{"properties":{"items":{"description":"Items are the conditions.","items":{"$ref":"#/components/schemas/o11y.O11yFilterItem"},"type":"array"},"op":{"description":"Operator combines the items — AND or OR.","type":"string"}},"type":"object"},"o11y.O11yFilterSuggestions":{"properties":{"attributes":{"description":"Attributes are the suggested attribute keys.","items":{"$ref":"#/components/schemas/o11y.O11yAttributeKey"},"type":"array"},"example_queries":{"description":"ExampleQueries are ready-to-run filter sets.","items":{"$ref":"#/components/schemas/o11y.O11yFilterSet"},"type":"array"}},"type":"object"},"o11y.O11yFilterSuggestionsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yFilterSuggestions","description":"Data holds the suggestions."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yFrame":{"properties":{"column":{"description":"Column is the column number.","format":"uint32","type":"integer"},"file":{"description":"File is the file it is in.","type":"string"},"function":{"description":"Function is the function the frame is in.","type":"string"},"line":{"description":"Line is the line number.","format":"uint32","type":"integer"},"own":{"description":"Own marks a frame in the reporting application's own code rather than in a\ndependency or the runtime.","type":"boolean"}},"type":"object"},"o11y.O11yFunnelCreateIn":{"properties":{"funnel_name":{"description":"Name is the funnel's name.","type":"string"},"timestamp":{"description":"Timestamp is when the funnel was created, as a millisecond epoch. Zero\ntakes the runtime's own clock.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yFunnelDeleteOut":{"properties":{"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yFunnelOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableFunnel","description":"Data is the funnel with its steps."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yFunnelRow":{"properties":{"data":{"additionalProperties":{},"description":"Data are the row's columns, keyed by column name.","type":"object"},"timestamp":{"description":"Timestamp is the row's time.","type":"string"}},"type":"object"},"o11y.O11yFunnelRowsOut":{"properties":{"data":{"description":"Data are the rows.","items":{"$ref":"#/components/schemas/o11y.O11yFunnelRow"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yFunnelStepWindowIn":{"properties":{"end_time":{"format":"int64","type":"integer"},"start_time":{"format":"int64","type":"integer"},"step_end":{"format":"int64","type":"integer"},"step_start":{"format":"int64","type":"integer"}},"type":"object"},"o11y.O11yFunnelStepsUpdateIn":{"properties":{"description":{"description":"Description replaces the funnel's description. Empty leaves it as it was.","type":"string"},"funnel_id":{"description":"FunnelID is the funnel to update.","type":"string"},"funnel_name":{"description":"Name replaces the funnel's name. Empty leaves it as it was.","type":"string"},"steps":{"description":"Steps are the funnel's steps, in order. At least two are needed before\nany analytics read will answer.","items":{"$ref":"#/components/schemas/o11y.FunnelStep"},"type":"array"},"timestamp":{"description":"Timestamp is when the change was made, as a millisecond epoch.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yFunnelUpdateIn":{"properties":{"description":{"description":"Description replaces the funnel's description. Empty leaves it as it was.","type":"string"},"funnel_name":{"description":"Name replaces the funnel's name. Empty leaves it as it was.","type":"string"},"timestamp":{"description":"Timestamp is when the change was made, as a millisecond epoch.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yFunnelWindowIn":{"properties":{"end_time":{"format":"int64","type":"integer"},"start_time":{"format":"int64","type":"integer"}},"type":"object"},"o11y.O11yFunnelsOut":{"properties":{"data":{"description":"Data are the funnels.","items":{"$ref":"#/components/schemas/o11y.GettableFunnel"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yGettableHostOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableHost","description":"Data holds the host info."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yGlobalConfig":{"properties":{"ai_assistant_url":{"description":"AIAssistantURL is the AI assistant endpoint, when one is exposed.","type":"string"},"external_url":{"description":"ExternalURL is the deployment's public URL.","type":"string"},"identN":{"$ref":"#/components/schemas/o11y.O11yIdentN","description":"IdentN says which identity providers are enabled."},"ingestion_url":{"description":"IngestionURL is where telemetry is sent.","type":"string"},"mcp_url":{"description":"MCPURL is the MCP endpoint, when one is exposed.","type":"string"}},"type":"object"},"o11y.O11yGlobalConfigOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yGlobalConfig","description":"Data is the configuration."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yHealthOut":{"properties":{"status":{"description":"Status is \"ok\".","type":"string"}},"type":"object"},"o11y.O11yHostListOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.HostListResponse","description":"Data holds the host records and the fleet's reporting state."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yIdentN":{"properties":{"apikey":{"$ref":"#/components/schemas/o11y.O11yToggle","description":"APIKey is the API-key provider."},"impersonation":{"$ref":"#/components/schemas/o11y.O11yToggle","description":"Impersonation is the impersonation provider."},"tokenizer":{"$ref":"#/components/schemas/o11y.O11yToggle","description":"Tokenizer is the token-based provider."}},"type":"object"},"o11y.O11yIdentifiable":{"properties":{"id":{"description":"ID is the created resource's id.","type":"string"}},"type":"object"},"o11y.O11yIdentifiableOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yIdentifiable","description":"Data is the created resource's id."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yInfraAttributeKeysOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.FilterAttributeKeyResponse","description":"Data holds the keys."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yInfraAttributeValuesOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.FilterAttributeValueResponse","description":"Data holds the values, split by data type."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yInfraChecksOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.Checks","description":"Data holds what is present, what is missing and whether the section is\nready."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yInfraClustersOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.Clusters","description":"Data holds the rows."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yInfraDaemonSetsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.DaemonSets","description":"Data holds the rows."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yInfraDeploymentsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.Deployments","description":"Data holds the rows."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yInfraHostsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.Hosts","description":"Data holds the rows."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yInfraJobsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.Jobs","description":"Data holds the rows."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yInfraNamespacesOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.Namespaces","description":"Data holds the rows."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yInfraNodesOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.Nodes","description":"Data holds the rows."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yInfraPodsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.Pods","description":"Data holds the rows."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yInfraStatefulSetsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.StatefulSets","description":"Data holds the rows."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yInfraVolumesOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.Volumes","description":"Data holds the rows."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yIngestionKeysOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableIngestionKeys","description":"Data holds the ingestion keys."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yInstallOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.IntegrationsListItem","description":"Data holds the installed integration."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yIntegrationAck":{"properties":{"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yIntegrationOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.Integration","description":"Data holds the integration and its installation record."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yIntegrationsListOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.IntegrationsListResponse","description":"Data holds the available integrations and their installed state."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yJobListOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.JobListResponse","description":"Data holds the job records."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yK8sOnboarding":{"properties":{"didSendClusterMetrics":{"description":"DidSendClusterMetrics says whether cluster metrics have arrived.","type":"boolean"},"didSendNodeMetrics":{"description":"DidSendNodeMetrics says whether node metrics have arrived.","type":"boolean"},"didSendPodMetrics":{"description":"DidSendPodMetrics says whether pod metrics have arrived.","type":"boolean"},"isSendingOptionalPodMetrics":{"description":"IsSendingOptionalPodMetrics says whether optional pod metrics are\nflowing.","type":"boolean"},"isSendingRequiredMetadata":{"description":"IsSendingRequiredMetadata reports, per pod, which required metadata\nlabels are present.","items":{"$ref":"#/components/schemas/o11y.O11yPodOnboarding"},"type":"array"}},"type":"object"},"o11y.O11yLLMAnnotation":{"properties":{"author":{"description":"Author is who wrote it.","type":"string"},"content":{"description":"Content is the note itself.","type":"string"},"createdAt":{"description":"CreatedAt is when the annotation was stored.","format":"date-time","type":"string"},"id":{"description":"ID is the annotation's id.","type":"string"},"observationId":{"description":"ObservationID is the observation the annotation attaches to, when narrowed.","type":"string"},"queue":{"description":"Queue is the review queue the annotation sits in, when queued.","type":"string"},"status":{"description":"Status is the annotation's review status, e.g. PENDING.","type":"string"},"traceId":{"description":"TraceID is the trace the annotation attaches to.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the annotation last changed.","format":"date-time","type":"string"}},"type":"object"},"o11y.O11yLLMAnnotationOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yLLMAnnotation","description":"Data is the annotation."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yLLMAnnotationsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yLLMAnnotationsPage","description":"Data is the page."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yLLMAnnotationsPage":{"properties":{"items":{"description":"Items are the annotations, newest first.","items":{"$ref":"#/components/schemas/o11y.O11yLLMAnnotation"},"type":"array"},"limit":{"description":"Limit is the page cap the read ran with.","format":"int64","type":"integer"},"offset":{"description":"Offset is the row offset this page started at.","format":"int64","type":"integer"},"total":{"description":"Total is how many annotations match, across all pages.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yLLMIngestAnnotation":{"properties":{"content":{"description":"Content is the note itself. Required.","type":"string"},"observationId":{"description":"ObservationID is the single observation the annotation attaches to, when\nnarrowed to one.","type":"string"},"queue":{"description":"Queue is the review queue to file the annotation in.","type":"string"},"status":{"description":"Status is the annotation's initial review status. Defaults to PENDING.","type":"string"},"traceId":{"description":"TraceID is the trace the annotation attaches to. Required.","type":"string"}},"type":"object"},"o11y.O11yLLMIngestScore":{"properties":{"comment":{"description":"Comment is a free-text note.","type":"string"},"dataType":{"description":"DataType is the score's kind — NUMERIC or CATEGORICAL. Defaults from the\nvalue when empty.","type":"string"},"name":{"description":"Name is the score's name, e.g. helpfulness. Required.","type":"string"},"observationId":{"description":"ObservationID is the single observation the score attaches to, when\nnarrowed to one.","type":"string"},"source":{"description":"Source is where the score came from, e.g. API, EVAL. Defaults to API.","type":"string"},"stringValue":{"description":"StringValue is the categorical score, when the score is categorical.","type":"string"},"traceId":{"description":"TraceID is the trace the score attaches to. Required.","type":"string"},"value":{"description":"Value is the numeric score.","format":"double","type":"number"}},"type":"object"},"o11y.O11yLLMObservation":{"properties":{"completionTokens":{"description":"CompletionTokens is the output token count.","format":"int64","type":"integer"},"id":{"description":"ID is the observation's id (the span id).","type":"string"},"latencyMs":{"description":"LatencyMs is how long it took, in milliseconds.","format":"double","type":"number"},"model":{"description":"Model is the model that served it.","type":"string"},"name":{"description":"Name is the observation's name.","type":"string"},"parentObservationId":{"description":"ParentID is the parent observation, when the span has one.","type":"string"},"promptTokens":{"description":"PromptTokens is the input token count.","format":"int64","type":"integer"},"provider":{"description":"Provider is the model's provider.","type":"string"},"serviceName":{"description":"ServiceName is the app that emitted it.","type":"string"},"sessionId":{"description":"SessionID is the conversation the observation belongs to.","type":"string"},"startTime":{"description":"StartTime is when the observation started.","format":"date-time","type":"string"},"statusCode":{"description":"StatusCode is the observation's status, e.g. OK, ERROR.","type":"string"},"totalCost":{"description":"TotalCost is the observation's cost.","format":"double","type":"number"},"totalTokens":{"description":"TotalTokens is the sum of prompt and completion tokens.","format":"int64","type":"integer"},"traceId":{"description":"TraceID is the trace the observation belongs to.","type":"string"},"type":{"description":"Type is the observation kind, e.g. chat, embeddings, tool.","type":"string"},"userId":{"description":"UserID is the end user the observation is attributed to.","type":"string"}},"type":"object"},"o11y.O11yLLMObservationsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yLLMObservationsPage","description":"Data is the page."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yLLMObservationsPage":{"properties":{"items":{"description":"Items are the observations, newest first.","items":{"$ref":"#/components/schemas/o11y.O11yLLMObservation"},"type":"array"},"limit":{"description":"Limit is the page cap the read ran with.","format":"int64","type":"integer"},"offset":{"description":"Offset is the row offset this page started at.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yLLMPricingCacheCosts":{"properties":{"mode":{"description":"Mode is how cached tokens are counted — subtract (inside input_tokens,\nOpenAI-style), additive (reported separately, Anthropic-style) or unknown.","type":"string"},"read":{"description":"Read is the cost per unit of cache-read tokens.","format":"double","type":"number"},"write":{"description":"Write is the cost per unit of cache-write tokens.","format":"double","type":"number"}},"type":"object"},"o11y.O11yLLMPricingRule":{"properties":{"createdAt":{"description":"CreatedAt is when the rule was stored.","format":"date-time","type":"string"},"createdBy":{"description":"CreatedBy is who created the rule.","type":"string"},"enabled":{"description":"Enabled says whether the rule is on.","type":"boolean"},"id":{"description":"ID is the rule's id.","type":"string"},"isOverride":{"description":"IsOverride marks the rule user-pinned; when true the sync job skips it.","type":"boolean"},"modelName":{"description":"Model is the model the rule prices.","type":"string"},"modelPattern":{"description":"ModelPattern are the model-name globs the rule matches.","items":{"type":"string"},"type":"array"},"orgId":{"description":"OrgID is the org the rule belongs to.","type":"string"},"pricing":{"$ref":"#/components/schemas/o11y.O11yLLMRulePricing","description":"Pricing is the per-unit cost."},"provider":{"description":"Provider is the model's provider.","type":"string"},"sourceId":{"description":"SourceID is the upstream source the rule was synced from, when synced.","type":"string"},"syncedAt":{"description":"SyncedAt is when the rule was last synced, when it is synced.","format":"date-time","type":"string"},"unit":{"description":"Unit is the pricing unit, e.g. per_million_tokens.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the rule last changed.","format":"date-time","type":"string"},"updatedBy":{"description":"UpdatedBy is who last changed it.","type":"string"}},"type":"object"},"o11y.O11yLLMPricingRuleOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yLLMPricingRule","description":"Data is the rule."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yLLMPricingRulesOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yLLMPricingRulesPage","description":"Data is the page."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yLLMPricingRulesPage":{"properties":{"items":{"description":"Items are the rules.","items":{"$ref":"#/components/schemas/o11y.O11yLLMPricingRule"},"type":"array"},"limit":{"description":"Limit is the page cap the read ran with.","format":"int64","type":"integer"},"offset":{"description":"Offset is the row offset this page started at.","format":"int64","type":"integer"},"total":{"description":"Total is how many rules match, across all pages.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yLLMRulePricing":{"properties":{"cache":{"$ref":"#/components/schemas/o11y.O11yLLMPricingCacheCosts","description":"Cache is the cost of cached tokens, when the model prices them."},"input":{"description":"Input is the cost per unit of input tokens.","format":"double","type":"number"},"output":{"description":"Output is the cost per unit of output tokens.","format":"double","type":"number"}},"type":"object"},"o11y.O11yLLMScore":{"properties":{"comment":{"description":"Comment is a free-text note.","type":"string"},"createdAt":{"description":"CreatedAt is when the score was stored.","format":"date-time","type":"string"},"createdBy":{"description":"CreatedBy is who created the score.","type":"string"},"dataType":{"description":"DataType is the score's kind — NUMERIC or CATEGORICAL.","type":"string"},"id":{"description":"ID is the score's id.","type":"string"},"name":{"description":"Name is the score's name.","type":"string"},"observationId":{"description":"ObservationID is the observation the score attaches to, when narrowed.","type":"string"},"source":{"description":"Source is where the score came from, e.g. API, EVAL.","type":"string"},"stringValue":{"description":"StringValue is the categorical score, when the score is categorical.","type":"string"},"timestamp":{"description":"Timestamp is the score's own event time.","format":"date-time","type":"string"},"traceId":{"description":"TraceID is the trace the score attaches to.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the score last changed.","format":"date-time","type":"string"},"value":{"description":"Value is the numeric score.","format":"double","type":"number"}},"type":"object"},"o11y.O11yLLMScoreOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yLLMScore","description":"Data is the score."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yLLMScoresOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yLLMScoresPage","description":"Data is the page."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yLLMScoresPage":{"properties":{"items":{"description":"Items are the scores, newest first.","items":{"$ref":"#/components/schemas/o11y.O11yLLMScore"},"type":"array"},"limit":{"description":"Limit is the page cap the read ran with.","format":"int64","type":"integer"},"offset":{"description":"Offset is the row offset this page started at.","format":"int64","type":"integer"},"total":{"description":"Total is how many scores match, across all pages.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yLLMSession":{"properties":{"completionTokens":{"description":"CompletionTokens is the conversation's total output tokens.","format":"int64","type":"integer"},"id":{"description":"ID is the session id.","type":"string"},"observations":{"description":"Observations is how many observations the conversation holds.","format":"int64","type":"integer"},"promptTokens":{"description":"PromptTokens is the conversation's total input tokens.","format":"int64","type":"integer"},"totalCost":{"description":"TotalCost is the conversation's total cost.","format":"double","type":"number"},"totalTokens":{"description":"TotalTokens is the conversation's total tokens.","format":"int64","type":"integer"},"traces":{"description":"Traces is how many traces the conversation holds.","format":"int64","type":"integer"},"userId":{"description":"UserID is the end user the conversation is attributed to.","type":"string"}},"type":"object"},"o11y.O11yLLMSessionsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yLLMSessionsPage","description":"Data is the page."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yLLMSessionsPage":{"properties":{"items":{"description":"Items are the conversations, newest first.","items":{"$ref":"#/components/schemas/o11y.O11yLLMSession"},"type":"array"},"limit":{"description":"Limit is the page cap the read ran with.","format":"int64","type":"integer"},"offset":{"description":"Offset is the row offset this page started at.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yLLMTrace":{"properties":{"completionTokens":{"description":"CompletionTokens is the trace's total output tokens.","format":"int64","type":"integer"},"id":{"description":"ID is the trace id.","type":"string"},"latencyMs":{"description":"LatencyMs is the trace's span, in milliseconds.","format":"double","type":"number"},"observations":{"description":"Observations is how many observations the trace holds.","format":"int64","type":"integer"},"promptTokens":{"description":"PromptTokens is the trace's total input tokens.","format":"int64","type":"integer"},"serviceName":{"description":"ServiceName is the app that emitted it.","type":"string"},"sessionId":{"description":"SessionID is the conversation the trace belongs to.","type":"string"},"totalCost":{"description":"TotalCost is the trace's total cost.","format":"double","type":"number"},"totalTokens":{"description":"TotalTokens is the trace's total tokens.","format":"int64","type":"integer"},"userId":{"description":"UserID is the end user the trace is attributed to.","type":"string"}},"type":"object"},"o11y.O11yLLMTracesOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yLLMTracesPage","description":"Data is the page."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yLLMTracesPage":{"properties":{"items":{"description":"Items are the traces, newest first.","items":{"$ref":"#/components/schemas/o11y.O11yLLMTrace"},"type":"array"},"limit":{"description":"Limit is the page cap the read ran with.","format":"int64","type":"integer"},"offset":{"description":"Offset is the row offset this page started at.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yLLMUpdatablePricingRule":{"properties":{"enabled":{"description":"Enabled turns the rule on.","type":"boolean"},"id":{"description":"ID matches an existing rule by its id.","type":"string"},"isOverride":{"description":"IsOverride pins the rule so the sync job skips it. Omit to leave a matched\noverride untouched.","type":"boolean"},"modelName":{"description":"Model is the model the rule prices. Required.","type":"string"},"modelPattern":{"description":"ModelPattern are the model-name globs the rule matches. Required.","items":{"type":"string"},"type":"array"},"pricing":{"$ref":"#/components/schemas/o11y.O11yLLMRulePricing","description":"Pricing is the per-unit cost. Required."},"provider":{"description":"Provider is the model's provider. Required.","type":"string"},"sourceId":{"description":"SourceID matches an existing rule by its upstream source id.","type":"string"},"unit":{"description":"Unit is the pricing unit, e.g. per_million_tokens. Required.","type":"string"}},"type":"object"},"o11y.O11yLLMUpdatablePricingRules":{"properties":{"rules":{"description":"Rules are the rules to create or update, matched per rule.","items":{"$ref":"#/components/schemas/o11y.O11yLLMUpdatablePricingRule"},"type":"array"}},"type":"object"},"o11y.O11yLLMUser":{"properties":{"completionTokens":{"description":"CompletionTokens is their total output tokens.","format":"int64","type":"integer"},"id":{"description":"ID is the end user's id (user.id).","type":"string"},"observations":{"description":"Observations is how many observations they produced.","format":"int64","type":"integer"},"promptTokens":{"description":"PromptTokens is their total input tokens.","format":"int64","type":"integer"},"sessions":{"description":"Sessions is how many conversations they had.","format":"int64","type":"integer"},"totalCost":{"description":"TotalCost is their total cost.","format":"double","type":"number"},"totalTokens":{"description":"TotalTokens is their total tokens.","format":"int64","type":"integer"},"traces":{"description":"Traces is how many traces they produced.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yLLMUsersOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yLLMUsersPage","description":"Data is the page."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yLLMUsersPage":{"properties":{"items":{"description":"Items are the end users, newest first.","items":{"$ref":"#/components/schemas/o11y.O11yLLMUser"},"type":"array"},"limit":{"description":"Limit is the page cap the read ran with.","format":"int64","type":"integer"},"offset":{"description":"Offset is the row offset this page started at.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yLicenseActiveOut":{"properties":{"data":{"description":"Data is the license."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yLicensesOut":{"properties":{"data":{"description":"Data are the licenses.","items":{},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yListError":{"properties":{"exceptionCount":{"description":"ExceptionCount is how many instances the group holds in the window.","format":"uint64","type":"integer"},"exceptionMessage":{"description":"ExceptionMsg is its message.","type":"string"},"exceptionType":{"description":"ExceptionType is the exception's type.","type":"string"},"firstSeen":{"description":"FirstSeen is when the earliest was.","format":"date-time","type":"string"},"groupID":{"description":"GroupID is the group's id.","type":"string"},"lastSeen":{"description":"LastSeen is when the latest instance was recorded.","format":"date-time","type":"string"},"serviceName":{"description":"ServiceName is the service that reported them.","type":"string"}},"type":"object"},"o11y.O11yLogAggregateBucket":{"properties":{"groupBy":{"additionalProperties":{},"description":"GroupBy carries the group's key values when the aggregate grouped.","type":"object"},"timestamp":{"description":"Timestamp is the start of the bucket.","format":"int64","type":"integer"},"value":{"description":"Value is the bucket's aggregated value."}},"type":"object"},"o11y.O11yLogAggregateOut":{"properties":{"items":{"additionalProperties":{"$ref":"#/components/schemas/o11y.O11yLogAggregateBucket"},"description":"Items are the buckets, keyed by bucket timestamp.","type":"object"}},"type":"object"},"o11y.O11yLogConfigVersion":{"properties":{"config":{"description":"Config is the rendered collector config the version deployed.","type":"string"},"createdAt":{"description":"CreatedAt is when the version was created.","format":"date-time","type":"string"},"createdBy":{"description":"CreatedBy is the id of who created the version.","type":"string"},"createdByName":{"description":"CreatedByName is the display name of who created the version.","type":"string"},"deployResult":{"description":"DeployResult is the deployment's outcome message.","type":"string"},"deploySequence":{"description":"DeploySequence orders this deployment among the version's deployments.","format":"int64","type":"integer"},"deployStatus":{"description":"DeployStatus is where the deployment stands, e.g. dirty, deploying,\ndeployed, in_progress, failed, unknown.","type":"string"},"elementType":{"description":"ElementType is the config element the version carries — log_pipelines.","type":"string"},"id":{"description":"ID is the version record's id.","type":"string"},"lastHash":{"description":"LastHash is the deployed config's hash.","type":"string"},"orgId":{"description":"OrgID is the org the version belongs to.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the version last changed.","format":"date-time","type":"string"},"updatedBy":{"description":"UpdatedBy is the id of who last changed it.","type":"string"},"version":{"description":"Version is the config version number.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yLogFilter":{"properties":{"items":{"description":"Items are the predicates.","items":{"$ref":"#/components/schemas/o11y.O11yLogFilterItem"},"type":"array"},"op":{"description":"Op combines the items: AND or OR.","type":"string"}},"type":"object"},"o11y.O11yLogFilterItem":{"properties":{"key":{"$ref":"#/components/schemas/o11y.O11yLogFilterKey","description":"Key is the field the predicate tests."},"op":{"description":"Op is the comparison, e.g. =, !=, in, contains.","type":"string"},"value":{"description":"Value is what it tests against, in the value's own JSON type."}},"type":"object"},"o11y.O11yLogFilterKey":{"properties":{"dataType":{"description":"DataType is the field's data type, e.g. string, int64, float64, bool.","type":"string"},"isColumn":{"description":"IsColumn marks a field materialized as its own column.","type":"boolean"},"isJSON":{"description":"IsJSON marks a path into the record's JSON body.","type":"boolean"},"key":{"description":"Key is the field's name.","type":"string"},"type":{"description":"Type is where the field lives: tag or resource.","type":"string"}},"type":"object"},"o11y.O11yLogParseFrom":{"properties":{"parse_from":{"description":"ParseFrom is the field to read.","type":"string"}},"type":"object"},"o11y.O11yLogPipeline":{"properties":{"alias":{"description":"Alias is the pipeline's short name.","type":"string"},"config":{"description":"Config is the pipeline's processors, in order.","items":{"$ref":"#/components/schemas/o11y.O11yLogPipelineOperator"},"type":"array"},"createdAt":{"description":"CreatedAt is when the pipeline was created.","format":"date-time","type":"string"},"createdBy":{"description":"CreatedBy is the id of who created the pipeline.","type":"string"},"description":{"description":"Description says what the pipeline is for.","type":"string"},"enabled":{"description":"Enabled says whether the pipeline is on.","type":"boolean"},"filter":{"$ref":"#/components/schemas/o11y.O11yLogFilter","description":"Filter selects which records the pipeline processes."},"id":{"description":"ID is the pipeline's id.","type":"string"},"name":{"description":"Name is the pipeline's display name.","type":"string"},"orderId":{"description":"OrderID is the pipeline's 1-based position in the set.","format":"int64","type":"integer"},"updatedAt":{"description":"UpdatedAt is when the pipeline last changed.","format":"date-time","type":"string"},"updatedBy":{"description":"UpdatedBy is the id of who last changed it.","type":"string"}},"type":"object"},"o11y.O11yLogPipelineCreateIn":{"properties":{"pipelines":{"description":"Pipelines are the pipelines the new version holds, in order.","items":{"$ref":"#/components/schemas/o11y.O11yLogPostablePipeline"},"type":"array"}},"type":"object"},"o11y.O11yLogPipelineOperator":{"properties":{"default":{"description":"Default is the id of the processor a router falls through to.","type":"string"},"enable_flattening":{"description":"EnableFlattening flattens parsed JSON one level when true.","type":"boolean"},"enable_paths":{"description":"EnablePaths keeps the JSON path in flattened keys when true.","type":"boolean"},"enabled":{"description":"Enabled turns the processor on.","type":"boolean"},"expr":{"description":"Expr is a router route's expression.","type":"string"},"field":{"description":"Field is the field an add/remove processor works on.","type":"string"},"fields":{"description":"Fields are the fields a retain processor keeps.","items":{"type":"string"},"type":"array"},"from":{"description":"From is the source field of a move or copy.","type":"string"},"id":{"description":"ID is the processor's id, unique within the pipeline.","type":"string"},"if":{"description":"If gates the processor on an expression.","type":"string"},"layout":{"description":"Layout is a time parser's layout.","type":"string"},"layout_type":{"description":"LayoutType is the layout's kind, e.g. strptime, gotime, epoch.","type":"string"},"mapping":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"description":"Mapping maps severity levels (or flattened keys) to the values that\nmean them.","type":"object"},"name":{"description":"Name is the processor's display name.","type":"string"},"on_error":{"description":"OnError says what to do when the processor fails, e.g. send, drop.","type":"string"},"orderId":{"description":"OrderID is the processor's 1-based position in the pipeline.","format":"int64","type":"integer"},"output":{"description":"Output is the id of the processor that runs next.","type":"string"},"overwrite_text":{"description":"OverwriteSeverityText rewrites the severity text alongside the number\nwhen true.","type":"boolean"},"parse_from":{"description":"ParseFrom is where a parser reads from.","type":"string"},"parse_to":{"description":"ParseTo is where a parser writes its result.","type":"string"},"path_prefix":{"description":"PathPrefix prefixes flattened keys.","type":"string"},"pattern":{"description":"Pattern is a grok parser's pattern.","type":"string"},"regex":{"description":"Regex is a regex parser's expression.","type":"string"},"routes":{"description":"Routes are a router processor's routes.","items":{"$ref":"#/components/schemas/o11y.O11yLogPipelineRoute"},"type":"array"},"span_id":{"$ref":"#/components/schemas/o11y.O11yLogParseFrom","description":"SpanID says where a trace parser reads the span id from."},"to":{"description":"To is the destination field of a move or copy.","type":"string"},"trace_flags":{"$ref":"#/components/schemas/o11y.O11yLogParseFrom","description":"TraceFlags says where a trace parser reads the trace flags from."},"trace_id":{"$ref":"#/components/schemas/o11y.O11yLogParseFrom","description":"TraceID says where a trace parser reads the trace id from."},"type":{"description":"Type is the processor type, e.g. grok_parser, regex_parser, json_parser,\ntrace_parser, time_parser, severity_parser, add, remove, move, copy.","type":"string"},"value":{"description":"Value is the value an add processor writes.","type":"string"}},"type":"object"},"o11y.O11yLogPipelinePreview":{"properties":{"collectorLogs":{"description":"CollectorLogs is what the collector logged while simulating.","items":{"type":"string"},"type":"array"},"logs":{"description":"Logs are the sample records after the pipelines ran over them.","items":{"$ref":"#/components/schemas/o11y.O11yLogRecord"},"type":"array"}},"type":"object"},"o11y.O11yLogPipelinePreviewIn":{"properties":{"logs":{"description":"Logs are the sample records to transform.","items":{"$ref":"#/components/schemas/o11y.O11yLogRecord"},"type":"array"},"pipelines":{"description":"Pipelines are the pipelines to simulate, in order.","items":{"$ref":"#/components/schemas/o11y.O11yLogPipeline"},"type":"array"}},"type":"object"},"o11y.O11yLogPipelinePreviewOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yLogPipelinePreview","description":"Data is the dry run's result."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yLogPipelineRoute":{"properties":{"expr":{"description":"Expr is the expression that selects the route.","type":"string"},"output":{"description":"Output is the id of the processor the route sends to.","type":"string"}},"type":"object"},"o11y.O11yLogPipelines":{"properties":{"config":{"description":"Config is the rendered collector config the version deployed.","type":"string"},"createdAt":{"description":"CreatedAt is when the version was created.","format":"date-time","type":"string"},"createdBy":{"description":"CreatedBy is the id of who created the version.","type":"string"},"createdByName":{"description":"CreatedByName is the display name of who created the version.","type":"string"},"deployResult":{"description":"DeployResult is the deployment's outcome message.","type":"string"},"deploySequence":{"description":"DeploySequence orders this deployment among the version's deployments.","format":"int64","type":"integer"},"deployStatus":{"description":"DeployStatus is where the deployment stands, e.g. dirty, deploying,\ndeployed, in_progress, failed, unknown.","type":"string"},"elementType":{"description":"ElementType is the config element this version carries — log_pipelines.","type":"string"},"history":{"description":"History is the recent version history, newest first.","items":{"$ref":"#/components/schemas/o11y.O11yLogConfigVersion"},"type":"array"},"id":{"description":"ID is the version record's id.","type":"string"},"lastHash":{"description":"LastHash is the deployed config's hash.","type":"string"},"orgId":{"description":"OrgID is the org the version belongs to.","type":"string"},"pipelines":{"description":"Pipelines are the version's pipelines, in order.","items":{"$ref":"#/components/schemas/o11y.O11yLogPipeline"},"type":"array"},"updatedAt":{"description":"UpdatedAt is when the version last changed.","format":"date-time","type":"string"},"updatedBy":{"description":"UpdatedBy is the id of who last changed it.","type":"string"},"version":{"description":"Version is the config version number.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yLogPipelinesOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yLogPipelines","description":"Data is the config version."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yLogPostablePipeline":{"properties":{"alias":{"description":"Alias is the pipeline's short name.","type":"string"},"config":{"description":"Config is the pipeline's processors, in order.","items":{"$ref":"#/components/schemas/o11y.O11yLogPipelineOperator"},"type":"array"},"description":{"description":"Description says what the pipeline is for.","type":"string"},"enabled":{"description":"Enabled turns the pipeline on.","type":"boolean"},"filter":{"$ref":"#/components/schemas/o11y.O11yLogFilter","description":"Filter selects which records the pipeline processes."},"id":{"description":"ID is the pipeline's id. Empty on a new pipeline; the id it was listed\nwith to keep an existing one.","type":"string"},"name":{"description":"Name is the pipeline's display name.","type":"string"},"orderId":{"description":"OrderID is the pipeline's 1-based position in the set.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yLogPromoteIndex":{"properties":{"fieldDataType":{"description":"FieldDataType is the path's data type, e.g. string, number, bool.","type":"string"},"granularity":{"description":"Granularity is the index granularity in rows.","format":"int64","type":"integer"},"type":{"description":"Type is the index type, e.g. minmax, set(N), bloom_filter(P).","type":"string"}},"type":"object"},"o11y.O11yLogPromoteOut":{"properties":{"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yLogPromotePath":{"properties":{"indexes":{"description":"Indexes are the indexes to put on the path.","items":{"$ref":"#/components/schemas/o11y.O11yLogPromoteIndex"},"type":"array"},"path":{"description":"Path is the body path, e.g. body.user.id on the way in; listed without\nthe body. prefix.","type":"string"},"promote":{"description":"Promote lifts the path into its own column when true.","type":"boolean"}},"type":"object"},"o11y.O11yLogPromotedOut":{"properties":{"data":{"description":"Data holds the paths.","items":{"$ref":"#/components/schemas/o11y.O11yLogPromotePath"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yLogRecord":{"properties":{"attributes_bool":{"additionalProperties":{"type":"boolean"},"description":"AttributesBool are the record's boolean attributes.","type":"object"},"attributes_float":{"additionalProperties":{"format":"double","type":"number"},"description":"AttributesFloat are the record's float attributes.","type":"object"},"attributes_int":{"additionalProperties":{"format":"int64","type":"integer"},"description":"AttributesInt are the record's integer attributes.","type":"object"},"attributes_string":{"additionalProperties":{"type":"string"},"description":"AttributesString are the record's string attributes.","type":"object"},"body":{"description":"Body is the record's body.","type":"string"},"id":{"description":"ID is the record's id.","type":"string"},"resources_string":{"additionalProperties":{"type":"string"},"description":"ResourcesString are the record's string resource attributes.","type":"object"},"severity_number":{"description":"SeverityNumber is the record's severity as a number.","format":"uint8","type":"integer"},"severity_text":{"description":"SeverityText is the record's severity as text, e.g. ERROR.","type":"string"},"span_id":{"description":"SpanID is the span the record belongs to.","type":"string"},"timestamp":{"description":"Timestamp is the record's time as a nanosecond epoch.","format":"uint64","type":"integer"},"trace_flags":{"description":"TraceFlags are the record's trace flags.","format":"uint32","type":"integer"},"trace_id":{"description":"TraceID is the trace the record belongs to.","type":"string"}},"type":"object"},"o11y.O11yLogRecordsOut":{"properties":{"results":{"description":"Results are the records, newest first.","items":{"additionalProperties":{},"type":"object"},"type":"array"}},"type":"object"},"o11y.O11yLogsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yEvents","description":"Data holds the events."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yMessage":{"properties":{"data":{"description":"Data is the acknowledgment message.","type":"string"}},"type":"object"},"o11y.O11yMetricAckOut":{"properties":{"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yMetricAlert":{"properties":{"alertId":{"description":"AlertID is the alert rule's id.","type":"string"},"alertName":{"description":"AlertName is the alert rule's name.","type":"string"}},"type":"object"},"o11y.O11yMetricAlerts":{"properties":{"alerts":{"description":"Alerts are the alert rules referencing the metric.","items":{"$ref":"#/components/schemas/o11y.O11yMetricAlert"},"type":"array"}},"type":"object"},"o11y.O11yMetricAlertsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yMetricAlerts","description":"Data holds the alerts."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yMetricAttribute":{"properties":{"key":{"description":"Key is the attribute's name.","type":"string"},"valueCount":{"description":"ValueCount is how many distinct values the attribute has.","format":"uint64","type":"integer"},"values":{"description":"Values are the attribute's distinct values.","items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.O11yMetricAttributes":{"properties":{"attributes":{"description":"Attributes are the keys, each with its values.","items":{"$ref":"#/components/schemas/o11y.O11yMetricAttribute"},"type":"array"},"totalKeys":{"description":"TotalKeys is how many keys the metric has.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yMetricAttributesOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yMetricAttributes","description":"Data holds the attributes."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yMetricDashboards":{"properties":{"dashboards":{"description":"Dashboards are the panels referencing the metric.","items":{"$ref":"#/components/schemas/o11y.O11yMetricPanel"},"type":"array"}},"type":"object"},"o11y.O11yMetricDashboardsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yMetricDashboards","description":"Data holds the panels."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yMetricField":{"properties":{"description":{"description":"Description describes the field.","type":"string"},"fieldContext":{"description":"FieldContext is the context the field lives in, e.g. resource, attribute.","type":"string"},"fieldDataType":{"description":"FieldDataType is the field's data type.","type":"string"},"name":{"description":"Name is the field's name.","type":"string"},"signal":{"description":"Signal is the telemetry signal the field belongs to.","type":"string"},"unit":{"description":"Unit is the field's unit.","type":"string"}},"type":"object"},"o11y.O11yMetricFilter":{"properties":{"expression":{"description":"Expression is the filter, in the query-builder filter syntax.","type":"string"}},"type":"object"},"o11y.O11yMetricHighlights":{"properties":{"activeTimeSeries":{"description":"ActiveTimeSeries is how many of them are active.","format":"uint64","type":"integer"},"dataPoints":{"description":"DataPoints is how many data points the metric has.","format":"uint64","type":"integer"},"lastReceived":{"description":"LastReceived is when the metric last arrived, as a Unix timestamp in\nmilliseconds.","format":"uint64","type":"integer"},"totalTimeSeries":{"description":"TotalTimeSeries is how many time series the metric has ever had.","format":"uint64","type":"integer"}},"type":"object"},"o11y.O11yMetricHighlightsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yMetricHighlights","description":"Data holds the highlights."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yMetricInspectIn":{"properties":{"end":{"description":"End is the end of the window as a Unix timestamp in milliseconds, at most\nthirty minutes after start. Required.","format":"int64","type":"integer"},"filter":{"$ref":"#/components/schemas/o11y.O11yMetricFilter","description":"Filter narrows the series returned."},"metricName":{"description":"MetricName is the metric to inspect. Required.","type":"string"},"start":{"description":"Start is the start of the window as a Unix timestamp in milliseconds. Required.","format":"int64","type":"integer"}},"required":["metricName","start","end"],"type":"object"},"o11y.O11yMetricInspectOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yMetricSeriesSet","description":"Data holds the series."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yMetricLabel":{"properties":{"key":{"$ref":"#/components/schemas/o11y.O11yMetricField","description":"Key is the label's field."},"value":{"description":"Value is the label's value."}},"type":"object"},"o11y.O11yMetricList":{"properties":{"metrics":{"description":"Metrics are the metrics, with their metadata.","items":{"$ref":"#/components/schemas/o11y.O11yMetricSummary"},"type":"array"}},"type":"object"},"o11y.O11yMetricListOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yMetricList","description":"Data holds the metrics."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yMetricMetadata":{"properties":{"description":{"description":"Description describes the metric.","type":"string"},"isMonotonic":{"description":"IsMonotonic marks a sum that only ever increases.","type":"boolean"},"temporality":{"description":"Temporality is delta or cumulative.","type":"string"},"type":{"description":"Type is the metric type, e.g. gauge, sum, histogram.","type":"string"},"unit":{"description":"Unit is the metric's unit.","type":"string"}},"type":"object"},"o11y.O11yMetricMetadataOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yMetricMetadata","description":"Data holds the metadata."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yMetricMetadataSaveIn":{"properties":{"description":{"description":"Description describes the metric.","type":"string"},"isMonotonic":{"description":"IsMonotonic marks a sum that only ever increases.","type":"boolean"},"metricName":{"description":"MetricName is the metric to update. Required.","type":"string"},"temporality":{"description":"Temporality is delta or cumulative.","type":"string"},"type":{"description":"Type is the metric type, e.g. gauge, sum, histogram.","type":"string"},"unit":{"description":"Unit is the metric's unit.","type":"string"}},"required":["metricName"],"type":"object"},"o11y.O11yMetricOnboarding":{"properties":{"hasMetrics":{"description":"HasMetrics is true once any non-O11y metric has been ingested.","type":"boolean"}},"type":"object"},"o11y.O11yMetricOnboardingOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yMetricOnboarding","description":"Data holds the flag."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yMetricOrder":{"properties":{"direction":{"description":"Direction is asc or desc.","type":"string"},"key":{"$ref":"#/components/schemas/o11y.O11yMetricField","description":"Key is the field to order by."}},"type":"object"},"o11y.O11yMetricPanel":{"properties":{"dashboardId":{"description":"DashboardID is the dashboard's id.","type":"string"},"dashboardName":{"description":"DashboardName is the dashboard's name.","type":"string"},"filterBy":{"description":"FilterBy are the labels the panel filters the metric by.","items":{"type":"string"},"type":"array"},"groupBy":{"description":"GroupBy are the labels the panel groups the metric by.","items":{"type":"string"},"type":"array"},"panelId":{"description":"PanelID is the panel's id.","type":"string"},"panelName":{"description":"PanelName is the panel's name.","type":"string"}},"type":"object"},"o11y.O11yMetricPoint":{"properties":{"partial":{"description":"Partial marks a point whose bucket the window only partly covers.","type":"boolean"},"timestamp":{"description":"Timestamp is the point's time as a Unix timestamp in milliseconds.","format":"int64","type":"integer"},"value":{"description":"Value is the point's value.","format":"double","type":"number"},"values":{"description":"Values carries the bucket values of a heatmap point.","items":{"format":"double","type":"number"},"type":"array"}},"type":"object"},"o11y.O11yMetricSeries":{"properties":{"labels":{"description":"Labels identify the series.","items":{"$ref":"#/components/schemas/o11y.O11yMetricLabel"},"type":"array"},"values":{"description":"Values are the series' points, in time order.","items":{"$ref":"#/components/schemas/o11y.O11yMetricPoint"},"type":"array"}},"type":"object"},"o11y.O11yMetricSeriesSet":{"properties":{"series":{"description":"Series are the time series.","items":{"$ref":"#/components/schemas/o11y.O11yMetricSeries"},"type":"array"}},"type":"object"},"o11y.O11yMetricStat":{"properties":{"description":{"description":"Description describes the metric.","type":"string"},"metricName":{"description":"MetricName is the metric's name.","type":"string"},"samples":{"description":"Samples is how many samples the metric had.","format":"uint64","type":"integer"},"timeseries":{"description":"TimeSeries is how many time series the metric had.","format":"uint64","type":"integer"},"type":{"description":"Type is the metric type.","type":"string"},"unit":{"description":"Unit is the metric's unit.","type":"string"}},"type":"object"},"o11y.O11yMetricStats":{"properties":{"metrics":{"description":"Metrics are the counted metrics.","items":{"$ref":"#/components/schemas/o11y.O11yMetricStat"},"type":"array"},"total":{"description":"Total is how many metrics matched, across all pages.","format":"uint64","type":"integer"}},"type":"object"},"o11y.O11yMetricStatsIn":{"properties":{"end":{"description":"End is the end of the window as a Unix timestamp in milliseconds. Required.","format":"int64","type":"integer"},"filter":{"$ref":"#/components/schemas/o11y.O11yMetricFilter","description":"Filter narrows the metrics counted."},"limit":{"description":"Limit caps how many metrics come back, between 1 and 5000. Required.","format":"int64","type":"integer"},"offset":{"description":"Offset is how many metrics to skip, for paging.","format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.O11yMetricOrder","description":"OrderBy sorts the page, by samples or timeseries."},"start":{"description":"Start is the start of the window as a Unix timestamp in milliseconds. Required.","format":"int64","type":"integer"}},"required":["start","end","limit"],"type":"object"},"o11y.O11yMetricStatsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yMetricStats","description":"Data holds the statistics."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yMetricSummary":{"properties":{"description":{"description":"Description describes the metric.","type":"string"},"isMonotonic":{"description":"IsMonotonic marks a sum that only ever increases.","type":"boolean"},"metricName":{"description":"MetricName is the metric's name.","type":"string"},"temporality":{"description":"Temporality is delta or cumulative.","type":"string"},"type":{"description":"Type is the metric type, e.g. gauge, sum, histogram.","type":"string"},"unit":{"description":"Unit is the metric's unit.","type":"string"}},"type":"object"},"o11y.O11yMetricTreemap":{"properties":{"samples":{"description":"Samples are the entries when measuring by sample count.","items":{"$ref":"#/components/schemas/o11y.O11yTreemapEntry"},"type":"array"},"timeseries":{"description":"TimeSeries are the entries when measuring by time-series count.","items":{"$ref":"#/components/schemas/o11y.O11yTreemapEntry"},"type":"array"}},"type":"object"},"o11y.O11yMetricTreemapIn":{"properties":{"end":{"description":"End is the end of the window as a Unix timestamp in milliseconds. Required.","format":"int64","type":"integer"},"filter":{"$ref":"#/components/schemas/o11y.O11yMetricFilter","description":"Filter narrows the metrics counted."},"limit":{"description":"Limit caps how many entries come back, between 1 and 5000. Required.","format":"int64","type":"integer"},"mode":{"description":"Mode picks the measure: timeseries or samples. Required.","type":"string"},"start":{"description":"Start is the start of the window as a Unix timestamp in milliseconds. Required.","format":"int64","type":"integer"}},"required":["start","end","limit","mode"],"type":"object"},"o11y.O11yMetricTreemapOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yMetricTreemap","description":"Data holds the treemap."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yMetricsQueryRangeOut":{"properties":{"data":{"description":"Data is the result — its result type, the value, and query stats when\nasked."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yMyServiceAccountUpdateIn":{"properties":{"name":{"description":"Name is the account's new name, under the same rules it was created with.\nRequired.","type":"string"}},"type":"object"},"o11y.O11yNamespaceListOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.NamespaceListResponse","description":"Data holds the namespace records."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yNextPrevErrorIDs":{"properties":{"groupID":{"description":"GroupID is the group both belong to.","type":"string"},"nextErrorID":{"description":"NextErrorID is the id of the instance immediately after this one.","type":"string"},"nextTimestamp":{"description":"NextTimestamp is that instance's time.","format":"date-time","type":"string"},"prevErrorID":{"description":"PrevErrorID is the id of the instance immediately before this one.","type":"string"},"prevTimestamp":{"description":"PrevTimestamp is that instance's time.","format":"date-time","type":"string"}},"type":"object"},"o11y.O11yNodeListOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.NodeListResponse","description":"Data holds the node records."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yObject":{"properties":{"resource":{"$ref":"#/components/schemas/o11y.O11yResourceRef","description":"Resource is the resource's type and kind."},"selector":{"description":"Selector picks the instance — an FGA object string, wildcard allowed.","type":"string"}},"type":"object"},"o11y.O11yObjectGroup":{"properties":{"resource":{"$ref":"#/components/schemas/o11y.O11yResourceRef","description":"Resource is the objects' type and kind."},"selectors":{"description":"Selectors pick the instances; a wildcard selects them all.","items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.O11yOccurrence":{"properties":{"culprit":{"description":"Culprit is where it came from.","type":"string"},"environment":{"description":"Environment is the deployment it happened in.","type":"string"},"eventId":{"description":"EventID is the occurrence's id.","type":"string"},"fingerprint":{"description":"Fingerprint is the grouping key it was bucketed by.","type":"string"},"frames":{"description":"Frames are the stack, innermost first.","items":{"$ref":"#/components/schemas/o11y.O11yOccurrenceFrame"},"type":"array"},"level":{"description":"Level is its severity, e.g. error, warning, info.","type":"string"},"platform":{"description":"Platform is the reporting runtime.","type":"string"},"release":{"description":"Release is the version that produced it.","type":"string"},"serverName":{"description":"ServerName is the host that reported it.","type":"string"},"serviceName":{"description":"ServiceName is the service that reported it.","type":"string"},"spanId":{"description":"SpanID is the span it belonged to.","type":"string"},"tags":{"additionalProperties":{"type":"string"},"description":"Tags are the reporter's own key/value labels.","type":"object"},"timestamp":{"description":"Timestamp is when the error happened.","format":"date-time","type":"string"},"traceId":{"description":"TraceID is the trace it belonged to.","type":"string"},"transaction":{"description":"Transaction is the operation it happened in.","type":"string"},"type":{"description":"Type is the exception type.","type":"string"},"user":{"$ref":"#/components/schemas/o11y.O11yEventUser","description":"User is the affected end-user context, when the reporter attached one."},"value":{"description":"Value is the exception value.","type":"string"}},"type":"object"},"o11y.O11yOccurrenceFrame":{"properties":{"absPath":{"description":"AbsPath is the file's absolute path.","type":"string"},"colno":{"description":"Colno is the column number.","format":"int64","type":"integer"},"filename":{"description":"Filename is the file it is in.","type":"string"},"function":{"description":"Function is the function the frame is in.","type":"string"},"inApp":{"description":"InApp marks a frame in the reporting application's own code.","type":"boolean"},"lineno":{"description":"Lineno is the line number.","format":"int64","type":"integer"},"module":{"description":"Module is the module the function is in.","type":"string"}},"type":"object"},"o11y.O11yOnboardingOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yK8sOnboarding","description":"Data is the progress report."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yOperation":{"properties":{"errorCount":{"description":"ErrorCount is how many of those runs errored.","format":"uint64","type":"integer"},"name":{"description":"Name is the operation (span name).","type":"string"},"numCalls":{"description":"NumCalls is how many times it ran in the window.","format":"uint64","type":"integer"},"p50":{"description":"P50 is its median latency, nanoseconds.","format":"double","type":"number"},"p95":{"description":"P95 is its p95 latency, nanoseconds.","format":"double","type":"number"},"p99":{"description":"P99 is its p99 latency, nanoseconds.","format":"double","type":"number"}},"type":"object"},"o11y.O11yOperationsIn":{"properties":{"end":{"description":"End is the window's end, epoch nanoseconds as a string.","type":"string"},"limit":{"description":"Limit caps how many operations come back.","format":"int64","type":"integer"},"service":{"description":"Service is the service whose operations are read.","type":"string"},"start":{"description":"Start is the window's start, epoch nanoseconds as a string.","type":"string"},"tags":{"description":"Tags narrow the spans counted, each a span-attribute predicate.","items":{"$ref":"#/components/schemas/o11y.O11yServiceTag"},"type":"array"}},"type":"object"},"o11y.O11yOperationsOut":{"properties":{"data":{"description":"Data holds one entry per operation.","items":{"$ref":"#/components/schemas/o11y.O11yOperation"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yOrgStatsOut":{"properties":{"data":{"additionalProperties":{},"description":"Data are the statistics, keyed by the reporter's own counter names.","type":"object"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yOrganization":{"properties":{"alias":{"description":"Alias is an alternate name the org also answers to.","type":"string"},"createdAt":{"description":"CreatedAt is when the org was created.","format":"date-time","type":"string"},"displayName":{"description":"DisplayName is what the console shows for the org.","type":"string"},"id":{"description":"ID is the org id. On update it is ignored: the call always addresses the\ncaller's own org.","type":"string"},"key":{"description":"Key is the org's stable numeric key, derived from its id.","format":"uint32","type":"integer"},"name":{"description":"Name is the org's short name.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it last changed.","format":"date-time","type":"string"}},"type":"object"},"o11y.O11yOrganizationOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yOrganization","description":"Data is the organization."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yOverallStateTransitionsOut":{"properties":{"data":{"description":"Data holds the windows.","items":{"$ref":"#/components/schemas/o11y.ReleStateItem"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yPercentilePosition":{"properties":{"description":{"description":"Description says the same in words.","type":"string"},"percentile":{"description":"Percentile is the percentile the duration lands at.","format":"double","type":"number"}},"type":"object"},"o11y.O11yPercentiles":{"properties":{"p50":{"description":"P50 is the median.","format":"double","type":"number"},"p90":{"description":"P90 is the 90th percentile.","format":"double","type":"number"},"p99":{"description":"P99 is the 99th percentile.","format":"double","type":"number"}},"type":"object"},"o11y.O11yPodListOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.PodListResponse","description":"Data holds the pod records."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yPodOnboarding":{"properties":{"clusterName":{"description":"ClusterName is the pod's cluster.","type":"string"},"hasClusterName":{"description":"HasClusterName says whether the cluster label is present.","type":"boolean"},"hasCronjobName":{"description":"HasCronjobName says whether the cronjob label is present.","type":"boolean"},"hasDaemonsetName":{"description":"HasDaemonsetName says whether the daemonset label is present.","type":"boolean"},"hasDeploymentName":{"description":"HasDeploymentName says whether the deployment label is present.","type":"boolean"},"hasJobName":{"description":"HasJobName says whether the job label is present.","type":"boolean"},"hasNamespaceName":{"description":"HasNamespaceName says whether the namespace label is present.","type":"boolean"},"hasNodeName":{"description":"HasNodeName says whether the node label is present.","type":"boolean"},"hasStatefulsetName":{"description":"HasStatefulsetName says whether the statefulset label is present.","type":"boolean"},"namespaceName":{"description":"NamespaceName is the pod's namespace.","type":"string"},"nodeName":{"description":"NodeName is the pod's node.","type":"string"},"podName":{"description":"PodName is the pod.","type":"string"}},"type":"object"},"o11y.O11yPreference":{"properties":{"allowedScopes":{"description":"AllowedScopes are the scopes the preference may be set at — org, user.","items":{"type":"string"},"type":"array"},"allowedValues":{"description":"AllowedValues restricts a string preference to these values.","items":{"type":"string"},"type":"array"},"defaultValue":{"description":"DefaultValue is the value before anyone set one."},"description":{"description":"Description says what the preference does.","type":"string"},"name":{"description":"Name is the preference name.","type":"string"},"value":{"description":"Value is the current value."},"valueType":{"description":"ValueType is the JSON type a value must have — string, integer, float or\nboolean.","type":"string"}},"type":"object"},"o11y.O11yPreferenceOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yPreference","description":"Data is the preference."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yPreferencesOut":{"properties":{"data":{"description":"Data holds the preferences.","items":{"$ref":"#/components/schemas/o11y.O11yPreference"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yProcessListOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.ProcessListResponse","description":"Data holds the process records."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yPromQueryOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yPromResult","description":"Data is the evaluation result."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yPromResult":{"properties":{"result":{"description":"Result is the result in PromQL's own wire shape for ResultType, carried\nverbatim."},"resultType":{"description":"ResultType discriminates Result: matrix, vector, scalar or string.","type":"string"},"stats":{"description":"Stats holds query statistics when the caller asked for them."}},"type":"object"},"o11y.O11yPublicDashboard":{"properties":{"defaultTimeRange":{"description":"DefaultTimeRange is the fixed window when the range is not caller-chosen.","type":"string"},"publicPath":{"description":"PublicPath is the public URL path the share is reachable at.","type":"string"},"timeRangeEnabled":{"description":"TimeRangeEnabled reports whether the public page may pick its own range.","type":"boolean"}},"type":"object"},"o11y.O11yPublicDashboardData":{"properties":{"dashboard":{"$ref":"#/components/schemas/o11y.O11yPublicDashboardV1","description":"Dashboard is the sanitized dashboard."},"publicDashboard":{"$ref":"#/components/schemas/o11y.O11yPublicDashboard","description":"PublicDashboard is the public-sharing config."}},"type":"object"},"o11y.O11yPublicDashboardDataOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yPublicDashboardData","description":"Data is the sanitized dashboard and its share config."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yPublicDashboardOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yPublicDashboard","description":"Data is the public-sharing config."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yPublicDashboardV1":{"properties":{"createdAt":{"description":"CreatedAt is when the dashboard was created.","format":"date-time","type":"string"},"createdBy":{"description":"CreatedBy is who created it.","type":"string"},"data":{"description":"Data is the sanitized widget data as stored, carried verbatim as open JSON."},"id":{"description":"ID is the dashboard's id.","type":"string"},"locked":{"description":"Locked reports whether the dashboard is locked.","type":"boolean"},"org_id":{"description":"OrgID is the org the dashboard belongs to.","type":"string"},"source":{"description":"Source is where the dashboard came from.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it last changed.","format":"date-time","type":"string"},"updatedBy":{"description":"UpdatedBy is who last changed it.","type":"string"}},"type":"object"},"o11y.O11yPublicDashboardWriteIn":{"properties":{"defaultTimeRange":{"description":"DefaultTimeRange is the fixed window as a Go duration, e.g. 1h, 30m.","type":"string"},"id":{"description":"ID is the dashboard id from the path.","type":"string"},"timeRangeEnabled":{"description":"TimeRangeEnabled lets the public page pick its own time range; when false\nthe share fixes DefaultTimeRange.","type":"boolean"}},"type":"object"},"o11y.O11yPvcListOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.VolumeListResponse","description":"Data holds the volume records."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yQueryFilterAnalysis":{"properties":{"groups":{"description":"Groups are the columns the query groups by.","items":{"$ref":"#/components/schemas/o11y.O11yColumnInfo"},"type":"array"},"metricNames":{"description":"MetricNames are the metrics the query reads.","items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.O11yQueryRange":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yQueryRangeData","description":"Data holds the results."},"meta":{"$ref":"#/components/schemas/o11y.O11yQueryStats","description":"Meta reports what the query scanned."},"type":{"description":"Type is the result kind; time_series here.","type":"string"},"warning":{"$ref":"#/components/schemas/o11y.O11yQueryWarning","description":"Warning carries a non-fatal warning, when the query raised one."}},"type":"object"},"o11y.O11yQueryRangeData":{"properties":{"results":{"description":"Results are the per-query results, each a set of aggregated series.","items":{"$ref":"#/components/schemas/o11y.O11yReductionSeriesResult"},"type":"array"}},"type":"object"},"o11y.O11yQueryRangeFormatOut":{"properties":{"data":{"description":"Data is the query, normalized to the v3 shape."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yQueryRangeOut":{"properties":{"data":{"description":"Data is the query result — the result type, the result set, execution stats\nand any warning — as the engine rendered it."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yQueryRangePreviewIn":{"properties":{"compositeQuery":{"$ref":"#/components/schemas/o11y.CompositeQuery","description":"CompositeQuery is the composite query to use for the request."},"end":{"description":"End is the end time of the query in epoch milliseconds.","format":"uint64","type":"integer"},"formatOptions":{"$ref":"#/components/schemas/o11y.FormatOptions"},"noCache":{"description":"NoCache is a flag to disable caching for the request.","type":"boolean"},"requestType":{"description":"RequestType is the type of the request."},"schemaVersion":{"description":"SchemaVersion is the version of the schema to use for the request payload.","type":"string"},"start":{"description":"Start is the start time of the query in epoch milliseconds.","format":"uint64","type":"integer"},"variables":{"additionalProperties":{"$ref":"#/components/schemas/o11y.VariableItem"},"description":"Variables is the variables to use for the request.","type":"object"},"verbose":{"description":"Verbose selects the answer's depth. Empty or \"true\" renders the underlying\nDatastore SQL with EXPLAIN and granule analysis; \"false\" returns only the\nper-query valid/error/warnings verdict with no Datastore round trips.","type":"string"}},"type":"object"},"o11y.O11yQueryRangePreviewOut":{"properties":{"data":{"description":"Data holds one preview per query, keyed by query name — the rendered\nstatements with optional EXPLAIN and granule analysis, or the per-query\nverdict."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yQueryStats":{"properties":{"bytesScanned":{"description":"BytesScanned is how many bytes the query read.","format":"uint64","type":"integer"},"durationMs":{"description":"DurationMS is how long the query took, in milliseconds.","format":"uint64","type":"integer"},"rowsScanned":{"description":"RowsScanned is how many rows the query read.","format":"uint64","type":"integer"},"stepIntervals":{"additionalProperties":{"format":"uint64","type":"integer"},"description":"StepIntervals is the step used per query, in seconds.","type":"object"}},"type":"object"},"o11y.O11yQueryWarning":{"properties":{"message":{"description":"Message is the warning.","type":"string"},"url":{"description":"URL points at the relevant documentation.","type":"string"},"warnings":{"description":"Warnings carries additional notes.","items":{"$ref":"#/components/schemas/o11y.O11yQueryWarningNote"},"type":"array"}},"type":"object"},"o11y.O11yQueryWarningNote":{"properties":{"message":{"description":"Message is the note.","type":"string"}},"type":"object"},"o11y.O11yQueueCheck":{"properties":{"attribute":{"description":"Attribute is the span attribute or telemetry the check looked for.","type":"string"},"error_message":{"description":"Message says what is missing when the check fails; empty on a pass. Its\nwire key is error_message.","type":"string"},"status":{"description":"Status is \"1\" when the telemetry is present, \"0\" when it is not.","type":"string"}},"type":"object"},"o11y.O11yQueueChecksOut":{"properties":{"data":{"description":"Data holds one check per required attribute, sorted by attribute.","items":{"$ref":"#/components/schemas/o11y.O11yQueueCheck"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yQueueFilterKey":{"properties":{"dataType":{"description":"DataType is the attribute's type: string, int64, float64 or bool.","type":"string"},"isColumn":{"description":"IsColumn marks an attribute materialized as its own store column.","type":"boolean"},"isJSON":{"description":"IsJSON marks an attribute read out of the span's JSON body.","type":"boolean"},"key":{"description":"Key is the attribute name.","type":"string"},"type":{"description":"Type says which plane the attribute lives on: tag or resource.","type":"string"}},"type":"object"},"o11y.O11yQueueFilterRule":{"properties":{"key":{"$ref":"#/components/schemas/o11y.O11yQueueFilterKey","description":"Key names the attribute the predicate tests."},"op":{"description":"Op is the comparison, e.g. =, !=, in, contains.","type":"string"},"value":{"description":"Value is the operand; its JSON type follows the attribute's dataType."}},"type":"object"},"o11y.O11yQueueFilterSet":{"properties":{"items":{"description":"Items are the predicates.","items":{"$ref":"#/components/schemas/o11y.O11yQueueFilterRule"},"type":"array"},"op":{"description":"Op combines the items: AND or OR.","type":"string"}},"type":"object"},"o11y.O11yQueueIn":{"properties":{"end":{"description":"End is the window's end, epoch nanoseconds.","format":"int64","type":"integer"},"eval_time":{"description":"EvalTime bounds the span-evaluation scan, nanoseconds; only the\nspan/evaluation view reads it.","format":"int64","type":"integer"},"start":{"description":"Start is the window's start, epoch nanoseconds.","format":"int64","type":"integer"},"variables":{"additionalProperties":{"type":"string"},"description":"Variables name what the view drills into — topic, partition, service,\nconsumer_group — keyed by the name the view expects.","type":"object"}},"type":"object"},"o11y.O11yQueueListIn":{"properties":{"end":{"description":"End is the window's end, epoch nanoseconds.","format":"int64","type":"integer"},"filters":{"$ref":"#/components/schemas/o11y.O11yQueueFilterSet","description":"Filters narrow the rows by span attribute; null means all rows."},"limit":{"description":"Limit caps how many rows come back.","format":"int64","type":"integer"},"start":{"description":"Start is the window's start, epoch nanoseconds.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yQueueRow":{"properties":{"data":{"additionalProperties":{},"description":"Data holds the row's cells keyed by column name; each cell's JSON type is\nthe column's own, so the bytes pass through verbatim.","type":"object"},"timestamp":{"description":"Timestamp anchors the row in time.","format":"date-time","type":"string"}},"type":"object"},"o11y.O11yQueueRowsOut":{"properties":{"data":{"description":"Data holds one row per messaging destination.","items":{"$ref":"#/components/schemas/o11y.O11yQueueRow"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yQuickFiltersOut":{"properties":{"data":{"description":"Data holds one entry per signal.","items":{"$ref":"#/components/schemas/o11y.O11ySignalFilters"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yReductionRule":{"properties":{"active":{"description":"Active says whether the rule is in force.","type":"boolean"},"createdAt":{"description":"CreatedAt is when the rule was created.","format":"date-time","type":"string"},"createdBy":{"description":"CreatedBy is who created it.","type":"string"},"effectiveFrom":{"description":"EffectiveFrom is when the rule took effect.","format":"date-time","type":"string"},"id":{"description":"ID is the rule's id.","type":"string"},"ingestedSamples":{"description":"IngestedSamples is how many samples arrived while the rule was active.","format":"uint64","type":"integer"},"ingestedSeries":{"description":"IngestedSeries is how many series arrived while the rule was active.","format":"uint64","type":"integer"},"labels":{"description":"Labels are the label names the rule matches.","items":{"type":"string"},"type":"array"},"matchType":{"description":"MatchType is drop or keep.","type":"string"},"metricName":{"description":"MetricName is the metric the rule governs.","type":"string"},"retainedSamples":{"description":"RetainedSamples is how many of them were kept.","format":"uint64","type":"integer"},"retainedSeries":{"description":"RetainedSeries is how many of them were kept.","format":"uint64","type":"integer"},"updatedAt":{"description":"UpdatedAt is when the rule last changed.","format":"date-time","type":"string"},"updatedBy":{"description":"UpdatedBy is who last changed it.","type":"string"}},"type":"object"},"o11y.O11yReductionRuleCreateIn":{"properties":{"labels":{"description":"Labels are the label names the rule matches. Required, at least one.","items":{"type":"string"},"type":"array"},"matchType":{"description":"MatchType is drop or keep: drop the named labels, or keep only them. Required.","type":"string"},"metricName":{"description":"MetricName is the metric the rule governs; one rule per metric. Required.","type":"string"}},"required":["metricName","matchType","labels"],"type":"object"},"o11y.O11yReductionRuleListOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yReductionRules","description":"Data holds the rules."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yReductionRuleOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yReductionRule","description":"Data holds the rule."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yReductionRulePreview":{"properties":{"affectedAssets":{"description":"AffectedAssets are the dashboards and alerts the rule would touch.","items":{"$ref":"#/components/schemas/o11y.O11yAffectedAsset"},"type":"array"},"currentRetainedSeries":{"description":"CurrentRetainedSeries is how many survive the rules in force today.","format":"uint64","type":"integer"},"droppedLabels":{"description":"DroppedLabels are the labels the rule would drop.","items":{"type":"string"},"type":"array"},"effectiveFrom":{"description":"EffectiveFrom is when the rule would take effect.","format":"date-time","type":"string"},"ingestedSeries":{"description":"IngestedSeries is how many series the metric ingests today.","format":"uint64","type":"integer"},"reductionPercent":{"description":"ReductionPercent is the estimated reduction, in percent.","format":"double","type":"number"},"retainedSeries":{"description":"RetainedSeries is how many would survive with the candidate rule.","format":"uint64","type":"integer"}},"type":"object"},"o11y.O11yReductionRulePreviewIn":{"properties":{"labels":{"description":"Labels are the label names the rule would match. Required, at least one.","items":{"type":"string"},"type":"array"},"lookbackMs":{"description":"LookbackMs is how far back to sample when estimating.","format":"int64","type":"integer"},"matchType":{"description":"MatchType is drop or keep. Required.","type":"string"},"metricName":{"description":"MetricName is the metric the rule would govern. Required.","type":"string"}},"required":["metricName","matchType","labels"],"type":"object"},"o11y.O11yReductionRulePreviewOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yReductionRulePreview","description":"Data holds the estimate."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yReductionRuleSaveIn":{"properties":{"id":{"description":"ID is the rule's id.","type":"string"},"labels":{"description":"Labels are the label names the rule matches. Required, at least one.","items":{"type":"string"},"type":"array"},"matchType":{"description":"MatchType is drop or keep. Required.","type":"string"}},"required":["id","matchType","labels"],"type":"object"},"o11y.O11yReductionRules":{"properties":{"rules":{"description":"Rules are the rules.","items":{"$ref":"#/components/schemas/o11y.O11yReductionRule"},"type":"array"},"total":{"description":"Total is how many rules matched, across all pages.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yReductionSeriesOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yQueryRange","description":"Data holds the query-range answer."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yReductionSeriesResult":{"properties":{"aggregations":{"description":"Aggregations are the query's aggregation buckets.","items":{"$ref":"#/components/schemas/o11y.O11yAggregation"},"type":"array"},"queryName":{"description":"QueryName names the query the result answers.","type":"string"}},"type":"object"},"o11y.O11yReductionStats":{"properties":{"estimatedMonthlySavingsUsd":{"description":"EstimatedMonthlySavingsUsd is the estimated monthly savings, in USD.","format":"double","type":"number"},"ingestedSamples":{"description":"IngestedSamples is how many samples arrived across all rules.","format":"uint64","type":"integer"},"ingestedSeries":{"description":"IngestedSeries is how many series arrived across all rules.","format":"uint64","type":"integer"},"retainedSamples":{"description":"RetainedSamples is how many of them were kept.","format":"uint64","type":"integer"},"retainedSeries":{"description":"RetainedSeries is how many of them were kept.","format":"uint64","type":"integer"}},"type":"object"},"o11y.O11yReductionStatsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yReductionStats","description":"Data holds the totals."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yResourceRef":{"properties":{"kind":{"description":"Kind is the resource kind the type belongs to.","type":"string"},"type":{"description":"Type is the resource type, e.g. role, dashboard, serviceaccount.","type":"string"}},"type":"object"},"o11y.O11yRetentionMatch":{"properties":{"key":{"description":"Key is the label to test.","type":"string"},"values":{"description":"Values are the label values the rule matches.","items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.O11yRetentionOut":{"properties":{"cold_storage_ttl_days":{"description":"ColdStorageTTLDays is how old data must be before it moves, in days.","format":"int64","type":"integer"},"cold_storage_volume":{"description":"ColdStorageVolume names the volume aged data moves to.","type":"string"},"default_ttl_days":{"description":"DefaultTTLDays is the retention for data no rule matches, in days.","format":"int64","type":"integer"},"expected_logs_move_ttl_duration_hrs":{"description":"ExpectedLogsMoveTTLHours is the pending logs cold-storage move TTL, in\nhours.","format":"int64","type":"integer"},"expected_logs_ttl_duration_hrs":{"description":"ExpectedLogsTTLHours is the pending logs TTL, in hours.","format":"int64","type":"integer"},"status":{"description":"Status is the last TTL operation's state.","type":"string"},"ttl_conditions":{"description":"TTLConditions are the ordered per-label rules; the first match wins.","items":{"$ref":"#/components/schemas/o11y.O11yRetentionRule"},"type":"array"},"version":{"description":"Version is the policy format version.","type":"string"}},"type":"object"},"o11y.O11yRetentionRule":{"properties":{"conditions":{"description":"Conditions all have to hold for the rule to match.","items":{"$ref":"#/components/schemas/o11y.O11yRetentionMatch"},"type":"array"},"ttlDays":{"description":"TTLDays is the retention applied when it does, in days.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11yRetentionSetIn":{"properties":{"coldStorageDurationDays":{"description":"ColdStorageDurationDays is how old data must be before it moves, in days.","format":"int64","type":"integer"},"coldStorageVolume":{"description":"ColdStorageVolume names the volume aged data moves to, when set.","type":"string"},"defaultTTLDays":{"description":"DefaultTTLDays is the retention for data no rule matches, in days.","format":"int64","type":"integer"},"ttlConditions":{"description":"TTLConditions are ordered per-label rules; the first matching rule wins.","items":{"$ref":"#/components/schemas/o11y.O11yRetentionRule"},"type":"array"},"type":{"description":"Type is the signal the policy applies to — traces, metrics or logs.","type":"string"}},"type":"object"},"o11y.O11yRetentionSetOut":{"properties":{"message":{"description":"Message says what was done.","type":"string"}},"type":"object"},"o11y.O11yRole":{"properties":{"createdAt":{"description":"CreatedAt is when the role was created.","format":"date-time","type":"string"},"description":{"description":"Description says what the role is for.","type":"string"},"id":{"description":"ID is the role id.","type":"string"},"name":{"description":"Name is the role's name.","type":"string"},"orgId":{"description":"OrgID is the org the role belongs to.","type":"string"},"type":{"description":"Type is how the role came to be — managed by the platform or custom.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it last changed.","format":"date-time","type":"string"}},"type":"object"},"o11y.O11yRoleCreateIn":{"properties":{"description":{"description":"Description says what the role is for.","type":"string"},"name":{"description":"Name is the role's name: lowercase letters and hyphens, at most 50\ncharacters, not starting with the reserved managed-role prefix. Required.","type":"string"},"transactionGroups":{"description":"TransactionGroups are the grants the role carries.","items":{"$ref":"#/components/schemas/o11y.O11yTransactionGroup"},"type":"array"}},"type":"object"},"o11y.O11yRoleCreateOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yCreated","description":"Data carries the new role's id."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yRoleDetail":{"properties":{"createdAt":{"description":"CreatedAt is when the role was created.","format":"date-time","type":"string"},"description":{"description":"Description says what the role is for.","type":"string"},"id":{"description":"ID is the role id.","type":"string"},"name":{"description":"Name is the role's name.","type":"string"},"orgId":{"description":"OrgID is the org the role belongs to.","type":"string"},"transactionGroups":{"description":"TransactionGroups are the grants the role carries.","items":{"$ref":"#/components/schemas/o11y.O11yTransactionGroup"},"type":"array"},"type":{"description":"Type is custom or managed.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it last changed.","format":"date-time","type":"string"}},"type":"object"},"o11y.O11yRoleOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yRoleDetail","description":"Data holds the role and its transaction groups."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yRoleUpdateIn":{"properties":{"description":{"description":"Description says what the role is for. Required — send an empty string to\nclear it.","type":"string"},"transactionGroups":{"description":"TransactionGroups are the grants the role carries. Required — send an\nempty array to clear them.","items":{"$ref":"#/components/schemas/o11y.O11yTransactionGroup"},"type":"array"}},"type":"object"},"o11y.O11yRolesOut":{"properties":{"data":{"description":"Data holds the roles.","items":{"$ref":"#/components/schemas/o11y.O11yRole"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yRoutePoliciesOut":{"properties":{"data":{"description":"Data holds the policies.","items":{"$ref":"#/components/schemas/o11y.GettableRoutePolicy"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yRoutePolicyOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableRoutePolicy","description":"Data holds the policy."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yRoutePolicyUpdateIn":{"properties":{"channels":{"items":{"type":"string"},"type":"array"},"description":{"type":"string"},"expression":{"type":"string"},"kind":{},"name":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.O11yRuleHistoryContributorsOut":{"properties":{"data":{"description":"Data holds the contributors.","items":{"$ref":"#/components/schemas/o11y.GettableRuleStateHistoryContributor"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yRuleHistoryFilterKeysOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableFieldKeys","description":"Data holds the keys."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yRuleHistoryFilterValuesOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableFieldValues","description":"Data holds the values."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yRuleHistoryOverallStatusOut":{"properties":{"data":{"description":"Data holds the windows.","items":{"$ref":"#/components/schemas/o11y.GettableRuleStateWindow"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yRuleHistoryQueryIn":{"properties":{"end":{"format":"int64","type":"integer"},"filters":{"$ref":"#/components/schemas/o11y.FilterSet"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"order":{"type":"string"},"start":{"format":"int64","type":"integer"},"state":{"type":"string"}},"type":"object"},"o11y.O11yRuleHistoryStatsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableRuleStateHistoryStats","description":"Data holds the statistics."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yRuleHistoryTimelineOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableRuleStateTimeline","description":"Data holds the timeline and its paging cursor."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yRuleOut":{"properties":{"data":{"description":"Data holds the rule."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yRuleStateContributorsOut":{"properties":{"data":{"description":"Data holds the contributors.","items":{"$ref":"#/components/schemas/o11y.RuleStateHistoryContributor"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yRuleStateTimelineOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.RuleStateTimeline","description":"Data holds the timeline."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yRuleStatsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.Stats","description":"Data holds the statistics."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yRulesOut":{"properties":{"data":{"description":"Data holds the rules.","items":{},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11ySavedViewCreateOut":{"properties":{"data":{"description":"Data is the new view's id."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11ySavedViewDeleteOut":{"properties":{"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11ySavedViewListOut":{"properties":{"data":{"description":"Data holds the views.","items":{"$ref":"#/components/schemas/o11y.SavedView"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11ySavedViewOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.SavedView","description":"Data holds the view."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11ySavedViewUpdateIn":{"properties":{"category":{"type":"string"},"compositeQuery":{"$ref":"#/components/schemas/o11y.v3.CompositeQuery"},"createdAt":{"format":"date-time","type":"string"},"createdBy":{"type":"string"},"extraData":{"description":"ExtraData is JSON encoded data used by frontend to store additional data","type":"string"},"id":{},"name":{"type":"string"},"sourcePage":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"},"updatedAt":{"format":"date-time","type":"string"},"updatedBy":{"type":"string"},"viewId":{"description":"ViewID is the id of the view to replace, taken from the URL.","type":"string"}},"type":"object"},"o11y.O11ySentryEventOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yEvent","description":"Data is the event."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11ySentryIssueEventsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yEvents","description":"Data holds the occurrences."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11ySentryPostableProject":{"properties":{"name":{"description":"Name is the project's display name. Required.","type":"string"},"platform":{"description":"Platform is the reporting runtime, e.g. go, python, javascript.","type":"string"},"slug":{"description":"Slug is the project's short name. Server-assigned from Name when empty.","type":"string"}},"required":["name"],"type":"object"},"o11y.O11ySentryProject":{"properties":{"createdAt":{"description":"CreatedAt is when the project was created.","format":"date-time","type":"string"},"id":{"description":"ID is the project id.","type":"string"},"name":{"description":"Name is the project's display name.","type":"string"},"platform":{"description":"Platform is the reporting runtime, e.g. go, python, javascript.","type":"string"},"slug":{"description":"Slug is the project's short name.","type":"string"},"status":{"description":"Status is the project's lifecycle state: active or disabled.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the project last changed.","format":"date-time","type":"string"}},"type":"object"},"o11y.O11ySentryProjectOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11ySentryProject","description":"Data is the project."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11ySentryProjects":{"properties":{"items":{"description":"Items are the projects.","items":{"$ref":"#/components/schemas/o11y.O11ySentryProject"},"type":"array"},"total":{"description":"Total is how many the org has.","format":"int64","type":"integer"}},"type":"object"},"o11y.O11ySentryProjectsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11ySentryProjects","description":"Data holds the projects."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11ySentryUpdateIssueIn":{"properties":{"assignee":{"description":"Assignee is who the issue is assigned to.","type":"string"},"id":{"description":"ID is the issue id.","type":"string"},"status":{"description":"Status is the new lifecycle state: unresolved, resolved or ignored.","type":"string"}},"required":["id"],"type":"object"},"o11y.O11yService":{"properties":{"avgDuration":{"description":"AvgDuration is their average latency, nanoseconds.","format":"double","type":"number"},"callRate":{"description":"CallRate is calls per second over the window.","format":"double","type":"number"},"dataWarning":{"$ref":"#/components/schemas/o11y.O11yServiceWarning","description":"DataWarning carries the entry-point operations the numbers were computed\nover."},"errorRate":{"description":"ErrorRate is the percentage of calls that errored.","format":"double","type":"number"},"fourXXRate":{"description":"FourXXRate is the percentage of calls that answered 4xx.","format":"double","type":"number"},"num4XX":{"description":"Num4XX is how many of the calls answered 4xx.","format":"uint64","type":"integer"},"numCalls":{"description":"NumCalls is how many entry-point spans landed in the window.","format":"uint64","type":"integer"},"numErrors":{"description":"NumErrors is how many of the calls errored.","format":"uint64","type":"integer"},"p99":{"description":"Percentile99 is the p99 latency of its entry-point spans, nanoseconds.","format":"double","type":"number"},"serviceName":{"description":"ServiceName is the service.","type":"string"}},"type":"object"},"o11y.O11yServiceAccount":{"properties":{"createdAt":{"description":"CreatedAt is when the account was created.","format":"date-time","type":"string"},"email":{"description":"Email is the address the account authenticates as.","type":"string"},"id":{"description":"ID is the service account id.","type":"string"},"name":{"description":"Name is the account's name.","type":"string"},"orgId":{"description":"OrgID is the org the account belongs to.","type":"string"},"status":{"description":"Status is active or deleted.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it last changed.","format":"date-time","type":"string"}},"type":"object"},"o11y.O11yServiceAccountCreateIn":{"properties":{"name":{"description":"Name is the account's name: a lowercase letter followed by lowercase\nletters, digits or hyphens, at most 50 characters. Required.","type":"string"}},"type":"object"},"o11y.O11yServiceAccountCreateOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yCreated","description":"Data carries the new account's id."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yServiceAccountDetail":{"properties":{"createdAt":{"description":"CreatedAt is when the account was created.","format":"date-time","type":"string"},"email":{"description":"Email is the address the account authenticates as.","type":"string"},"id":{"description":"ID is the service account id.","type":"string"},"name":{"description":"Name is the account's name.","type":"string"},"orgId":{"description":"OrgID is the org the account belongs to.","type":"string"},"serviceAccountRoles":{"description":"ServiceAccountRoles are the account's role assignments.","items":{"$ref":"#/components/schemas/o11y.O11yServiceAccountRole"},"type":"array"},"status":{"description":"Status is active or deleted.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it last changed.","format":"date-time","type":"string"}},"type":"object"},"o11y.O11yServiceAccountOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yServiceAccountDetail","description":"Data holds the account and its role assignments."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yServiceAccountRole":{"properties":{"createdAt":{"description":"CreatedAt is when the role was assigned.","format":"date-time","type":"string"},"id":{"description":"ID is the assignment's own id.","type":"string"},"role":{"$ref":"#/components/schemas/o11y.O11yRole","description":"Role is the role itself."},"roleId":{"description":"RoleID is the role held.","type":"string"},"serviceAccountId":{"description":"ServiceAccountID is the account holding the role.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the assignment last changed.","format":"date-time","type":"string"}},"type":"object"},"o11y.O11yServiceAccountRoleGrantIn":{"properties":{"id":{"description":"RoleID is the id of the role to assign. Required.","type":"string"}},"type":"object"},"o11y.O11yServiceAccountRolesOut":{"properties":{"data":{"description":"Data holds the roles.","items":{"$ref":"#/components/schemas/o11y.O11yRole"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yServiceAccountUpdateIn":{"properties":{"name":{"description":"Name is the account's new name, under the same rules it was created with.\nRequired.","type":"string"}},"type":"object"},"o11y.O11yServiceAccountsOut":{"properties":{"data":{"description":"Data holds the service accounts.","items":{"$ref":"#/components/schemas/o11y.O11yServiceAccount"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yServiceOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.Service","description":"Data holds the service."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yServiceTag":{"properties":{"BoolValues":{"description":"BoolValues are the boolean operands, when the attribute is a bool.","items":{"type":"boolean"},"type":"array"},"Key":{"description":"Key is the span attribute to test.","type":"string"},"NumberValues":{"description":"NumberValues are the numeric operands, when the attribute is a number.","items":{"format":"double","type":"number"},"type":"array"},"Operator":{"description":"Operator is how to test it, e.g. in, not_in.","type":"string"},"StringValues":{"description":"StringValues are the string operands, when the attribute is a string.","items":{"type":"string"},"type":"array"},"TagType":{"description":"TagType says which plane the attribute lives on, e.g. tag or resource.","type":"string"}},"type":"object"},"o11y.O11yServiceWarning":{"properties":{"topLevelOps":{"description":"TopLevelOps are the entry-point operations the profile was computed over.","items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.O11yServicesIn":{"properties":{"end":{"description":"End is the window's end, epoch nanoseconds as a string.","type":"string"},"start":{"description":"Start is the window's start, epoch nanoseconds as a string.","type":"string"},"tags":{"description":"Tags narrow the spans counted, each a span-attribute predicate.","items":{"$ref":"#/components/schemas/o11y.O11yServiceTag"},"type":"array"}},"type":"object"},"o11y.O11yServicesMetadataOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableServicesMetadata","description":"Data holds the services metadata."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yServicesOut":{"properties":{"data":{"description":"Data holds one entry per service.","items":{"$ref":"#/components/schemas/o11y.O11yService"},"type":"array"},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11ySignalFilters":{"properties":{"filters":{"description":"Filters are the attributes offered, in display order.","items":{"$ref":"#/components/schemas/o11y.O11yFilterKey"},"type":"array"},"signal":{"description":"Signal is the signal the filters belong to.","type":"string"}},"type":"object"},"o11y.O11ySignalFiltersOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11ySignalFilters","description":"Data is the signal's entry."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11ySpanMapperCreateIn":{"properties":{"config":{"$ref":"#/components/schemas/o11y.SpanMapperConfig"},"enabled":{"type":"boolean"},"fieldContext":{},"name":{"type":"string"}},"type":"object"},"o11y.O11ySpanMapperGroupOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.SpanMapperGroup","description":"Data is the group."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11ySpanMapperGroupUpdateIn":{"properties":{"condition":{"$ref":"#/components/schemas/o11y.SpanMapperGroupCondition"},"enabled":{"type":"boolean"},"name":{"type":"string"}},"type":"object"},"o11y.O11ySpanMapperGroupsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableSpanMapperGroups","description":"Data holds the groups."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11ySpanMapperOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.SpanMapper","description":"Data is the mapper."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11ySpanMapperUpdateIn":{"properties":{"config":{"$ref":"#/components/schemas/o11y.SpanMapperConfig"},"enabled":{"type":"boolean"},"fieldContext":{}},"type":"object"},"o11y.O11ySpanMappersOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableSpanMappers","description":"Data holds the mappers."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11ySpanPercentile":{"properties":{"percentiles":{"$ref":"#/components/schemas/o11y.O11yPercentiles","description":"Percentiles are the peer group's duration percentiles."},"position":{"$ref":"#/components/schemas/o11y.O11yPercentilePosition","description":"Position is where the given duration lands."}},"type":"object"},"o11y.O11ySpanPercentileIn":{"properties":{"end":{"description":"End is the window end, as epoch nanoseconds.","format":"uint64","type":"integer"},"name":{"description":"Name is the span name whose peers are compared. Required.","type":"string"},"resourceAttributes":{"additionalProperties":{"type":"string"},"description":"ResourceAttributes narrow the peer group to spans carrying them all.","type":"object"},"serviceName":{"description":"ServiceName is the service the span belongs to. Required.","type":"string"},"spanDuration":{"description":"SpanDuration is the span's duration in nanoseconds.","format":"int64","type":"integer"},"start":{"description":"Start is the window start, as epoch nanoseconds.","format":"uint64","type":"integer"}},"required":["name","serviceName"],"type":"object"},"o11y.O11ySpanPercentileOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11ySpanPercentile","description":"Data is the placement."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yStat":{"properties":{"time":{"description":"Time is the start of the bucket.","format":"date-time","type":"string"},"value":{"description":"Value is how many events fell in it.","format":"uint64","type":"integer"}},"type":"object"},"o11y.O11yStatefulSetListOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.StatefulSetListResponse","description":"Data holds the statefulset records."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yStats":{"properties":{"items":{"description":"Items are the buckets, oldest first.","items":{"$ref":"#/components/schemas/o11y.O11yStat"},"type":"array"}},"type":"object"},"o11y.O11yStatsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yStats","description":"Data holds the buckets."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11ySubstituteVarsOut":{"properties":{"data":{"description":"Data is the resolved composite query, with its variables substituted."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yTable":{"properties":{"columns":{"description":"Columns names each position in a row.","items":{"type":"string"},"type":"array"},"rows":{"description":"Rows are the result rows, each as long as Columns.","items":{"items":{},"type":"array"},"type":"array"}},"type":"object"},"o11y.O11yTagFilter":{"properties":{"boolValues":{"description":"BoolValues are the values matched when the tag holds booleans.","items":{"type":"boolean"},"type":"array"},"key":{"description":"Key is the tag to test.","type":"string"},"numberValues":{"description":"NumberValues are the values matched when the tag holds numbers.","items":{"format":"double","type":"number"},"type":"array"},"operator":{"description":"Operator is the comparison to apply — in, not_in, equals, contains and\nthe other operators the trace filter grammar names.","type":"string"},"stringValues":{"description":"StringValues are the values matched when the tag holds strings.","items":{"type":"string"},"type":"array"},"tagType":{"description":"TagType says which kind of value the tag holds: string, number or bool.","type":"string"}},"type":"object"},"o11y.O11yTagQuery":{"properties":{"boolValues":{"description":"BoolValues are the boolean values to test against.","items":{"type":"boolean"},"type":"array"},"key":{"description":"Key is the tag to test.","type":"string"},"numberValues":{"description":"NumberValues are the numeric values to test against.","items":{"format":"double","type":"number"},"type":"array"},"operator":{"description":"Operator is the comparison, e.g. in, nin, contains, exists.","type":"string"},"stringValues":{"description":"StringValues are the string values to test against.","items":{"type":"string"},"type":"array"},"tagType":{"description":"TagType is where the tag lives, e.g. ResourceAttribute, SpanAttribute.","type":"string"}},"type":"object"},"o11y.O11yTelemetryField":{"properties":{"dataType":{"description":"DataType is the field's data type, e.g. string, int64, float64, bool.","type":"string"},"name":{"description":"Name is the field's name.","type":"string"},"type":{"description":"Type is where the field lives: attributes or resources.","type":"string"}},"type":"object"},"o11y.O11yTestNotificationOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yTestNotificationResult","description":"Data holds the fired-series count and a status message."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yTestNotificationResult":{"properties":{"alertCount":{"description":"AlertCount is how many series would alert for the tested rule.","format":"int64","type":"integer"},"message":{"description":"Message is a human-readable status, e.g. \"notification sent\".","type":"string"}},"type":"object"},"o11y.O11yTestRuleOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableTestRule","description":"Data holds how many series would alert."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yToggle":{"properties":{"enabled":{"description":"Enabled says whether the feature is on.","type":"boolean"}},"type":"object"},"o11y.O11yTopLevelOpsIn":{"properties":{"end":{"description":"End is the window's end, epoch nanoseconds as a string; empty means\nunbounded.","type":"string"},"service":{"description":"Service narrows the map to one service when set.","type":"string"},"start":{"description":"Start is the window's start, epoch nanoseconds as a string; empty means\nunbounded.","type":"string"}},"type":"object"},"o11y.O11yTrace":{"properties":{"count":{"description":"Count is how many captured errors carried it.","format":"uint64","type":"integer"},"firstSeen":{"description":"FirstSeen is when the earliest of them was recorded.","format":"date-time","type":"string"},"lastSeen":{"description":"LastSeen is when the latest was.","format":"date-time","type":"string"},"message":{"description":"Message is the latest error message seen on the trace.","type":"string"},"traceId":{"description":"TraceID is the trace id.","type":"string"}},"type":"object"},"o11y.O11yTraceAggregationsIn":{"properties":{"aggregations":{"items":{"$ref":"#/components/schemas/o11y.SpanAggregation"},"type":"array"}},"type":"object"},"o11y.O11yTraceAggregationsOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableTraceAggregations","description":"Data holds one result per aggregation asked for."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yTraceDetail":{"properties":{"events":{"description":"Events are the error events carrying the trace id.","items":{"$ref":"#/components/schemas/o11y.O11yEvent"},"type":"array"},"traceId":{"description":"TraceID is the trace that was read.","type":"string"}},"type":"object"},"o11y.O11yTraceFlamegraphIn":{"properties":{"selectFields":{"items":{"$ref":"#/components/schemas/o11y.TelemetryFieldKey"},"type":"array"},"selectedSpanId":{"type":"string"}},"type":"object"},"o11y.O11yTraceFlamegraphOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableFlamegraphTrace","description":"Data holds the flamegraph."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yTraceOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yTraceDetail","description":"Data holds the trace and its events."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yTraceSpanWindow":{"properties":{"columns":{"description":"Columns names the fields each row carries, in row order.","items":{"type":"string"},"type":"array"},"endTimestampMillis":{"description":"EndTimestampMillis is when it closes.","format":"uint64","type":"integer"},"events":{"description":"Events are the rows, each positionally matching Columns.","items":{"items":{},"type":"array"},"type":"array"},"isSubTree":{"description":"IsSubTree says the window is a subtree of the trace rather than the whole\nof it.","type":"boolean"},"startTimestampMillis":{"description":"StartTimestampMillis is when the window opens.","format":"uint64","type":"integer"}},"type":"object"},"o11y.O11yTraceWaterfallIn":{"properties":{"selectedSpanId":{"type":"string"},"uncollapsedSpans":{"items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.O11yTraceWaterfallOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.GettableWaterfallTrace","description":"Data holds the waterfall."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yTraces":{"properties":{"items":{"description":"Items are the traces, most recent first.","items":{"$ref":"#/components/schemas/o11y.O11yTrace"},"type":"array"}},"type":"object"},"o11y.O11yTracesOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yTraces","description":"Data holds the traces."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.O11yTransaction":{"properties":{"object":{"$ref":"#/components/schemas/o11y.O11yObject","description":"Object is the resource the verb would act on."},"relation":{"description":"Relation is the verb being asked about, e.g. read, create, update, delete.","type":"string"}},"type":"object"},"o11y.O11yTransactionGroup":{"properties":{"objectGroup":{"$ref":"#/components/schemas/o11y.O11yObjectGroup","description":"ObjectGroup is the set of objects it allows the verb on."},"relation":{"description":"Relation is the verb the grant allows.","type":"string"}},"type":"object"},"o11y.O11yTransactionResult":{"properties":{"authorized":{"description":"Authorized says whether the caller may do it.","type":"boolean"},"object":{"$ref":"#/components/schemas/o11y.O11yObject","description":"Object is the resource it would act on."},"relation":{"description":"Relation is the verb that was asked about.","type":"string"}},"type":"object"},"o11y.O11yTreemapEntry":{"properties":{"metricName":{"description":"MetricName is the metric's name.","type":"string"},"percentage":{"description":"Percentage is the metric's share, in percent.","format":"double","type":"number"},"totalValue":{"description":"TotalValue is the metric's absolute count.","format":"uint64","type":"integer"}},"type":"object"},"o11y.O11yUpdatablePreference":{"properties":{"value":{"description":"Value is the value to set; its JSON type must match the preference's\ndeclared value type."}},"type":"object"},"o11y.O11yUpdatableQuickFilters":{"properties":{"filters":{"description":"Filters are the attributes to offer, in the order to offer them.","items":{"$ref":"#/components/schemas/o11y.O11yFilterKey"},"type":"array"},"signal":{"description":"Signal is the signal whose filters are being replaced.","type":"string"}},"type":"object"},"o11y.O11yUpdateAccountIn":{"properties":{"config":{"$ref":"#/components/schemas/o11y.UpdatableAccountConfig"}},"type":"object"},"o11y.O11yUpdateIngestionKeyIn":{"properties":{"expires_at":{"format":"date-time","type":"string"},"name":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.O11yUpdateLimitIn":{"properties":{"config":{"$ref":"#/components/schemas/o11y.LimitConfig"},"tags":{"items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.O11yUpdateServiceIn":{"properties":{"config":{"$ref":"#/components/schemas/o11y.ServiceConfig"}},"type":"object"},"o11y.O11yUsageItem":{"properties":{"count":{"description":"Count is how many spans were ingested in the bucket.","format":"uint64","type":"integer"},"time":{"description":"Time is the bucket start.","format":"date-time","type":"string"},"timestamp":{"description":"Timestamp is the bucket start, as epoch nanoseconds.","format":"uint64","type":"integer"}},"type":"object"},"o11y.O11yUser":{"properties":{"createdAt":{"format":"date-time","type":"string"},"displayName":{"type":"string"},"email":{"type":"string"},"id":{"type":"string"},"isRoot":{"type":"boolean"},"orgId":{"type":"string"},"status":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"o11y.O11yUserOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yUser"},"status":{"type":"string"}},"type":"object"},"o11y.O11yVersionOut":{"properties":{"ee":{"description":"EE says whether an enterprise edition is present; \"N\" in this build.","type":"string"},"setupCompleted":{"description":"SetupCompleted says whether the first user has been created.","type":"boolean"},"version":{"description":"Version is the build version.","type":"string"}},"type":"object"},"o11y.O11yWidgetQueryRange":{"properties":{"data":{"description":"Data is the query result payload, carried verbatim as open JSON."},"meta":{"description":"Meta is the execution stats, carried verbatim as open JSON."},"type":{"description":"Type is the request type the result answers, e.g. time_series, scalar.","type":"string"},"warning":{"description":"Warning is any query warning, carried verbatim as open JSON when present."}},"type":"object"},"o11y.O11yWidgetQueryRangeOut":{"properties":{"data":{"$ref":"#/components/schemas/o11y.O11yWidgetQueryRange","description":"Data is the query-range result."},"status":{"description":"Status is \"success\".","type":"string"}},"type":"object"},"o11y.OAuth2":{"properties":{"TLSConfig":{"$ref":"#/components/schemas/o11y.TLSConfig"},"audience":{"description":"Audience optionally specifies the intended audience of the\nrequest.  If empty, the value of TokenURL is used as the\nintended audience. Only used if\nGrantType is set to \"urn:ietf:params:oauth:grant-type:jwt-bearer\".","type":"string"},"claims":{"additionalProperties":{},"description":"Claims is a map of claims to be added to the JWT token. Only used if\nGrantType is set to \"urn:ietf:params:oauth:grant-type:jwt-bearer\".","type":"object"},"client_certificate_key":{},"client_certificate_key_file":{"type":"string"},"client_certificate_key_id":{"type":"string"},"client_certificate_key_ref":{"description":"ClientCertificateKeyRef is the name of the secret within the secret manager to use as the client\nsecret.","type":"string"},"client_id":{"type":"string"},"client_secret":{},"client_secret_file":{"type":"string"},"client_secret_ref":{"description":"ClientSecretRef is the name of the secret within the secret manager to use as the client\nsecret.","type":"string"},"endpoint_params":{"additionalProperties":{"type":"string"},"type":"object"},"grant_type":{"description":"GrantType is the OAuth2 grant type to use. It can be one of\n\"client_credentials\" or \"urn:ietf:params:oauth:grant-type:jwt-bearer\" (RFC 7523).\nDefault value is \"client_credentials\"","type":"string"},"iss":{"description":"Iss is the OAuth client identifier used when communicating with\nthe configured OAuth provider. Default value is client_id. Only used if\nGrantType is set to \"urn:ietf:params:oauth:grant-type:jwt-bearer\".","type":"string"},"no_proxy":{"description":"NoProxy contains addresses that should not use a proxy.","type":"string"},"proxy_connect_header":{"additionalProperties":{"items":{},"type":"array"},"description":"ProxyConnectHeader optionally specifies headers to send to\nproxies during CONNECT requests. Assume that at least _some_ of\nthese headers are going to contain secrets and use Secret as the\nvalue type instead of string.","type":"object"},"proxy_from_environment":{"description":"ProxyFromEnvironment makes use of net/http ProxyFromEnvironment function\nto determine proxies.","type":"boolean"},"proxy_url":{"description":"HTTP proxy server to use to connect to the targets."},"scopes":{"items":{"type":"string"},"type":"array"},"signature_algorithm":{"description":"SignatureAlgorithm is the RSA algorithm used to sign JWT token. Only used if\nGrantType is set to \"urn:ietf:params:oauth:grant-type:jwt-bearer\".\nDefault value is RS256 and valid values RS256, RS384, RS512","type":"string"},"token_url":{"type":"string"}},"type":"object"},"o11y.OldAWSCollectionStrategy":{"properties":{"aws_logs":{"$ref":"#/components/schemas/o11y.OldAWSLogsStrategy"},"aws_metrics":{"$ref":"#/components/schemas/o11y.OldAWSMetricsStrategy"},"provider":{"type":"string"},"s3_buckets":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"}},"type":"object"},"o11y.OldAWSLogsStrategy":{"properties":{"cloudwatch_logs_subscriptions":{"items":{"properties":{"filter_pattern":{"type":"string"},"log_group_name_prefix":{"type":"string"}},"type":"object"},"type":"array"}},"type":"object"},"o11y.OldAWSMetricsStrategy":{"properties":{"cloudwatch_metric_stream_filters":{"items":{"properties":{"MetricNames":{"items":{"type":"string"},"type":"array"},"Namespace":{"type":"string"}},"type":"object"},"type":"array"}},"type":"object"},"o11y.OpsGenieConfig":{"properties":{"NotifierConfig":{"$ref":"#/components/schemas/o11y.NotifierConfig"},"actions":{"type":"string"},"api_key":{},"api_key_file":{"type":"string"},"api_url":{},"description":{"type":"string"},"details":{"additionalProperties":{"type":"string"},"type":"object"},"entity":{"type":"string"},"http_config":{"$ref":"#/components/schemas/o11y.HTTPClientConfig"},"message":{"type":"string"},"note":{"type":"string"},"priority":{"type":"string"},"responders":{"items":{"$ref":"#/components/schemas/o11y.OpsGenieConfigResponder"},"type":"array"},"source":{"type":"string"},"tags":{"type":"string"},"update_alerts":{"type":"boolean"}},"type":"object"},"o11y.OpsGenieConfigResponder":{"properties":{"id":{"description":"One of those 3 should be filled.","type":"string"},"name":{"type":"string"},"type":{"description":"team, user, escalation, schedule etc.","type":"string"},"username":{"type":"string"}},"type":"object"},"o11y.OrderBy":{"properties":{"columnName":{"type":"string"},"order":{"type":"string"}},"type":"object"},"o11y.OrderByKey":{"properties":{"description":{"type":"string"},"fieldContext":{},"fieldDataType":{},"name":{"type":"string"},"signal":{},"unit":{"type":"string"}},"required":["name"],"type":"object"},"o11y.OtelSpanRef":{"properties":{"refType":{"type":"string"},"spanId":{"type":"string"},"traceId":{"type":"string"}},"type":"object"},"o11y.PagerdutyConfig":{"properties":{"NotifierConfig":{"$ref":"#/components/schemas/o11y.NotifierConfig"},"class":{"type":"string"},"client":{"type":"string"},"client_url":{"type":"string"},"component":{"type":"string"},"description":{"type":"string"},"details":{"additionalProperties":{},"type":"object"},"group":{"type":"string"},"http_config":{"$ref":"#/components/schemas/o11y.HTTPClientConfig"},"images":{"items":{"$ref":"#/components/schemas/o11y.PagerdutyImage"},"type":"array"},"links":{"items":{"$ref":"#/components/schemas/o11y.PagerdutyLink"},"type":"array"},"routing_key":{},"routing_key_file":{"type":"string"},"service_key":{},"service_key_file":{"type":"string"},"severity":{"type":"string"},"source":{"type":"string"},"timeout":{"description":"Timeout is the maximum time allowed to invoke the pagerduty. Setting this to 0\ndoes not impose a timeout.","format":"int64","type":"integer"},"url":{}},"type":"object"},"o11y.PagerdutyImage":{"properties":{"alt":{"type":"string"},"href":{"type":"string"},"src":{"type":"string"}},"type":"object"},"o11y.PagerdutyLink":{"properties":{"href":{"type":"string"},"text":{"type":"string"}},"type":"object"},"o11y.Pagination":{"properties":{"page":{"format":"int64","type":"integer"},"pages":{"format":"int64","type":"integer"},"per_page":{"format":"int64","type":"integer"},"total":{"format":"int64","type":"integer"}},"type":"object"},"o11y.PodCountByPhase":{"properties":{"failed":{"format":"int64","type":"integer"},"pending":{"format":"int64","type":"integer"},"running":{"format":"int64","type":"integer"},"succeeded":{"format":"int64","type":"integer"},"unknown":{"format":"int64","type":"integer"}},"type":"object"},"o11y.PodCountsByPhase":{"properties":{"failed":{"format":"int64","type":"integer"},"pending":{"format":"int64","type":"integer"},"running":{"format":"int64","type":"integer"},"succeeded":{"format":"int64","type":"integer"},"unknown":{"format":"int64","type":"integer"}},"type":"object"},"o11y.PodListRecord":{"properties":{"countByPhase":{"$ref":"#/components/schemas/o11y.PodCountByPhase"},"meta":{"additionalProperties":{"type":"string"},"type":"object"},"podCPU":{"format":"double","type":"number"},"podCPULimit":{"format":"double","type":"number"},"podCPURequest":{"format":"double","type":"number"},"podMemory":{"format":"double","type":"number"},"podMemoryLimit":{"format":"double","type":"number"},"podMemoryRequest":{"format":"double","type":"number"},"podUID":{"type":"string"},"restartCount":{"format":"int64","type":"integer"}},"type":"object"},"o11y.PodListRequest":{"properties":{"end":{"description":"epoch time in ms","format":"int64","type":"integer"},"filters":{"$ref":"#/components/schemas/o11y.FilterSet"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.AttributeKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.OrderBy"},"start":{"description":"epoch time in ms","format":"int64","type":"integer"}},"type":"object"},"o11y.PodListResponse":{"properties":{"records":{"items":{"$ref":"#/components/schemas/o11y.PodListRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{"type":"string"}},"type":"object"},"o11y.PodRecord":{"properties":{"meta":{"additionalProperties":{"type":"string"},"type":"object"},"podAge":{"format":"int64","type":"integer"},"podCPU":{"format":"double","type":"number"},"podCPULimit":{"format":"double","type":"number"},"podCPURequest":{"format":"double","type":"number"},"podCountsByPhase":{"$ref":"#/components/schemas/o11y.PodCountsByPhase"},"podMemory":{"format":"double","type":"number"},"podMemoryLimit":{"format":"double","type":"number"},"podMemoryRequest":{"format":"double","type":"number"},"podPhase":{},"podUID":{"type":"string"}},"type":"object"},"o11y.Pods":{"properties":{"endTimeBeforeRetention":{"type":"boolean"},"records":{"items":{"$ref":"#/components/schemas/o11y.PodRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{},"warning":{"$ref":"#/components/schemas/o11y.QueryWarnData"}},"type":"object"},"o11y.PostableAccountConfig":{"properties":{"AgentVersion":{"description":"as agent version is common for all providers, we can keep it at top level of this struct","type":"string"},"aws":{"$ref":"#/components/schemas/o11y.AWSPostableAccountConfig"},"azure":{"$ref":"#/components/schemas/o11y.AzureAccountConfig"},"gcp":{"$ref":"#/components/schemas/o11y.GCPAccountConfig"}},"type":"object"},"o11y.PostableChannel":{"properties":{"Receiver":{"$ref":"#/components/schemas/o11y.Receiver"},"googlechat_configs":{"items":{"$ref":"#/components/schemas/o11y.GoogleChatReceiverConfig"},"type":"array"}},"type":"object"},"o11y.PostableClusters":{"properties":{"end":{"format":"int64","type":"integer"},"filter":{"$ref":"#/components/schemas/o11y.Filter"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.GroupByKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.querybuildertypesv5.OrderBy"},"start":{"format":"int64","type":"integer"}},"type":"object"},"o11y.PostableDaemonSets":{"properties":{"end":{"format":"int64","type":"integer"},"filter":{"$ref":"#/components/schemas/o11y.Filter"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.GroupByKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.querybuildertypesv5.OrderBy"},"start":{"format":"int64","type":"integer"}},"type":"object"},"o11y.PostableDeployments":{"properties":{"end":{"format":"int64","type":"integer"},"filter":{"$ref":"#/components/schemas/o11y.Filter"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.GroupByKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.querybuildertypesv5.OrderBy"},"start":{"format":"int64","type":"integer"}},"type":"object"},"o11y.PostableHost":{"properties":{"name":{"type":"string"}},"type":"object"},"o11y.PostableHosts":{"properties":{"end":{"format":"int64","type":"integer"},"filter":{"$ref":"#/components/schemas/o11y.HostFilter"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.GroupByKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.querybuildertypesv5.OrderBy"},"start":{"format":"int64","type":"integer"}},"type":"object"},"o11y.PostableIngestionKey":{"properties":{"expires_at":{"format":"date-time","type":"string"},"name":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.PostableJobs":{"properties":{"end":{"format":"int64","type":"integer"},"filter":{"$ref":"#/components/schemas/o11y.Filter"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.GroupByKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.querybuildertypesv5.OrderBy"},"start":{"format":"int64","type":"integer"}},"type":"object"},"o11y.PostableNamespaces":{"properties":{"end":{"format":"int64","type":"integer"},"filter":{"$ref":"#/components/schemas/o11y.Filter"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.GroupByKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.querybuildertypesv5.OrderBy"},"start":{"format":"int64","type":"integer"}},"type":"object"},"o11y.PostableNodes":{"properties":{"end":{"format":"int64","type":"integer"},"filter":{"$ref":"#/components/schemas/o11y.Filter"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.GroupByKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.querybuildertypesv5.OrderBy"},"start":{"format":"int64","type":"integer"}},"type":"object"},"o11y.PostablePipeline":{"properties":{"alias":{"type":"string"},"config":{"items":{},"type":"array"},"description":{"type":"string"},"enabled":{"type":"boolean"},"filter":{"$ref":"#/components/schemas/o11y.FilterSet"},"id":{"type":"string"},"name":{"type":"string"},"orderId":{"format":"int64","type":"integer"}},"type":"object"},"o11y.PostablePlannedMaintenance":{"properties":{"alertIds":{"items":{"type":"string"},"type":"array"},"description":{"type":"string"},"name":{"type":"string"},"schedule":{},"scope":{"type":"string"}},"type":"object"},"o11y.PostablePods":{"properties":{"end":{"format":"int64","type":"integer"},"filter":{"$ref":"#/components/schemas/o11y.Filter"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.GroupByKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.querybuildertypesv5.OrderBy"},"start":{"format":"int64","type":"integer"}},"type":"object"},"o11y.PostableProfile":{"properties":{"existing_observability_tool":{"type":"string"},"has_existing_observability_tool":{"type":"boolean"},"logs_scale_per_day_in_gb":{"format":"int64","type":"integer"},"number_of_hosts":{"format":"int64","type":"integer"},"number_of_services":{"format":"int64","type":"integer"},"reasons_for_interest_in_o11y":{"items":{"type":"string"},"type":"array"},"timeline_for_migrating_to_o11y":{"type":"string"},"uses_otel":{"type":"boolean"},"where_did_you_discover_o11y":{"type":"string"}},"type":"object"},"o11y.PostableRoutePolicy":{"properties":{"channels":{"items":{"type":"string"},"type":"array"},"description":{"type":"string"},"expression":{"type":"string"},"kind":{},"name":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.PostableSpanMapperGroup":{"properties":{"condition":{"$ref":"#/components/schemas/o11y.SpanMapperGroupCondition"},"enabled":{"type":"boolean"},"name":{"type":"string"}},"type":"object"},"o11y.PostableStatefulSets":{"properties":{"end":{"format":"int64","type":"integer"},"filter":{"$ref":"#/components/schemas/o11y.Filter"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.GroupByKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.querybuildertypesv5.OrderBy"},"start":{"format":"int64","type":"integer"}},"type":"object"},"o11y.PostableVolumes":{"properties":{"end":{"format":"int64","type":"integer"},"filter":{"$ref":"#/components/schemas/o11y.Filter"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.GroupByKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.querybuildertypesv5.OrderBy"},"start":{"format":"int64","type":"integer"}},"type":"object"},"o11y.ProcessListRecord":{"properties":{"meta":{"additionalProperties":{"type":"string"},"type":"object"},"processCMD":{"type":"string"},"processCMDLine":{"type":"string"},"processCPU":{"format":"double","type":"number"},"processID":{"type":"string"},"processMemory":{"format":"double","type":"number"},"processName":{"type":"string"}},"type":"object"},"o11y.ProcessListRequest":{"properties":{"end":{"description":"epoch time in ms","format":"int64","type":"integer"},"filters":{"$ref":"#/components/schemas/o11y.FilterSet"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.AttributeKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.OrderBy"},"start":{"description":"epoch time in ms","format":"int64","type":"integer"}},"type":"object"},"o11y.ProcessListResponse":{"properties":{"records":{"items":{"$ref":"#/components/schemas/o11y.ProcessListRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{"type":"string"}},"type":"object"},"o11y.PromQuery":{"properties":{"disabled":{"type":"boolean"},"legend":{"type":"string"},"query":{"type":"string"},"stats":{"type":"string"}},"type":"object"},"o11y.ProviderIntegrationConfig":{"properties":{"aws":{"$ref":"#/components/schemas/o11y.AWSIntegrationConfig"},"azure":{"$ref":"#/components/schemas/o11y.AzureIntegrationConfig"},"gcp":{"$ref":"#/components/schemas/o11y.GCPIntegrationConfig"}},"type":"object"},"o11y.PushoverConfig":{"properties":{"NotifierConfig":{"$ref":"#/components/schemas/o11y.NotifierConfig"},"device":{"type":"string"},"expire":{"format":"int64","type":"integer"},"html":{"type":"boolean"},"http_config":{"$ref":"#/components/schemas/o11y.HTTPClientConfig"},"message":{"type":"string"},"monospace":{"type":"boolean"},"priority":{"type":"string"},"retry":{"format":"int64","type":"integer"},"sound":{"type":"string"},"title":{"type":"string"},"token":{},"token_file":{"type":"string"},"ttl":{"format":"int64","type":"integer"},"url":{"type":"string"},"url_title":{"type":"string"},"user_key":{},"user_key_file":{"type":"string"}},"type":"object"},"o11y.QueryEnvelope":{"properties":{"spec":{"description":"Spec is the deferred decoding of the query if any."},"type":{"description":"Type is the type of the query."}},"type":"object"},"o11y.QueryRangeParamsV3":{"properties":{"compositeQuery":{"$ref":"#/components/schemas/o11y.v3.CompositeQuery"},"end":{"format":"int64","type":"integer"},"formatForWeb":{"type":"boolean"},"noCache":{"type":"boolean"},"start":{"format":"int64","type":"integer"},"step":{"description":"step is in seconds; used for prometheus queries","format":"int64","type":"integer"},"variables":{"additionalProperties":{},"type":"object"}},"type":"object"},"o11y.QueryRangeRequest":{"properties":{"compositeQuery":{"$ref":"#/components/schemas/o11y.CompositeQuery","description":"CompositeQuery is the composite query to use for the request."},"end":{"description":"End is the end time of the query in epoch milliseconds.","format":"uint64","type":"integer"},"formatOptions":{"$ref":"#/components/schemas/o11y.FormatOptions"},"noCache":{"description":"NoCache is a flag to disable caching for the request.","type":"boolean"},"requestType":{"description":"RequestType is the type of the request."},"schemaVersion":{"description":"SchemaVersion is the version of the schema to use for the request payload.","type":"string"},"start":{"description":"Start is the start time of the query in epoch milliseconds.","format":"uint64","type":"integer"},"variables":{"additionalProperties":{"$ref":"#/components/schemas/o11y.VariableItem"},"description":"Variables is the variables to use for the request.","type":"object"}},"type":"object"},"o11y.QueryWarnData":{"properties":{"message":{"type":"string"},"url":{"type":"string"},"warnings":{"items":{"$ref":"#/components/schemas/o11y.QueryWarnDataAdditional"},"type":"array"}},"type":"object"},"o11y.QueryWarnDataAdditional":{"properties":{"message":{"type":"string"}},"type":"object"},"o11y.Receiver":{"properties":{"discord_configs":{"items":{"$ref":"#/components/schemas/o11y.DiscordConfig"},"type":"array"},"email_configs":{"items":{"$ref":"#/components/schemas/o11y.EmailConfig"},"type":"array"},"incidentio_configs":{"items":{"$ref":"#/components/schemas/o11y.IncidentioConfig"},"type":"array"},"jira_configs":{"items":{"$ref":"#/components/schemas/o11y.JiraConfig"},"type":"array"},"mattermost_configs":{"items":{"$ref":"#/components/schemas/o11y.MattermostConfig"},"type":"array"},"msteams_configs":{"items":{"$ref":"#/components/schemas/o11y.MSTeamsConfig"},"type":"array"},"msteamsv2_configs":{"items":{"$ref":"#/components/schemas/o11y.MSTeamsV2Config"},"type":"array"},"name":{"description":"A unique identifier for this receiver.","type":"string"},"opsgenie_configs":{"items":{"$ref":"#/components/schemas/o11y.OpsGenieConfig"},"type":"array"},"pagerduty_configs":{"items":{"$ref":"#/components/schemas/o11y.PagerdutyConfig"},"type":"array"},"pushover_configs":{"items":{"$ref":"#/components/schemas/o11y.PushoverConfig"},"type":"array"},"rocketchat_configs":{"items":{"$ref":"#/components/schemas/o11y.RocketchatConfig"},"type":"array"},"slack_configs":{"items":{"$ref":"#/components/schemas/o11y.SlackConfig"},"type":"array"},"sns_configs":{"items":{"$ref":"#/components/schemas/o11y.SNSConfig"},"type":"array"},"telegram_configs":{"items":{"$ref":"#/components/schemas/o11y.TelegramConfig"},"type":"array"},"victorops_configs":{"items":{"$ref":"#/components/schemas/o11y.VictorOpsConfig"},"type":"array"},"webex_configs":{"items":{"$ref":"#/components/schemas/o11y.WebexConfig"},"type":"array"},"webhook_configs":{"items":{"$ref":"#/components/schemas/o11y.WebhookConfig"},"type":"array"},"wechat_configs":{"items":{"$ref":"#/components/schemas/o11y.WechatConfig"},"type":"array"}},"type":"object"},"o11y.ReleStateItem":{"properties":{"end":{"format":"int64","type":"integer"},"start":{"format":"int64","type":"integer"},"state":{}},"type":"object"},"o11y.RocketchatAttachmentAction":{"properties":{"image_url":{"type":"string"},"is_webview":{"type":"boolean"},"msg":{"type":"string"},"msg_in_chat_window":{"type":"boolean"},"msg_processing_type":{"type":"string"},"text":{"type":"string"},"type":{"type":"string"},"url":{"type":"string"},"webview_height_ratio":{"type":"string"}},"type":"object"},"o11y.RocketchatAttachmentField":{"properties":{"short":{"type":"boolean"},"title":{"type":"string"},"value":{"type":"string"}},"type":"object"},"o11y.RocketchatConfig":{"properties":{"NotifierConfig":{"$ref":"#/components/schemas/o11y.NotifierConfig"},"actions":{"items":{"$ref":"#/components/schemas/o11y.RocketchatAttachmentAction"},"type":"array"},"api_url":{},"channel":{"description":"RocketChat channel override, (like #other-channel or @username).","type":"string"},"color":{"type":"string"},"emoji":{"type":"string"},"fields":{"items":{"$ref":"#/components/schemas/o11y.RocketchatAttachmentField"},"type":"array"},"http_config":{"$ref":"#/components/schemas/o11y.HTTPClientConfig"},"icon_url":{"type":"string"},"image_url":{"type":"string"},"link_names":{"type":"boolean"},"short_fields":{"type":"boolean"},"text":{"type":"string"},"thumb_url":{"type":"string"},"title":{"type":"string"},"title_link":{"type":"string"},"token":{},"token_file":{"type":"string"},"token_id":{},"token_id_file":{"type":"string"}},"type":"object"},"o11y.RuleStateHistory":{"properties":{"fingerprint":{"format":"uint64","type":"integer"},"labels":{},"overallState":{"description":"One of [\"normal\", \"firing\"]"},"overallStateChanged":{"type":"boolean"},"relatedLogsLink":{"type":"string"},"relatedTracesLink":{"type":"string"},"ruleID":{"type":"string"},"ruleName":{"type":"string"},"state":{"description":"One of [\"normal\", \"firing\", \"nodata\", \"muted\"]"},"stateChanged":{"type":"boolean"},"unixMilli":{"format":"int64","type":"integer"},"value":{"format":"double","type":"number"}},"type":"object"},"o11y.RuleStateHistoryContributor":{"properties":{"count":{"format":"uint64","type":"integer"},"fingerprint":{"format":"uint64","type":"integer"},"labels":{},"relatedLogsLink":{"type":"string"},"relatedTracesLink":{"type":"string"}},"type":"object"},"o11y.RuleStateTimeline":{"properties":{"items":{"items":{"$ref":"#/components/schemas/o11y.RuleStateHistory"},"type":"array"},"labels":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"total":{"format":"uint64","type":"integer"}},"type":"object"},"o11y.SNSConfig":{"properties":{"NotifierConfig":{"$ref":"#/components/schemas/o11y.NotifierConfig"},"api_url":{"type":"string"},"attributes":{"additionalProperties":{"type":"string"},"type":"object"},"http_config":{"$ref":"#/components/schemas/o11y.HTTPClientConfig"},"message":{"type":"string"},"phone_number":{"type":"string"},"sigv4":{"$ref":"#/components/schemas/o11y.SigV4Config"},"subject":{"type":"string"},"target_arn":{"type":"string"},"topic_arn":{"type":"string"}},"type":"object"},"o11y.SavedView":{"properties":{"category":{"type":"string"},"compositeQuery":{"$ref":"#/components/schemas/o11y.v3.CompositeQuery"},"createdAt":{"format":"date-time","type":"string"},"createdBy":{"type":"string"},"extraData":{"description":"ExtraData is JSON encoded data used by frontend to store additional data","type":"string"},"id":{},"name":{"type":"string"},"sourcePage":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"},"updatedAt":{"format":"date-time","type":"string"},"updatedBy":{"type":"string"}},"type":"object"},"o11y.Series":{"properties":{"labels":{"additionalProperties":{"type":"string"},"type":"object"},"labelsArray":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array"},"values":{"items":{},"type":"array"}},"type":"object"},"o11y.Service":{"properties":{"assets":{"$ref":"#/components/schemas/o11y.ServiceAssets"},"cloudIntegrationService":{"$ref":"#/components/schemas/o11y.CloudIntegrationService"},"dataCollected":{"$ref":"#/components/schemas/o11y.DataCollected"},"icon":{"type":"string"},"id":{"type":"string"},"overview":{"description":"markdown","type":"string"},"supportedSignals":{"$ref":"#/components/schemas/o11y.SupportedSignals"},"title":{"type":"string"}},"type":"object"},"o11y.ServiceAssets":{"properties":{"dashboards":{"items":{"$ref":"#/components/schemas/o11y.ServiceDashboard"},"type":"array"}},"type":"object"},"o11y.ServiceConfig":{"properties":{"aws":{"$ref":"#/components/schemas/o11y.AWSServiceConfig"},"azure":{"$ref":"#/components/schemas/o11y.AzureServiceConfig"},"gcp":{"$ref":"#/components/schemas/o11y.GCPServiceConfig"}},"type":"object"},"o11y.ServiceDashboard":{"properties":{"description":{"type":"string"},"integrationDashboard":{"$ref":"#/components/schemas/o11y.StorableIntegrationDashboard"},"title":{"type":"string"}},"type":"object"},"o11y.ServiceMetadata":{"properties":{"enabled":{"description":"if the service is enabled for the account","type":"boolean"},"icon":{"type":"string"},"id":{"type":"string"},"title":{"type":"string"}},"type":"object"},"o11y.SigV4Config":{"properties":{"AccessKey":{"type":"string"},"ExternalID":{"type":"string"},"Profile":{"type":"string"},"Region":{"type":"string"},"RoleARN":{"type":"string"},"SecretKey":{},"ServiceName":{"type":"string"},"UseFIPSSTSEndpoint":{"type":"boolean"}},"type":"object"},"o11y.SignalConnectionStatus":{"properties":{"last_received_from":{"description":"resource identifier","type":"string"},"last_received_ts_ms":{"description":"epoch milliseconds","format":"int64","type":"integer"}},"type":"object"},"o11y.SlackAction":{"properties":{"confirm":{"$ref":"#/components/schemas/o11y.SlackConfirmationField"},"name":{"type":"string"},"style":{"type":"string"},"text":{"type":"string"},"type":{"type":"string"},"url":{"type":"string"},"value":{"type":"string"}},"type":"object"},"o11y.SlackConfig":{"properties":{"NotifierConfig":{"$ref":"#/components/schemas/o11y.NotifierConfig"},"actions":{"items":{"$ref":"#/components/schemas/o11y.SlackAction"},"type":"array"},"api_url":{},"api_url_file":{"type":"string"},"app_token":{},"app_token_file":{"type":"string"},"app_url":{},"callback_id":{"type":"string"},"channel":{"description":"Slack channel override, (like #other-channel or @username).","type":"string"},"color":{"type":"string"},"fallback":{"type":"string"},"fields":{"items":{"$ref":"#/components/schemas/o11y.SlackField"},"type":"array"},"footer":{"type":"string"},"http_config":{"$ref":"#/components/schemas/o11y.HTTPClientConfig"},"icon_emoji":{"type":"string"},"icon_url":{"type":"string"},"image_url":{"type":"string"},"link_names":{"type":"boolean"},"message_text":{"type":"string"},"mrkdwn_in":{"items":{"type":"string"},"type":"array"},"pretext":{"type":"string"},"short_fields":{"type":"boolean"},"text":{"type":"string"},"thumb_url":{"type":"string"},"timeout":{"description":"Timeout is the maximum time allowed to invoke the slack. Setting this to 0\ndoes not impose a timeout.","format":"int64","type":"integer"},"title":{"type":"string"},"title_link":{"type":"string"},"username":{"type":"string"}},"type":"object"},"o11y.SlackConfirmationField":{"properties":{"dismiss_text":{"type":"string"},"ok_text":{"type":"string"},"text":{"type":"string"},"title":{"type":"string"}},"type":"object"},"o11y.SlackField":{"properties":{"short":{"type":"boolean"},"title":{"type":"string"},"value":{"type":"string"}},"type":"object"},"o11y.SpanAggregation":{"properties":{"aggregation":{},"field":{"$ref":"#/components/schemas/o11y.TelemetryFieldKey"}},"type":"object"},"o11y.SpanAggregationResult":{"properties":{"aggregation":{},"field":{"$ref":"#/components/schemas/o11y.TelemetryFieldKey"},"value":{"additionalProperties":{"format":"uint64","type":"integer"},"type":"object"}},"type":"object"},"o11y.SpanMapper":{"properties":{"config":{"$ref":"#/components/schemas/o11y.SpanMapperConfig"},"createdAt":{"format":"date-time","type":"string"},"createdBy":{"type":"string"},"enabled":{"type":"boolean"},"fieldContext":{},"group_id":{},"id":{},"name":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"updatedBy":{"type":"string"}},"type":"object"},"o11y.SpanMapperConfig":{"properties":{"sources":{"items":{"$ref":"#/components/schemas/o11y.SpanMapperSource"},"type":"array"}},"type":"object"},"o11y.SpanMapperGroup":{"properties":{"condition":{"$ref":"#/components/schemas/o11y.SpanMapperGroupCondition"},"createdAt":{"format":"date-time","type":"string"},"createdBy":{"type":"string"},"enabled":{"type":"boolean"},"id":{},"name":{"type":"string"},"orgId":{},"updatedAt":{"format":"date-time","type":"string"},"updatedBy":{"type":"string"}},"type":"object"},"o11y.SpanMapperGroupCondition":{"properties":{"attributes":{"items":{"type":"string"},"type":"array"},"resource":{"items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.SpanMapperSource":{"properties":{"context":{},"key":{"type":"string"},"operation":{},"priority":{"format":"int64","type":"integer"}},"type":"object"},"o11y.StatefulSetListRecord":{"properties":{"availablePods":{"format":"int64","type":"integer"},"cpuLimit":{"format":"double","type":"number"},"cpuRequest":{"format":"double","type":"number"},"cpuUsage":{"format":"double","type":"number"},"desiredPods":{"format":"int64","type":"integer"},"memoryLimit":{"format":"double","type":"number"},"memoryRequest":{"format":"double","type":"number"},"memoryUsage":{"format":"double","type":"number"},"meta":{"additionalProperties":{"type":"string"},"type":"object"},"restarts":{"format":"int64","type":"integer"},"statefulSetName":{"type":"string"}},"type":"object"},"o11y.StatefulSetListRequest":{"properties":{"end":{"description":"epoch time in ms","format":"int64","type":"integer"},"filters":{"$ref":"#/components/schemas/o11y.FilterSet"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.AttributeKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.OrderBy"},"start":{"description":"epoch time in ms","format":"int64","type":"integer"}},"type":"object"},"o11y.StatefulSetListResponse":{"properties":{"records":{"items":{"$ref":"#/components/schemas/o11y.StatefulSetListRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{"type":"string"}},"type":"object"},"o11y.StatefulSetRecord":{"properties":{"currentPods":{"format":"int64","type":"integer"},"desiredPods":{"format":"int64","type":"integer"},"meta":{"additionalProperties":{"type":"string"},"type":"object"},"podCountsByPhase":{"$ref":"#/components/schemas/o11y.PodCountsByPhase"},"statefulSetCPU":{"format":"double","type":"number"},"statefulSetCPULimit":{"format":"double","type":"number"},"statefulSetCPURequest":{"format":"double","type":"number"},"statefulSetMemory":{"format":"double","type":"number"},"statefulSetMemoryLimit":{"format":"double","type":"number"},"statefulSetMemoryRequest":{"format":"double","type":"number"},"statefulSetName":{"type":"string"}},"type":"object"},"o11y.StatefulSets":{"properties":{"endTimeBeforeRetention":{"type":"boolean"},"records":{"items":{"$ref":"#/components/schemas/o11y.StatefulSetRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{},"warning":{"$ref":"#/components/schemas/o11y.QueryWarnData"}},"type":"object"},"o11y.Stats":{"properties":{"currentAvgResolutionTime":{"type":"string"},"currentAvgResolutionTimeSeries":{"$ref":"#/components/schemas/o11y.Series"},"currentTriggersSeries":{"$ref":"#/components/schemas/o11y.Series"},"pastAvgResolutionTime":{"type":"string"},"pastAvgResolutionTimeSeries":{"$ref":"#/components/schemas/o11y.Series"},"pastTriggersSeries":{"$ref":"#/components/schemas/o11y.Series"},"totalCurrentTriggers":{"format":"uint64","type":"integer"},"totalPastTriggers":{"format":"uint64","type":"integer"}},"type":"object"},"o11y.StatusComponent":{"properties":{"current_status":{"description":"CurrentStatus is this component's own condition: \"full_outage\" for a\nservice that did not answer its health probe at all.","type":"string"},"id":{"description":"ID is the component's stable handle, which on this platform IS the service\nname — there is no separate component registry to allocate ids from.","type":"string"},"name":{"description":"Name is the service as the fleet prober knows it (the `service` label on\nhanzo_service_up), so a reader can match a component to what is being probed.","type":"string"}},"type":"object"},"o11y.StatusIncident":{"properties":{"affected_components":{"description":"AffectedComponents is what this incident covers. It is COUNTED rather than\nclassified: some services down is a partial outage and every probed service\ndown is a full one, because deciding that one service is critical and another\nis not would need a judgement nobody has measured.","items":{"$ref":"#/components/schemas/o11y.StatusComponent"},"type":"array"},"current_worst_impact":{"description":"CurrentWorstImpact is the incident's impact on the PLATFORM, which is not\nthe same question as the component's own condition above.","type":"string"},"id":{"description":"ID is derived from the service, so the same outage keeps one id across reads\nrather than being reported as a new incident every 15 seconds.","type":"string"},"last_update_at":{"description":"LastUpdateAt is when the failing measurement this incident reports was\nread, RFC3339 UTC.","type":"string"},"last_update_message":{"description":"LastUpdateMessage says what was observed, not what is being done about it —\nthere is no operator writing updates here, only the probe that failed.","type":"string"},"name":{"description":"Name is the one-line headline, built from the service that stopped answering.","type":"string"},"status":{"description":"Status is always \"investigating\" — the member of the client's closed set that\nmeans detected, cause not yet established, which is exactly what an automated\nprober knows. Nothing here ever claims \"identified\": that would assert a\ndiagnosis no measurement made.","type":"string"},"url":{"description":"URL points at the HUMAN status page, not back at this JSON. Every link in this\ndocument goes to the same place.","type":"string"}},"type":"object"},"o11y.StatusMaintenance":{"properties":{"affected_components":{"description":"AffectedComponents is what the window touches.","items":{"$ref":"#/components/schemas/o11y.StatusComponent"},"type":"array"},"ends_at":{"description":"EndsAt is when it is expected to finish, RFC3339 UTC.","type":"string"},"id":{"description":"ID is the window's handle.","type":"string"},"last_update_at":{"description":"LastUpdateAt is when the window was last revised, RFC3339 UTC.","type":"string"},"last_update_message":{"description":"LastUpdateMessage is the text of that revision.","type":"string"},"name":{"description":"Name is its one-line headline.","type":"string"},"starts_at":{"description":"StartsAt is when work begins, RFC3339 UTC.","type":"string"},"status":{"description":"Status is where the window is in its life, in the client's own vocabulary.","type":"string"},"url":{"description":"URL points at the human status page, as every link in this document does.","type":"string"}},"type":"object"},"o11y.StatusSummary":{"properties":{"checked_at":{"description":"CheckedAt is when the underlying availability read was taken, RFC3339 UTC.\nNot part of the status-page schema the panel parses (which ignores unknown\nfields); it is here because a status document with no timestamp cannot be\ntold apart from a stale one.","type":"string"},"in_progress_maintenances":{"description":"InProgressMaintenances is always empty: this platform has no maintenance\nscheduling plane, so \"nothing is running\" is a true statement rather than a\nplaceholder.","items":{"$ref":"#/components/schemas/o11y.StatusMaintenance"},"type":"array"},"ongoing_incidents":{"description":"OngoingIncidents is one entry per service that failed its health probe, sorted\nby name. Empty means every probed service answered — which is a measurement,\nnot an absence of reports.","items":{"$ref":"#/components/schemas/o11y.StatusIncident"},"type":"array"},"page_title":{"description":"PageTitle is the brand's own status-page title, resolved per request from the\nHost — a lux caller must never be shown Hanzo's.","type":"string"},"page_url":{"description":"PageURL is the HUMAN status page — an HTML page for people, distinct from\nthis JSON endpoint. Every link in this document points there.","type":"string"},"scheduled_maintenances":{"description":"ScheduledMaintenances is always empty, for the same reason.","items":{"$ref":"#/components/schemas/o11y.StatusMaintenance"},"type":"array"}},"type":"object"},"o11y.StorableFunnel":{"properties":{"createdAt":{"format":"date-time","type":"string"},"createdBy":{"type":"string"},"description":{"type":"string"},"funnel_name":{"type":"string"},"id":{},"org_id":{},"steps":{"items":{"$ref":"#/components/schemas/o11y.FunnelStep"},"type":"array"},"tags":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"updatedBy":{"type":"string"},"user":{"$ref":"#/components/schemas/o11y.User"}},"type":"object"},"o11y.StorableIntegrationDashboard":{"properties":{"createdAt":{"format":"date-time","type":"string"},"dashboardId":{"type":"string"},"id":{"type":"string"},"provider":{},"slug":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"o11y.SupportedSignals":{"properties":{"logs":{"type":"boolean"},"metrics":{"type":"boolean"}},"type":"object"},"o11y.TLSConfig":{"properties":{"ca":{"description":"Text of the CA cert to use for the targets.","type":"string"},"ca_file":{"description":"The CA cert to use for the targets.","type":"string"},"ca_ref":{"description":"CARef is the name of the secret within the secret manager to use as the CA cert for the\ntargets.","type":"string"},"cert":{"description":"Text of the client cert file for the targets.","type":"string"},"cert_file":{"description":"The client cert file for the targets.","type":"string"},"cert_ref":{"description":"CertRef is the name of the secret within the secret manager to use as the client cert for\nthe targets.","type":"string"},"insecure_skip_verify":{"description":"Disable target certificate validation.","type":"boolean"},"key":{"description":"Text of the client key file for the targets."},"key_file":{"description":"The client key file for the targets.","type":"string"},"key_ref":{"description":"KeyRef is the name of the secret within the secret manager to use as the client key for\nthe targets.","type":"string"},"max_version":{"description":"Maximum TLS version."},"min_version":{"description":"Minimum TLS version."},"server_name":{"description":"Used to verify the hostname for the targets.","type":"string"}},"type":"object"},"o11y.TelegramConfig":{"properties":{"NotifierConfig":{"$ref":"#/components/schemas/o11y.NotifierConfig"},"api_url":{},"chat":{"format":"int64","type":"integer"},"chat_file":{"type":"string"},"disable_notifications":{"type":"boolean"},"http_config":{"$ref":"#/components/schemas/o11y.HTTPClientConfig"},"message":{"type":"string"},"message_thread_id":{"format":"int64","type":"integer"},"parse_mode":{"type":"string"},"token":{},"token_file":{"type":"string"}},"type":"object"},"o11y.TelemetryFieldKey":{"properties":{"description":{"type":"string"},"fieldContext":{},"fieldDataType":{},"name":{"type":"string"},"signal":{},"unit":{"type":"string"}},"required":["name"],"type":"object"},"o11y.TelemetryFieldValues":{"properties":{"boolValues":{"items":{"type":"boolean"},"type":"array"},"numberValues":{"items":{"format":"double","type":"number"},"type":"array"},"relatedValues":{"items":{"type":"string"},"type":"array"},"stringValues":{"items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.ThreadingConfig":{"properties":{"enabled":{"type":"boolean"},"thread_by_date":{"type":"string"}},"type":"object"},"o11y.TimeSeries":{"properties":{"labels":{"items":{"$ref":"#/components/schemas/o11y.Label"},"type":"array"},"values":{"items":{},"type":"array"}},"type":"object"},"o11y.UninstallIntegrationRequest":{"properties":{"integration_id":{"type":"string"}},"type":"object"},"o11y.UpdatableAccountConfig":{"properties":{"aws":{"$ref":"#/components/schemas/o11y.AWSAccountConfig"},"azure":{"$ref":"#/components/schemas/o11y.UpdatableAzureAccountConfig"},"gcp":{"$ref":"#/components/schemas/o11y.UpdatableGCPAccountConfig"}},"type":"object"},"o11y.UpdatableAzureAccountConfig":{"properties":{"resourceGroups":{"items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.UpdatableGCPAccountConfig":{"properties":{"deploymentProjectId":{"description":"Project ID where central pub/sub for logs exist","type":"string"},"deploymentRegion":{"description":"Compute service region where otel collector will be deployed","type":"string"},"projectIds":{"description":"List of project IDs to monitor","items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.User":{"properties":{"createdAt":{"format":"date-time","type":"string"},"displayName":{"type":"string"},"email":{},"id":{},"isRoot":{"type":"boolean"},"orgId":{},"status":{},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"o11y.VariableItem":{"properties":{"type":{},"value":{}},"type":"object"},"o11y.VictorOpsConfig":{"properties":{"NotifierConfig":{"$ref":"#/components/schemas/o11y.NotifierConfig"},"api_key":{},"api_key_file":{"type":"string"},"api_url":{},"custom_fields":{"additionalProperties":{"type":"string"},"type":"object"},"entity_display_name":{"type":"string"},"http_config":{"$ref":"#/components/schemas/o11y.HTTPClientConfig"},"message_type":{"type":"string"},"monitoring_tool":{"type":"string"},"routing_key":{"type":"string"},"state_message":{"type":"string"}},"type":"object"},"o11y.VolumeListRecord":{"properties":{"meta":{"additionalProperties":{"type":"string"},"type":"object"},"persistentVolumeClaimName":{"type":"string"},"volumeAvailable":{"format":"double","type":"number"},"volumeCapacity":{"format":"double","type":"number"},"volumeInodes":{"format":"double","type":"number"},"volumeInodesFree":{"format":"double","type":"number"},"volumeInodesUsed":{"format":"double","type":"number"},"volumeUsage":{"format":"double","type":"number"}},"type":"object"},"o11y.VolumeListRequest":{"properties":{"end":{"description":"epoch time in ms","format":"int64","type":"integer"},"filters":{"$ref":"#/components/schemas/o11y.FilterSet"},"groupBy":{"items":{"$ref":"#/components/schemas/o11y.AttributeKey"},"type":"array"},"limit":{"format":"int64","type":"integer"},"offset":{"format":"int64","type":"integer"},"orderBy":{"$ref":"#/components/schemas/o11y.OrderBy"},"start":{"description":"epoch time in ms","format":"int64","type":"integer"}},"type":"object"},"o11y.VolumeListResponse":{"properties":{"records":{"items":{"$ref":"#/components/schemas/o11y.VolumeListRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{"type":"string"}},"type":"object"},"o11y.VolumeRecord":{"properties":{"meta":{"additionalProperties":{"type":"string"},"type":"object"},"persistentVolumeClaimName":{"type":"string"},"volumeAvailable":{"format":"double","type":"number"},"volumeCapacity":{"format":"double","type":"number"},"volumeInodes":{"format":"double","type":"number"},"volumeInodesFree":{"format":"double","type":"number"},"volumeInodesUsed":{"format":"double","type":"number"},"volumeUsage":{"format":"double","type":"number"}},"type":"object"},"o11y.Volumes":{"properties":{"endTimeBeforeRetention":{"type":"boolean"},"records":{"items":{"$ref":"#/components/schemas/o11y.VolumeRecord"},"type":"array"},"total":{"format":"int64","type":"integer"},"type":{},"warning":{"$ref":"#/components/schemas/o11y.QueryWarnData"}},"type":"object"},"o11y.WaterfallSpan":{"properties":{"attributes":{"additionalProperties":{},"type":"object"},"db_name":{"description":"Calculated fields, derived from the span's attributes.","type":"string"},"db_operation":{"type":"string"},"duration_nano":{"format":"uint64","type":"integer"},"events":{"items":{"$ref":"#/components/schemas/o11y.Event"},"type":"array"},"external_http_method":{"type":"string"},"external_http_url":{"type":"string"},"flags":{"format":"uint32","type":"integer"},"has_children":{"type":"boolean"},"has_error":{"type":"boolean"},"http_host":{"type":"string"},"http_method":{"type":"string"},"http_url":{"type":"string"},"is_remote":{"type":"string"},"kind_string":{"type":"string"},"level":{"format":"uint64","type":"integer"},"name":{"type":"string"},"parent_span_id":{"type":"string"},"references":{"items":{"$ref":"#/components/schemas/o11y.OtelSpanRef"},"type":"array"},"resource":{"additionalProperties":{"type":"string"},"type":"object"},"response_status_code":{"type":"string"},"span_id":{"type":"string"},"status_code":{"format":"int16","type":"integer"},"status_code_string":{"type":"string"},"status_message":{"type":"string"},"sub_tree_node_count":{"format":"uint64","type":"integer"},"time_unix":{"format":"uint64","type":"integer"},"trace_id":{"type":"string"},"trace_state":{"type":"string"}},"type":"object"},"o11y.WebexConfig":{"properties":{"NotifierConfig":{"$ref":"#/components/schemas/o11y.NotifierConfig"},"api_url":{},"http_config":{"$ref":"#/components/schemas/o11y.HTTPClientConfig"},"message":{"type":"string"},"room_id":{"type":"string"}},"type":"object"},"o11y.WebhookConfig":{"properties":{"NotifierConfig":{"$ref":"#/components/schemas/o11y.NotifierConfig"},"http_config":{"$ref":"#/components/schemas/o11y.HTTPClientConfig"},"max_alerts":{"description":"MaxAlerts is the maximum number of alerts to be sent per webhook message.\nAlerts exceeding this threshold will be truncated. Setting this to 0\nallows an unlimited number of alerts.","format":"uint64","type":"integer"},"timeout":{"description":"Timeout is the maximum time allowed to invoke the webhook. Setting this to 0\ndoes not impose a timeout.","format":"int64","type":"integer"},"url":{"description":"URL to send POST request to."},"url_file":{"type":"string"}},"type":"object"},"o11y.WechatConfig":{"properties":{"NotifierConfig":{"$ref":"#/components/schemas/o11y.NotifierConfig"},"agent_id":{"type":"string"},"api_secret":{},"api_secret_file":{"type":"string"},"api_url":{},"corp_id":{"type":"string"},"http_config":{"$ref":"#/components/schemas/o11y.HTTPClientConfig"},"message":{"type":"string"},"message_type":{"type":"string"},"to_party":{"type":"string"},"to_tag":{"type":"string"},"to_user":{"type":"string"}},"type":"object"},"o11y.addItemsIn":{"properties":{"id":{"description":"ID is the annotation queue to add to, from the path.","type":"string"},"items":{"description":"Items are the objects to enqueue for review, 1–200 per request. Each names\nexactly one object.","items":{"$ref":"#/components/schemas/o11y.itemInput"},"type":"array"}},"type":"object"},"o11y.alertmanagertypes.Receiver":{"properties":{"Receiver":{"$ref":"#/components/schemas/o11y.Receiver"},"googlechat_configs":{"items":{"$ref":"#/components/schemas/o11y.GoogleChatReceiverConfig"},"type":"array"}},"type":"object"},"o11y.annItemList":{"properties":{"data":{"description":"Data is the page of items.","items":{"$ref":"#/components/schemas/o11y.annItemView"},"type":"array"},"meta":{"$ref":"#/components/schemas/o11y.listMeta","description":"Meta is the paging that produced it."}},"type":"object"},"o11y.annItemView":{"properties":{"assignee":{"description":"Assignee is the reviewer it is for, omitted when unassigned.","type":"string"},"completedAt":{"description":"CompletedAt is when it was reviewed, omitted while pending.","type":"string"},"createdAt":{"description":"CreatedAt is when it was enqueued, RFC3339 in UTC.","type":"string"},"id":{"description":"ID is the item's id.","type":"string"},"objectId":{"description":"ObjectID is the referenced object's id.","type":"string"},"objectType":{"description":"ObjectType is what it references: TRACE, OBSERVATION or SESSION.","type":"string"},"observationId":{"description":"ObservationID echoes objectId when objectType is OBSERVATION.","type":"string"},"queueId":{"description":"QueueID is the queue it belongs to.","type":"string"},"sessionId":{"description":"SessionID echoes objectId when objectType is SESSION.","type":"string"},"status":{"description":"Status is PENDING or COMPLETED.","type":"string"},"traceId":{"description":"TraceID echoes objectId when objectType is TRACE.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it last changed, RFC3339 in UTC.","type":"string"}},"type":"object"},"o11y.annItemsCreated":{"properties":{"data":{"description":"Data is every item created by this request, in request order.","items":{"$ref":"#/components/schemas/o11y.annItemView"},"type":"array"}},"type":"object"},"o11y.annQueueDeleted":{"properties":{"deleted":{"description":"Deleted is true when the queue (and its items) were removed.","type":"boolean"}},"type":"object"},"o11y.annQueueDetailView":{"properties":{"completedCount":{"description":"CompletedCount is how many have been reviewed.","format":"int64","type":"integer"},"createdAt":{"description":"CreatedAt is when it was created, RFC3339 in UTC.","type":"string"},"description":{"description":"Description is its free text, omitted when empty.","type":"string"},"id":{"description":"ID is the queue's id.","type":"string"},"items":{"description":"Items is the queue's first page of items (up to 100).","items":{"$ref":"#/components/schemas/o11y.annItemView"},"type":"array"},"name":{"description":"Name is its display handle.","type":"string"},"pendingCount":{"description":"PendingCount is how many of its items are still awaiting review.","format":"int64","type":"integer"},"scoreConfigIds":{"description":"ScoreConfigIDs are the eval score-configs reviewers grade against.","items":{"type":"string"},"type":"array"},"updatedAt":{"description":"UpdatedAt is when it last changed, RFC3339 in UTC.","type":"string"}},"type":"object"},"o11y.annQueueList":{"properties":{"data":{"description":"Data is the page of queues.","items":{"$ref":"#/components/schemas/o11y.annQueueView"},"type":"array"},"meta":{"$ref":"#/components/schemas/o11y.listMeta","description":"Meta is the paging that produced it."}},"type":"object"},"o11y.annQueueView":{"properties":{"createdAt":{"description":"CreatedAt is when it was created, RFC3339 in UTC.","type":"string"},"description":{"description":"Description is its free text, omitted when empty.","type":"string"},"id":{"description":"ID is the queue's id.","type":"string"},"name":{"description":"Name is its display handle.","type":"string"},"scoreConfigIds":{"description":"ScoreConfigIDs are the eval score-configs reviewers grade against.","items":{"type":"string"},"type":"array"},"updatedAt":{"description":"UpdatedAt is when it last changed, RFC3339 in UTC.","type":"string"}},"type":"object"},"o11y.cloudintegrationtypes.CollectedLogAttribute":{"properties":{"name":{"type":"string"},"path":{"type":"string"},"type":{"type":"string"}},"type":"object"},"o11y.cloudintegrationtypes.CollectedMetric":{"properties":{"description":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"unit":{"type":"string"}},"type":"object"},"o11y.createQueueReq":{"properties":{"description":{"description":"Description is optional free text, up to 512 characters.","type":"string"},"name":{"description":"Name is the queue's display handle, 1–128 printable characters. It must be\nunique within the org's project. Required.","type":"string"},"scoreConfigIds":{"description":"ScoreConfigIDs are the eval score-configs reviewers grade against.","items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.deployment":{"properties":{"instance":{"description":"Instance is the replica as the telemetry store labels it — the address the\nseries was recorded against, which is what distinguishes two replicas of one\nservice.","type":"string"},"up":{"description":"Up is that replica's last reported state. Every target emits on every cycle,\nso a replica missing from the list is one the prober is not reporting at all,\nwhich is a different fact from down.","type":"boolean"}},"type":"object"},"o11y.itemInput":{"properties":{"assignee":{"description":"Assignee is the reviewer this item is for, up to 512 characters.","type":"string"},"objectId":{"description":"ObjectID is the referenced object's id, paired with objectType.","type":"string"},"objectType":{"description":"ObjectType is TRACE, OBSERVATION or SESSION — the generic form, paired\nwith objectId.","type":"string"},"observationId":{"description":"ObservationID references an observation — the console-friendly form of\nobjectType=OBSERVATION.","type":"string"},"sessionId":{"description":"SessionID references a session — the console-friendly form of\nobjectType=SESSION.","type":"string"},"traceId":{"description":"TraceID references a trace — the console-friendly form of\nobjectType=TRACE.","type":"string"}},"type":"object"},"o11y.listMeta":{"properties":{"limit":{"description":"Limit is how many rows one page holds.","format":"int64","type":"integer"},"page":{"description":"Page is the 1-based page this response is.","format":"int64","type":"integer"},"totalItems":{"description":"TotalItems is how many rows match in total.","format":"int64","type":"integer"},"totalPages":{"description":"TotalPages is ceil(totalItems/limit), at least 1.","format":"int64","type":"integer"}},"type":"object"},"o11y.metricsResponse":{"properties":{"product":{"description":"Product is the service these numbers are about, echoed back.","type":"string"},"range":{"description":"Range is the window actually used, after clamping — not what was asked for.\nA caller that wants to know what it got reads this rather than its own query.","properties":{"sinceSec":{"format":"int64","type":"integer"},"stepSec":{"format":"int64","type":"integer"}},"type":"object"},"series":{"description":"Series is the RED trend: request rate, error rate and two latency quantiles,\nbucketed at range.stepSec and oldest bucket first. Latencies are in\nMILLISECONDS.","properties":{"errors":{"items":{"$ref":"#/components/schemas/o11y.point"},"type":"array"},"latencyP50Ms":{"items":{"$ref":"#/components/schemas/o11y.point"},"type":"array"},"latencyP95Ms":{"items":{"$ref":"#/components/schemas/o11y.point"},"type":"array"},"requests":{"items":{"$ref":"#/components/schemas/o11y.point"},"type":"array"}},"type":"object"},"summary":{"description":"Summary totals the window in one object, so a tile does not have to sum the\nseries to render. errorRate is a RATIO of the window's requests, not a\npercentage, and p95Ms is over the window rather than the worst bucket.","properties":{"errorRate":{"format":"double","type":"number"},"errors":{"format":"int64","type":"integer"},"p95Ms":{"format":"double","type":"number"},"requests":{"format":"int64","type":"integer"}},"type":"object"},"usage":{"description":"Usage is the LLM side of the same window: how many calls, how many tokens and\nwhat they cost. It counts model traffic, not HTTP requests, so it does not\nreconcile with series.requests.","properties":{"calls":{"format":"int64","type":"integer"},"costCents":{"format":"int64","type":"integer"},"series":{"items":{"$ref":"#/components/schemas/o11y.usageBucket"},"type":"array"},"tokens":{"format":"int64","type":"integer"}},"type":"object"}},"type":"object"},"o11y.point":{"properties":{"t":{"description":"T is the bucket start, RFC3339 in UTC.","type":"string"},"v":{"description":"V is the bucket's value.","format":"double","type":"number"}},"type":"object"},"o11y.querybuildertypesv5.OrderBy":{"properties":{"direction":{"description":"direction to order by"},"key":{"$ref":"#/components/schemas/o11y.OrderByKey","description":"key to order by"}},"type":"object"},"o11y.statusResult":{"properties":{"checkedAt":{"description":"CheckedAt is when this answer was measured, RFC3339 UTC.","type":"string"},"deployments":{"description":"Deployments is the per-replica inventory behind the verdict. Empty means the\ntelemetry store reported none, not that the service runs on none.","items":{"$ref":"#/components/schemas/o11y.deployment"},"type":"array"},"latencyMs":{"description":"LatencyMs is the health probe's round trip in MILLISECONDS, time-boxed at two\nseconds. It is 0 when no probe answered, which is not a fast service.","format":"int64","type":"integer"},"product":{"description":"Product is the service this answer is about, echoed back.","type":"string"},"source":{"description":"Source is where the verdict came from: \"probe\" (we asked and it answered),\n\"datastore\" (the probe did not answer and the replica inventory decided it),\n\"unreachable\" (neither), or \"unknown-service\" for a well-formed product name\nnothing backs — which is answered without probing, since dialling an\narbitrary host on a caller's say-so is the request forgery this refuses.","type":"string"},"up":{"description":"Up is true when the health probe succeeded OR any replica reports up, so a\nservice reachable by either route reads up. Read Source to know which.","type":"boolean"}},"type":"object"},"o11y.traceRow":{"properties":{"durationMs":{"description":"DurationMs is End minus Start in milliseconds: the trace's wall clock,\nnot the sum of its spans, which double-counts everything concurrent.","format":"double","type":"number"},"end":{"description":"End is the latest span end, RFC3339 with nanoseconds, in UTC.","type":"string"},"numSpans":{"description":"NumSpans is how many spans the trace carries.","format":"int64","type":"integer"},"start":{"description":"Start is the earliest span start, RFC3339 with nanoseconds, in UTC.","type":"string"},"traceId":{"description":"TraceID is the trace's id — the {traceId} of the detail read.","type":"string"}},"type":"object"},"o11y.tracesOut":{"properties":{"count":{"description":"Count is how many traces this page carries.","format":"int64","type":"integer"},"limit":{"description":"Limit is the page cap actually applied, after clamping.","format":"int64","type":"integer"},"sinceSec":{"description":"SinceSec is the window actually read, in seconds, after clamping.","format":"int64","type":"integer"},"traces":{"description":"Traces are the caller org's traces, most recently active first.","items":{"$ref":"#/components/schemas/o11y.traceRow"},"type":"array"}},"type":"object"},"o11y.updateItemIn":{"properties":{"assignee":{"description":"Assignee replaces the reviewer this item is for, up to 512 characters.","type":"string"},"id":{"description":"ID is the annotation queue the item belongs to, from the path.","type":"string"},"itemId":{"description":"ItemID is the item to update, from the path.","type":"string"},"status":{"description":"Status is the item's new review state: PENDING or COMPLETED. Required.","type":"string"}},"type":"object"},"o11y.updateQueueIn":{"properties":{"description":{"description":"Description replaces the free text when present, up to 512 characters.","type":"string"},"id":{"description":"ID is the annotation queue to update, from the path.","type":"string"},"name":{"description":"Name replaces the queue's display handle when present, 1–128 printable\ncharacters and unique within the project.","type":"string"},"scoreConfigIds":{"description":"ScoreConfigIDs replaces the whole score-config set when present.","items":{"type":"string"},"type":"array"}},"type":"object"},"o11y.usageBucket":{"properties":{"calls":{"description":"Calls is how many LLM calls landed in the bucket.","format":"int64","type":"integer"},"costCents":{"description":"CostCents is what they cost, in cents.","format":"int64","type":"integer"},"t":{"description":"T is the bucket start, RFC3339 in UTC.","type":"string"},"tokens":{"description":"Tokens is how many tokens they consumed.","format":"int64","type":"integer"}},"type":"object"},"o11y.v3.CompositeQuery":{"properties":{"builderQueries":{"additionalProperties":{"$ref":"#/components/schemas/o11y.BuilderQuery"},"type":"object"},"chQueries":{"additionalProperties":{"$ref":"#/components/schemas/o11y.DatastoreQuery"},"type":"object"},"fillGaps":{"description":"FillGaps is used to fill the gaps in the time series data","type":"boolean"},"panelType":{"type":"string"},"promQueries":{"additionalProperties":{"$ref":"#/components/schemas/o11y.PromQuery"},"type":"object"},"queries":{"items":{"$ref":"#/components/schemas/o11y.QueryEnvelope"},"type":"array"},"queryType":{"type":"string"},"unit":{"description":"Unit for the time series data shown in the graph\nThis is used in alerts to format the value and threshold","type":"string"}},"type":"object"},"openai.AudioResponse":{"properties":{"duration":{"type":"number"},"language":{"type":"string"},"segments":{"items":{"properties":{"avg_logprob":{"type":"number"},"compression_ratio":{"type":"number"},"end":{"type":"number"},"id":{"type":"integer"},"no_speech_prob":{"type":"number"},"seek":{"type":"integer"},"start":{"type":"number"},"temperature":{"type":"number"},"text":{"type":"string"},"tokens":{"items":{"type":"integer"},"type":"array"},"transient":{"type":"boolean"}},"type":"object"},"type":"array"},"task":{"type":"string"},"text":{"type":"string"},"words":{"items":{"properties":{"end":{"type":"number"},"start":{"type":"number"},"word":{"type":"string"}},"type":"object"},"type":"array"}},"type":"object"},"openai.ChatCompletionChoice":{"properties":{"content_filter_results":{"$ref":"#/components/schemas/openai.ContentFilterResults"},"finish_reason":{"type":"string"},"index":{"type":"integer"},"logprobs":{"$ref":"#/components/schemas/openai.LogProbs"},"message":{"$ref":"#/components/schemas/openai.ChatCompletionMessage"}},"type":"object"},"openai.ChatCompletionMessage":{"properties":{"MultiContent":{"items":{"$ref":"#/components/schemas/openai.ChatMessagePart"},"type":"array"},"content":{"type":"string"},"function_call":{"$ref":"#/components/schemas/openai.FunctionCall"},"name":{"type":"string"},"reasoning_content":{"type":"string"},"refusal":{"type":"string"},"role":{"type":"string"},"tool_call_id":{"type":"string"},"tool_calls":{"items":{"$ref":"#/components/schemas/openai.ToolCall"},"type":"array"}},"type":"object"},"openai.ChatCompletionRequest":{"properties":{"frequency_penalty":{"type":"number"},"function_call":{},"functions":{"items":{"$ref":"#/components/schemas/openai.FunctionDefinition"},"type":"array"},"logit_bias":{"additionalProperties":{"type":"integer"},"type":"object"},"logprobs":{"type":"boolean"},"max_completion_tokens":{"type":"integer"},"max_tokens":{"type":"integer"},"messages":{"items":{"$ref":"#/components/schemas/openai.ChatCompletionMessage"},"type":"array"},"metadata":{"additionalProperties":{"type":"string"},"type":"object"},"model":{"type":"string"},"n":{"type":"integer"},"parallel_tool_calls":{},"presence_penalty":{"type":"number"},"reasoning_effort":{"type":"string"},"response_format":{"$ref":"#/components/schemas/openai.ChatCompletionResponseFormat"},"seed":{"type":"integer"},"stop":{"items":{"type":"string"},"type":"array"},"store":{"type":"boolean"},"stream":{"type":"boolean"},"stream_options":{"$ref":"#/components/schemas/openai.StreamOptions"},"temperature":{"type":"number"},"tool_choice":{},"tools":{"items":{"$ref":"#/components/schemas/openai.Tool"},"type":"array"},"top_logprobs":{"type":"integer"},"top_p":{"type":"number"},"user":{"type":"string"}},"type":"object"},"openai.ChatCompletionResponse":{"properties":{"choices":{"items":{"$ref":"#/components/schemas/openai.ChatCompletionChoice"},"type":"array"},"created":{"type":"integer"},"id":{"type":"string"},"model":{"type":"string"},"object":{"type":"string"},"prompt_filter_results":{"items":{"$ref":"#/components/schemas/openai.PromptFilterResult"},"type":"array"},"system_fingerprint":{"type":"string"},"usage":{"$ref":"#/components/schemas/openai.Usage"}},"type":"object"},"openai.ChatCompletionResponseFormat":{"properties":{"json_schema":{"$ref":"#/components/schemas/openai.ChatCompletionResponseFormatJSONSchema"},"type":{"type":"string"}},"type":"object"},"openai.ChatCompletionResponseFormatJSONSchema":{"properties":{"description":{"type":"string"},"name":{"type":"string"},"schema":{},"strict":{"type":"boolean"}},"type":"object"},"openai.ChatMessageImageURL":{"properties":{"detail":{"type":"string"},"url":{"type":"string"}},"type":"object"},"openai.ChatMessagePart":{"properties":{"image_url":{"$ref":"#/components/schemas/openai.ChatMessageImageURL"},"text":{"type":"string"},"type":{"type":"string"}},"type":"object"},"openai.CompletionTokensDetails":{"properties":{"audio_tokens":{"type":"integer"},"reasoning_tokens":{"type":"integer"}},"type":"object"},"openai.ContentFilterResults":{"properties":{"hate":{"$ref":"#/components/schemas/openai.Hate"},"jailbreak":{"$ref":"#/components/schemas/openai.JailBreak"},"profanity":{"$ref":"#/components/schemas/openai.Profanity"},"self_harm":{"$ref":"#/components/schemas/openai.SelfHarm"},"sexual":{"$ref":"#/components/schemas/openai.Sexual"},"violence":{"$ref":"#/components/schemas/openai.Violence"}},"type":"object"},"openai.Embedding":{"properties":{"embedding":{"items":{"type":"number"},"type":"array"},"index":{"type":"integer"},"object":{"type":"string"}},"type":"object"},"openai.EmbeddingRequest":{"properties":{"dimensions":{"type":"integer"},"encoding_format":{"type":"string"},"input":{},"model":{"type":"string"},"user":{"type":"string"}},"type":"object"},"openai.EmbeddingResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/openai.Embedding"},"type":"array"},"model":{"type":"string"},"object":{"type":"string"},"usage":{"$ref":"#/components/schemas/openai.Usage"}},"type":"object"},"openai.FunctionCall":{"properties":{"arguments":{"type":"string"},"name":{"type":"string"}},"type":"object"},"openai.FunctionDefinition":{"properties":{"description":{"type":"string"},"name":{"type":"string"},"parameters":{},"strict":{"type":"boolean"}},"type":"object"},"openai.Hate":{"properties":{"filtered":{"type":"boolean"},"severity":{"type":"string"}},"type":"object"},"openai.ImageResponse":{"properties":{"created":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/openai.ImageResponseDataInner"},"type":"array"}},"type":"object"},"openai.ImageResponseDataInner":{"properties":{"b64_json":{"type":"string"},"revised_prompt":{"type":"string"},"url":{"type":"string"}},"type":"object"},"openai.JailBreak":{"properties":{"detected":{"type":"boolean"},"filtered":{"type":"boolean"}},"type":"object"},"openai.LogProb":{"properties":{"bytes":{"format":"byte","type":"string"},"logprob":{"type":"number"},"token":{"type":"string"},"top_logprobs":{"items":{"$ref":"#/components/schemas/openai.TopLogProbs"},"type":"array"}},"type":"object"},"openai.LogProbs":{"properties":{"content":{"items":{"$ref":"#/components/schemas/openai.LogProb"},"type":"array"}},"type":"object"},"openai.Profanity":{"properties":{"detected":{"type":"boolean"},"filtered":{"type":"boolean"}},"type":"object"},"openai.PromptFilterResult":{"properties":{"content_filter_results":{"$ref":"#/components/schemas/openai.ContentFilterResults"},"index":{"type":"integer"}},"type":"object"},"openai.PromptTokensDetails":{"properties":{"audio_tokens":{"type":"integer"},"cached_tokens":{"type":"integer"}},"type":"object"},"openai.SelfHarm":{"properties":{"filtered":{"type":"boolean"},"severity":{"type":"string"}},"type":"object"},"openai.Sexual":{"properties":{"filtered":{"type":"boolean"},"severity":{"type":"string"}},"type":"object"},"openai.StreamOptions":{"properties":{"include_usage":{"type":"boolean"}},"type":"object"},"openai.Tool":{"properties":{"function":{"$ref":"#/components/schemas/openai.FunctionDefinition"},"type":{"type":"string"}},"type":"object"},"openai.ToolCall":{"properties":{"function":{"$ref":"#/components/schemas/openai.FunctionCall"},"id":{"type":"string"},"index":{"type":"integer"},"type":{"type":"string"}},"type":"object"},"openai.TopLogProbs":{"properties":{"bytes":{"format":"byte","type":"string"},"logprob":{"type":"number"},"token":{"type":"string"}},"type":"object"},"openai.Usage":{"properties":{"completion_tokens":{"type":"integer"},"completion_tokens_details":{"$ref":"#/components/schemas/openai.CompletionTokensDetails"},"prompt_tokens":{"type":"integer"},"prompt_tokens_details":{"$ref":"#/components/schemas/openai.PromptTokensDetails"},"total_tokens":{"type":"integer"}},"type":"object"},"openai.Violence":{"properties":{"filtered":{"type":"boolean"},"severity":{"type":"string"}},"type":"object"},"patent.PatentAnchor":{"properties":{"at":{"description":"At is when the commitment was made, RFC3339, when there is one.","type":"string"},"commitment":{"description":"Commitment is the fold root the anchor would name.","type":"string"},"reference":{"description":"Reference is where a third party can check it — a block, an index, a\npublished headline. Empty means nothing outside this response names it.","type":"string"},"status":{"description":"Status is unanchored or anchored. Nothing else: an anchored answer arrives\nonly from a real commitment, and this app never invents a transaction id.","type":"string"}},"type":"object"},"patent.PatentApproval":{"properties":{"authored_by":{"description":"AuthoredBy is the validated principal who decided. The same rule as\neverywhere here: it comes from the credential, never the body, so one\nperson cannot record a decision on another's behalf.","type":"string"},"canonical":{"description":"Canonical is DERIVED on read: this author's latest word on this\ndisclosure.","type":"boolean"},"comment":{"description":"Comment is the reviewer's note — the part an inventor reads.","type":"string"},"content_hash":{"description":"ContentHash is the server's digest of the recorded content.","type":"string"},"decision":{"description":"Decision is approved, rejected or needs-work. A needs-work is dated and\nretained exactly like a sign-off, because it IS one.","type":"string"},"disclosure_id":{"description":"DisclosureID is the document this decides on. Required.","type":"string"},"id":{"description":"ID is the server's handle for this decision, derived from the disclosure\nand its author. Read-only: a caller cannot name someone else's approval.","type":"string"},"project":{"description":"Project is the SERVER's scope value.","type":"string"},"recorded_at":{"description":"RecordedAt is the server's clock.","type":"string"},"revision":{"description":"Revision is original, corrected or retracted.","type":"string"},"role":{"description":"Role is the capacity the person acted in: author, cto, reviewer, attorney\nor counsel. Required, because \"approved\" by nobody is not a fact.","type":"string"},"seq":{"description":"Seq is the append order.","format":"int64","type":"integer"}},"type":"object"},"patent.PatentCoverage":{"properties":{"approvals":{"description":"Approvals is how many decisions it covered.","format":"int64","type":"integer"},"disclosures":{"description":"Disclosures is how many documents it covered.","format":"int64","type":"integer"},"ideas":{"description":"Ideas is how many conception entries the fold covered.","format":"int64","type":"integer"},"implementations":{"description":"Implementations is how many implementation records it covered.","format":"int64","type":"integer"},"versions":{"description":"Versions is how many RETAINED versions were folded, which is at least the\nsum above and is the number that says corrections happened.","format":"int64","type":"integer"}},"type":"object"},"patent.PatentDisclosure":{"properties":{"approvals":{"description":"Approvals is DERIVED on read: the current decision of record from each\nperson who has ruled on this disclosure. Never an input — a caller cannot\napprove its own document by writing a field in it.","items":{"$ref":"#/components/schemas/patent.PatentApproval"},"type":"array"},"authored_by":{"description":"AuthoredBy is the validated principal who recorded this version.","type":"string"},"body":{"description":"Body is the document's text. Its digest is published beside it so a reader\ncan tell a stored body from a re-sent one.","type":"string"},"body_sha256":{"description":"BodySHA256 is the SERVER's digest of body. On a read it is the address of\nwhat is stored; a body is never hashed from what a reader sent.","type":"string"},"canonical":{"description":"Canonical is DERIVED on read.","type":"boolean"},"claims":{"description":"Claims is the draft claim set, or a pointer to where it lives.","type":"string"},"content_hash":{"description":"ContentHash is the server's digest of the recorded content.","type":"string"},"filing_ref":{"description":"FilingRef is a filing number a human recorded here after filing. Empty\nmeans nothing has been filed, and no code path fills it.","type":"string"},"id":{"description":"ID is the disclosure's stable id. Required.","type":"string"},"idea_ids":{"description":"IdeaIDs are the conception entries this disclosure is built from. The\nevidence half; a disclosure citing none is an assertion.","items":{"type":"string"},"type":"array"},"implementation_ids":{"description":"ImplementationIDs are the artifacts it describes.","items":{"type":"string"},"type":"array"},"project":{"description":"Project is the SERVER's scope value.","type":"string"},"recorded_at":{"description":"RecordedAt is the server's clock.","type":"string"},"revision":{"description":"Revision is original, corrected or retracted.","type":"string"},"seq":{"description":"Seq is the append order.","format":"int64","type":"integer"},"status":{"description":"Status is draft, reviewed, approved or filed. `approved` means the\napprovals below carry a decision for each required role, which is DERIVED\non read, not a word a caller sets and gets believed.","type":"string"},"summary":{"description":"Summary is the invention in one paragraph, for the reader who decides\nwhether to read the rest.","type":"string"},"title":{"description":"Title names the invention the way the document does.","type":"string"},"visibility":{"description":"Visibility is private, org or public; forced private on a write.","type":"string"}},"type":"object"},"patent.PatentGap":{"properties":{"field":{"description":"Field is the wire name, e.g. prior_art.","type":"string"},"missing":{"description":"Missing is how many covered records leave it empty.","format":"int64","type":"integer"},"why":{"description":"Why names what the absence costs, so a gap is a decision to fix rather\nthan a lint warning.","type":"string"}},"type":"object"},"patent.PatentIdea":{"properties":{"alternatives":{"description":"Alternatives are the routes considered and rejected, each with its reason.","items":{"$ref":"#/components/schemas/patent.PatentRejectedAlternative"},"type":"array"},"authored_by":{"description":"AuthoredBy is the validated principal who recorded this version — an IAM\nsubject, never a body field. It is the §115 answer, and a model has none.","type":"string"},"canonical":{"description":"Canonical is DERIVED on read: a version is canonical when it is the\nlatest-appended non-retracted version of its id.","type":"boolean"},"content_hash":{"description":"ContentHash is the SERVER's digest of the recorded content and this\nversion's identity. Computed on a write; read back on a read.","type":"string"},"id":{"description":"ID is the entry's stable id, the key its versions accrue under:\nlowercase, terse, and named for the idea rather than the file —\nlatency-aware-request-routing. Required on a write.","type":"string"},"kind":{"description":"Kind is what kind of conception this is: problem, alternative,\narchitecture, mechanism, decision or rejection. Required on a write.","type":"string"},"notes":{"description":"Notes is anything a later reader needs that the fields above cannot carry.","type":"string"},"prior_art":{"description":"PriorArt is what the author knows already existed, named as the author\nknows it. It is a statement of the inventor's awareness, not a search\nresult, and it is not a substitute for one.","type":"string"},"problem":{"description":"Problem is the technical problem being solved, and why the existing\napproaches fail at it.","type":"string"},"project":{"description":"Project is the sub-scope inside the org this entry is filed under. On a\nwrite it is the SERVER's value and a project in the body is ignored.","type":"string"},"recorded_at":{"description":"RecordedAt is when this store accepted the version, RFC3339, from the\nserver clock.","type":"string"},"revision":{"description":"Revision is the producer's declared kind of this version: original,\ncorrected or retracted. A retracted latest version WITHDRAWS the id; every\nearlier version stays retained.","type":"string"},"seq":{"description":"Seq is this version's place in the store's append order. The ordering\nauthority; never a client value.","format":"int64","type":"integer"},"signature":{"$ref":"#/components/schemas/patent.PatentSignature","description":"PatentSignature is an optional detached signature over this entry's digest."},"statement":{"description":"Statement is the operative idea in the author's own prose — definite\nenough that a reader could implement it from this alone. Required, and the\nfield an examiner would actually read.","type":"string"},"title":{"description":"Title is the one-line name of the entry.","type":"string"},"visibility":{"description":"Visibility is private, org or public. A write forces private.","type":"string"}},"type":"object"},"patent.PatentImplementation":{"properties":{"artifact_sha256":{"description":"ArtifactSHA256 is the digest of the recorded artifact — a diff, a file, a\nbuild — when the caller has one and wants it addressed by content.","type":"string"},"authored_by":{"description":"AuthoredBy is the validated principal who recorded this. Authorship of the\nIDEA is PatentIdea.AuthoredBy — this field records who filed the\nimplementation record, which is not the same question.","type":"string"},"canonical":{"description":"Canonical is DERIVED on read.","type":"boolean"},"content_hash":{"description":"ContentHash is the server's digest of the recorded content.","type":"string"},"generated":{"description":"Generated says the recorded artifact was produced with a model's\nassistance rather than typed by hand.","type":"boolean"},"git_branch":{"description":"GitBranch is the branch that commit was on.","type":"string"},"git_dirty":{"description":"GitDirty says the working tree carried uncommitted changes when this was\nrecorded. It is recorded because an exact commit claim that is not true is\nworse than no commit claim.","type":"boolean"},"git_sha":{"description":"GitSHA is the commit. Together with Seq it is what makes the claim checkable\noutside this app: a reader can go read the code.","type":"string"},"human_review":{"description":"HumanReview is what a person did with the output: accepted, edited,\nrewritten, or none. `none` on a novel mechanism is the disposition to\nknow about.","type":"string"},"id":{"description":"ID is this implementation's stable id — usually the artifact or change it\nrecords, e.g. router-v2-generated. Required.","type":"string"},"idea_ids":{"description":"IdeaIDs names the conceptions this implements. REQUIRED and non-empty:\nan implementation citing nothing is the inverted order the guidance is\nwritten against, and filing it silently would be the worst thing this\nsurface could do.","items":{"type":"string"},"type":"array"},"model":{"description":"Model names the system that produced the code, as it was addressed. This is\nthe field that answers \"how much of this was a tool\" without a guess.","type":"string"},"notes":{"description":"Notes is anything a later reader needs.","type":"string"},"project":{"description":"Project is the SERVER's scope value.","type":"string"},"prompt_sha256":{"description":"PromptSHA256 is the digest of the prompt, not the prompt. The text often\ncarries third-party material; the digest lets a later reader prove the\nsame request was made.","type":"string"},"recorded_at":{"description":"RecordedAt is the server's clock.","type":"string"},"repo":{"description":"Repo is the repository the work landed in.","type":"string"},"revision":{"description":"Revision is original, corrected or retracted.","type":"string"},"seq":{"description":"Seq is the append order, which is what GET /v1/patent/proof compares\nagainst the cited ideas.","format":"int64","type":"integer"},"visibility":{"description":"Visibility is private, org or public; forced private on a write.","type":"string"}},"type":"object"},"patent.PatentOrderCheck":{"properties":{"gap_seq":{"description":"GapSeq is how many appends separate them, negative when the implementation\nprecedes the idea. It is a distance in the LOG rather than in seconds,\nbecause seconds are comparable only within one server's clock.","format":"int64","type":"integer"},"idea":{"description":"Idea is the conception it cites.","type":"string"},"implementation":{"description":"Implementation is the artifact being examined.","type":"string"},"verdict":{"description":"Verdict is before, after or unproven.","type":"string"},"why":{"description":"Why states, in one sentence, what the verdict is resting on. A verdict\nwithout its basis is the thing this whole surface exists to avoid.","type":"string"}},"type":"object"},"patent.PatentProof":{"properties":{"anchor":{"$ref":"#/components/schemas/patent.PatentAnchor","description":"PatentAnchor is the external standing of this exact root."},"coverage":{"$ref":"#/components/schemas/patent.PatentCoverage","description":"Coverage counts what the fold held, per kind, so a short list reads as a\nshort log and not as a complete one."},"gaps":{"description":"Gaps names every field of the covered records that states nothing, with\nhow many records leave it unstated.","items":{"$ref":"#/components/schemas/patent.PatentGap"},"type":"array"},"order":{"description":"Order is one verdict per implementation-idea pair.","items":{"$ref":"#/components/schemas/patent.PatentOrderCheck"},"type":"array"},"project":{"description":"Project is the scope the fold covered.","type":"string"},"records":{"description":"Records are the entries folded, oldest clock first.","items":{"$ref":"#/components/schemas/patent.PatentProofEntry"},"type":"array"},"root":{"description":"Root is the fold digest over every record in append order.","type":"string"},"verdict":{"description":"Verdict is the whole answer in one word: supported when every pair is\n`before`, contested when any is `after`, unproven when any is missing, and\nempty when there was nothing to fold. It is the WORST pair, because a chain\nwith one inverted edge is not a chain.","type":"string"},"verified_at":{"description":"VerifiedAt is when this fold was computed. The records can have grown since;\nthe root is the set as of here.","type":"string"}},"type":"object"},"patent.PatentProofEntry":{"properties":{"authored_by":{"description":"AuthoredBy is the validated subject on the record.","type":"string"},"content_hash":{"description":"ContentHash is the server's digest of the recorded content.","type":"string"},"digest":{"description":"Digest is what the fold consumed: content hash and clock together, so two\nversions of one id with identical content still differ in the fold.","type":"string"},"id":{"description":"ID is the record's stable id.","type":"string"},"kind":{"description":"Kind is idea, implementation, disclosure or approval.","type":"string"},"recorded_at":{"description":"RecordedAt is the server clock at the append.","type":"string"},"revision":{"description":"Revision is original, corrected or retracted.","type":"string"},"seq":{"description":"Seq is the append clock value. The ordering authority.","format":"int64","type":"integer"}},"type":"object"},"patent.PatentRejectedAlternative":{"properties":{"option":{"description":"Option is the approach, in the author's words.","type":"string"},"reason":{"description":"Reason is why it was rejected — the constraint or failure that decided it.","type":"string"}},"type":"object"},"patent.PatentSignature":{"properties":{"algo":{"description":"Algo names the scheme, e.g. ed25519. Empty means the record does not say.","type":"string"},"key_id":{"description":"KeyID names the key that signed. It is a reference, not public bytes.","type":"string"},"value":{"description":"Value is the signature, base64.","type":"string"},"verified":{"description":"Verified is the SERVER's answer to whether it checked this signature. It is\nfalse on a deployment with no verifier wired, and a record carrying an\nunchecked signature says so rather than borrowing credibility.","type":"boolean"}},"type":"object"},"patent.PatentTimeline":{"properties":{"found":{"description":"Found is false when no version of that id exists in this org.","type":"boolean"},"id":{"description":"ID is the entry named.","type":"string"},"kind":{"description":"Kind is which log was read.","type":"string"},"project":{"description":"Project is the scope it is filed under.","type":"string"},"retained":{"description":"Retained is len(versions).","format":"int64","type":"integer"},"versions":{"description":"Versions are every retained version, oldest append first.","items":{"$ref":"#/components/schemas/patent.PatentTimelineEntry"},"type":"array"}},"type":"object"},"patent.PatentTimelineEntry":{"properties":{"authored_by":{"description":"AuthoredBy is the validated subject who appended it.","type":"string"},"canonical":{"description":"Canonical marks the version a listing would return: the latest non-retracted\none. Exactly one entry per id is canonical, or none, when the latest retracts.","type":"boolean"},"content_hash":{"description":"ContentHash is this version's identity.","type":"string"},"recorded_at":{"description":"RecordedAt is the server clock at the append.","type":"string"},"revision":{"description":"Revision is original, corrected or retracted.","type":"string"},"seq":{"description":"Seq is the append clock value this version was stamped with.","format":"int64","type":"integer"},"superseded":{"description":"Superseded marks a retained version that a later one replaced. Retained and\nsuperseded are both true of most of a long history, and that is the point.","type":"boolean"}},"type":"object"},"patent.approvalBatch":{"properties":{"approvals":{"description":"Approvals are the decisions to append, at most 2000.","items":{"$ref":"#/components/schemas/patent.PatentApproval"},"type":"array"}},"type":"object"},"patent.approvalsOut":{"properties":{"data":{"description":"Data are the current decisions of record, oldest append first.","items":{"$ref":"#/components/schemas/patent.PatentApproval"},"type":"array"},"total":{"description":"Total is len(data).","format":"int64","type":"integer"}},"type":"object"},"patent.disclosureBatch":{"properties":{"disclosures":{"description":"Disclosures are the documents to append, at most 2000.","items":{"$ref":"#/components/schemas/patent.PatentDisclosure"},"type":"array"}},"type":"object"},"patent.discsOut":{"properties":{"data":{"description":"Data are the canonical disclosures, oldest append first.","items":{"$ref":"#/components/schemas/patent.PatentDisclosure"},"type":"array"},"total":{"description":"Total is len(data).","format":"int64","type":"integer"}},"type":"object"},"patent.grantIn":{"properties":{"id":{"description":"ID is the record's stable id.","type":"string"},"kind":{"description":"Kind is idea, implementation or disclosure — what the id names.","type":"string"},"project":{"description":"Project locates the record inside the caller's own org.","type":"string"},"visibility":{"description":"Visibility is private, org or public.","type":"string"}},"type":"object"},"patent.ideaBatch":{"properties":{"ideas":{"description":"Ideas are the entries to append, at most 2000.","items":{"$ref":"#/components/schemas/patent.PatentIdea"},"type":"array"}},"type":"object"},"patent.ideasOut":{"properties":{"data":{"description":"Data are the canonical entries, oldest append first.","items":{"$ref":"#/components/schemas/patent.PatentIdea"},"type":"array"},"total":{"description":"Total is len(data).","format":"int64","type":"integer"}},"type":"object"},"patent.implBatch":{"properties":{"implementations":{"description":"Implementations are the records to append, at most 2000.","items":{"$ref":"#/components/schemas/patent.PatentImplementation"},"type":"array"}},"type":"object"},"patent.implsOut":{"properties":{"data":{"description":"Data are the canonical records, oldest append first.","items":{"$ref":"#/components/schemas/patent.PatentImplementation"},"type":"array"},"total":{"description":"Total is len(data).","format":"int64","type":"integer"}},"type":"object"},"patent.patentGrantOut":{"properties":{"updated":{"description":"Updated is how many records the grant moved to the visibility asked for.\nIt counts every RETAINED version of the target, so it is at least one.","format":"int64","type":"integer"}},"type":"object"},"patent.patentHealth":{"properties":{"anchored":{"description":"Anchored is whether record roots are committed outside this platform.\nFalse is the common case and the important one: without it the chain\nproves order WITHIN the platform's own honesty and nothing beyond it.","type":"boolean"},"durable":{"description":"Durable is whether acknowledged writes are fenced to a durable object.\nFalse means a store is local to this pod: the records stand, failover does\nnot carry them.","type":"boolean"},"now":{"description":"RecordedAt is the server's time now, RFC3339 — so a reader can tell how\nstale its own view is.","type":"string"},"signature_verification":{"description":"SignatureVerification is whether the server can verify a submitted\ndetached signature. Attribution does not depend on it — the author of\nevery record is the validated principal, never a body field — but a\nrecord carrying a signature it cannot check says so.","type":"boolean"},"stamped_by":{"description":"ServerClockSays is what stamps a record: always \"server\", because no\nclient-supplied timestamp is read anywhere in this package.","type":"string"}},"type":"object"},"patent.patentWriteOut":{"properties":{"canonical":{"description":"Canonical is how many entries the org's log now holds for this kind.","format":"int64","type":"integer"},"project":{"description":"Project is the scope the batch was filed under, as the server decided it.","type":"string"},"recorded":{"description":"Recorded is how many new versions this call appended.","format":"int64","type":"integer"}},"type":"object"},"patrol.patrolAct":{"properties":{"act":{"description":"Act is the act performed.","type":"string"},"actor":{"description":"Actor is who performed it.","type":"string"},"at":{"description":"At is when it happened.","type":"string"},"detail":{"description":"Detail is what they wrote with it.","type":"string"},"from":{"description":"From is the state the incident left.","type":"string"},"to":{"description":"To is the state it landed in.","type":"string"}},"type":"object"},"patrol.patrolActivation":{"properties":{"alarm":{"description":"Alarm is the recorded activation's document name.","type":"string"},"incident":{"$ref":"#/components/schemas/patrol.patrolIncident","description":"Incident is the incident it opened, or null when it matched no site."},"matched":{"description":"Matched says whether a site was found for it.","type":"boolean"},"site":{"description":"Site is the site it matched, or empty.","type":"string"}},"type":"object"},"patrol.patrolAlarmIn":{"properties":{"account":{"description":"Account is the alarm-panel account number that reported. It is what an\nactivation matches a site on when no site is named.","type":"string"},"raw":{"description":"Raw is the activation exactly as it arrived, kept verbatim up to 16 KiB.\nA panel's own idea of the time rides in here; when the activation was\nreceived is the server's stamp, which is the fact an insurer and a court\nread off it and the one every SLA clock runs from."},"ref":{"description":"Ref is the receiving centre's own reference for the activation.","type":"string"},"site":{"description":"Site names the site directly, by document name, when the caller already\nknows it.","type":"string"},"source":{"description":"Source is which receiver or operator the activation came through.","type":"string"},"trigger":{"description":"Trigger is what the panel reported.","type":"string"},"zone":{"description":"Zone is the panel zone that fired.","type":"string"}},"type":"object"},"patrol.patrolAlarmOut":{"properties":{"data":{"$ref":"#/components/schemas/patrol.patrolActivation","description":"Data is what became of the activation."}},"type":"object"},"patrol.patrolCamera":{"properties":{"kind":{"description":"Kind is the camera type.","type":"string"},"label":{"description":"Label is what the camera is called on screen.","type":"string"},"name":{"description":"Name is the camera's document name and the segment\n/v1/patrol/camera/{name}/stream addresses it by.","type":"string"},"online":{"description":"Online says whether the camera last reported healthy.","type":"boolean"},"site":{"description":"Site is the site the camera watches.","type":"string"}},"type":"object"},"patrol.patrolCameraList":{"properties":{"data":{"description":"Data is the matching cameras, never their credentials.","items":{"$ref":"#/components/schemas/patrol.patrolCamera"},"type":"array"}},"type":"object"},"patrol.patrolCheckpoint":{"properties":{"actor":{"description":"Actor is who confirmed it.","type":"string"},"at":{"description":"At is when it was confirmed, or empty.","type":"string"},"close":{"description":"Close is when that window shuts.","type":"string"},"lat":{"description":"Lat is the latitude the confirmation was taken at.","format":"double","type":"number"},"lon":{"description":"Lon is the longitude the confirmation was taken at.","format":"double","type":"number"},"method":{"description":"Method is how it was confirmed: tag, scan, fence, manual or photo.","type":"string"},"name":{"description":"Name is the checkpoint's document name and the segment\n/v1/patrol/point/{name}/confirm addresses it by.","type":"string"},"open":{"description":"Open is when the window to confirm it opens.","type":"string"},"photo":{"description":"Photo is the object key of the photo taken, or empty.","type":"string"},"site":{"description":"Site is the site to attend.","type":"string"},"state":{"description":"State is pending, done, late or skipped.","type":"string"},"tag":{"description":"Tag is the tag or marker to read there.","type":"string"},"tour":{"description":"Tour is the round this checkpoint belongs to.","type":"string"}},"type":"object"},"patrol.patrolCheckpointOut":{"properties":{"data":{"$ref":"#/components/schemas/patrol.patrolCheckpoint","description":"Data is the checkpoint as it now stands."}},"type":"object"},"patrol.patrolClock":{"properties":{"elapsed":{"description":"Elapsed is the seconds run so far, or the seconds it took when settled.","format":"int64","type":"integer"},"label":{"description":"Label names the clock: Verify, Dispatch or On site.","type":"string"},"settled":{"description":"Settled is the seconds it took, or -1 while the clock is still running.","format":"int64","type":"integer"},"target":{"description":"Target is the contracted seconds.","format":"int64","type":"integer"}},"type":"object"},"patrol.patrolConfirmIn":{"properties":{"lat":{"description":"Lat is the latitude the confirmation was taken at.","format":"double","type":"number"},"lon":{"description":"Lon is the longitude the confirmation was taken at.","format":"double","type":"number"},"method":{"description":"Method is how presence was proved: tag, scan, fence, manual or photo.","type":"string"},"name":{"description":"Name is the checkpoint's document name, from the path.","type":"string"},"photo":{"description":"Photo is the object key of a photo taken there, never the bytes.","type":"string"}},"type":"object"},"patrol.patrolEstate":{"properties":{"events":{"description":"Events is the recent feed, newest first.","items":{"$ref":"#/components/schemas/patrol.patrolEvent"},"type":"array"},"incident":{"$ref":"#/components/schemas/patrol.patrolIncident","description":"Incident is the incident currently running, or null when none is."},"keys":{"description":"Keys is the key register, empty for a caller whose roles do not reach it.","items":{"$ref":"#/components/schemas/patrol.patrolKey"},"type":"array"},"sites":{"description":"Sites is the estate under contract.","items":{"$ref":"#/components/schemas/patrol.patrolSite"},"type":"array"},"tours":{"description":"Tours is today's rounds with their checkpoints.","items":{"$ref":"#/components/schemas/patrol.patrolTour"},"type":"array"},"units":{"description":"Units is the fleet, each with the tail of its position trail.","items":{"$ref":"#/components/schemas/patrol.patrolUnit"},"type":"array"}},"type":"object"},"patrol.patrolEvent":{"properties":{"at":{"description":"At is when it was raised.","type":"string"},"detail":{"description":"Detail is the longer account, or empty.","type":"string"},"level":{"description":"Level is red, amber, green or cyan.","type":"string"},"name":{"description":"Name is the event's document name.","type":"string"},"site":{"description":"Site is the site the event is about, or empty.","type":"string"},"source":{"description":"Source is what raised it.","type":"string"},"title":{"description":"Title is the one line the feed shows.","type":"string"},"unit":{"description":"Unit is the unit the event is about, or empty.","type":"string"}},"type":"object"},"patrol.patrolEventIn":{"properties":{"detail":{"description":"Detail is the longer account.","type":"string"},"level":{"description":"Level is red, amber, green or cyan.","type":"string"},"site":{"description":"Site is the site it is about, by document name.","type":"string"},"source":{"description":"Source is what raised it.","type":"string"},"title":{"description":"Title is the one line the feed shows.","type":"string"},"unit":{"description":"Unit is the unit it is about, by call sign.","type":"string"}},"type":"object"},"patrol.patrolEventList":{"properties":{"data":{"description":"Data is the matching rows, newest first.","items":{"$ref":"#/components/schemas/patrol.patrolEvent"},"type":"array"}},"type":"object"},"patrol.patrolEventOut":{"properties":{"data":{"$ref":"#/components/schemas/patrol.patrolEvent","description":"Data is the row as recorded."}},"type":"object"},"patrol.patrolFix":{"properties":{"at":{"description":"At is when the position was recorded.","type":"string"},"lat":{"description":"Lat is the latitude in degrees.","format":"double","type":"number"},"lon":{"description":"Lon is the longitude in degrees.","format":"double","type":"number"}},"type":"object"},"patrol.patrolFixIn":{"properties":{"at":{"description":"At is not a caller's to fill. A position report is stamped by the server,\nand a body naming it is refused rather than silently restamped: the trail is\nthe proof of where a unit was, so a report that thought it was dating itself\nmust learn otherwise.","type":"string"},"lat":{"description":"Lat is the latitude in degrees.","format":"double","type":"number"},"lon":{"description":"Lon is the longitude in degrees.","format":"double","type":"number"},"name":{"description":"Name is the unit's call sign, from the path.","type":"string"}},"type":"object"},"patrol.patrolFixOut":{"properties":{"data":{"$ref":"#/components/schemas/patrol.patrolFixed","description":"Data is the acknowledgement."}},"type":"object"},"patrol.patrolFixed":{"properties":{"at":{"description":"At is the moment the position was recorded under.","type":"string"}},"type":"object"},"patrol.patrolIncident":{"properties":{"checked":{"description":"Checked is when the premises had been walked.","type":"string"},"clocks":{"description":"Clocks is the SLA clocks, present on a single-incident read.","items":{"$ref":"#/components/schemas/patrol.patrolClock"},"type":"array"},"closed":{"description":"Closed is when the incident was closed.","type":"string"},"dispatched":{"description":"Dispatched is when a unit was assigned.","type":"string"},"enroute":{"description":"Enroute is when that unit started moving.","type":"string"},"escalated":{"description":"Escalated is when it was escalated, or empty.","type":"string"},"false":{"description":"False says the activation turned out to be nothing.","type":"boolean"},"filed":{"description":"Filed is when the report was written.","type":"string"},"name":{"description":"Name is the incident's document name.","type":"string"},"onsite":{"description":"Onsite is when it arrived.","type":"string"},"opened":{"description":"Opened is when the activation landed.","type":"string"},"outcome":{"description":"Outcome is what it came to.","type":"string"},"ref":{"description":"Ref is the receiving centre's own reference.","type":"string"},"secured":{"description":"Secured is when the site was made safe.","type":"string"},"site":{"description":"Site is where it is happening.","type":"string"},"sla":{"description":"SLA is the contracted response time in minutes.","format":"int64","type":"integer"},"state":{"description":"State is one of received, verified, dispatched, enroute, onsite, checked,\nsecured, filed and closed.","type":"string"},"steps":{"description":"Steps is the act trail, present on a single-incident read.","items":{"$ref":"#/components/schemas/patrol.patrolAct"},"type":"array"},"tier":{"description":"Tier is the site's contracted service tier.","type":"string"},"trigger":{"description":"Trigger is what the panel reported.","type":"string"},"unit":{"description":"Unit is the call sign attending, or empty.","type":"string"},"verified":{"description":"Verified is when the activation was confirmed real.","type":"string"},"zone":{"description":"Zone is the panel zone that reported.","type":"string"}},"type":"object"},"patrol.patrolIncidentAct":{"properties":{"act":{"description":"Act is VERIFY, DISPATCH, ROLL, ARRIVE, CHECK, SECURE, FILE, CLOSE or\nESCALATE.","type":"string"},"detail":{"description":"Detail is what to write on the trail with this act.","type":"string"},"false":{"description":"False says the activation turned out to be nothing, read by CLOSE.","type":"boolean"},"name":{"description":"Name is the incident's document name, from the path.","type":"string"},"outcome":{"description":"Outcome is what the incident came to, read by CLOSE.","type":"string"},"unit":{"description":"Unit is the call sign to send, read by DISPATCH.","type":"string"}},"type":"object"},"patrol.patrolIncidentIn":{"properties":{"ref":{"description":"Ref is the receiving centre's own reference.","type":"string"},"site":{"description":"Site is where it is happening, by document name.","type":"string"},"trigger":{"description":"Trigger is what was reported.","type":"string"},"zone":{"description":"Zone is the panel zone that reported.","type":"string"}},"type":"object"},"patrol.patrolIncidentList":{"properties":{"data":{"description":"Data is the matching incidents, without their trails.","items":{"$ref":"#/components/schemas/patrol.patrolIncident"},"type":"array"}},"type":"object"},"patrol.patrolIncidentOut":{"properties":{"data":{"$ref":"#/components/schemas/patrol.patrolIncident","description":"Data is the incident with its act trail and SLA clocks."}},"type":"object"},"patrol.patrolKey":{"properties":{"holder":{"description":"Holder is who has it now.","type":"string"},"moved":{"description":"Moved is when it last changed hands.","type":"string"},"name":{"description":"Name is the key set's reference, which is its document name.","type":"string"},"site":{"description":"Site is the site the keys open.","type":"string"},"where":{"description":"Where is where the set is kept.","type":"string"}},"type":"object"},"patrol.patrolKeyList":{"properties":{"data":{"description":"Data is every key set held.","items":{"$ref":"#/components/schemas/patrol.patrolKey"},"type":"array"}},"type":"object"},"patrol.patrolKeyOut":{"properties":{"data":{"$ref":"#/components/schemas/patrol.patrolKey","description":"Data is the key set."}},"type":"object"},"patrol.patrolMoveIn":{"properties":{"act":{"description":"Act is out, in or audit.","type":"string"},"holder":{"description":"Holder is who the keys went to. Who SIGNED for the move is the caller, and\nis stamped from the request rather than read from here.","type":"string"},"job":{"description":"Job is the work the keys were drawn for.","type":"string"},"name":{"description":"Name is the key set's reference, from the path.","type":"string"}},"type":"object"},"patrol.patrolNearList":{"properties":{"data":{"description":"Data is the closest units, available ones first and then by distance.","items":{"$ref":"#/components/schemas/patrol.patrolNearest"},"type":"array"}},"type":"object"},"patrol.patrolNearest":{"properties":{"eta":{"description":"Eta is the minutes the drive would take at the planning speed.","format":"int64","type":"integer"},"km":{"description":"Km is the great-circle distance to the site in kilometres.","format":"double","type":"number"},"unit":{"description":"Unit is the unit's call sign.","type":"string"}},"type":"object"},"patrol.patrolNote":{"properties":{"actor":{"description":"Actor is who wrote it.","type":"string"},"at":{"description":"At is when it was written.","type":"string"},"body":{"description":"Body is the remark.","type":"string"},"name":{"description":"Name is the note's document name.","type":"string"},"subject":{"description":"Subject is what the note is about.","type":"string"}},"type":"object"},"patrol.patrolNoteIn":{"properties":{"body":{"description":"Body is the remark.","type":"string"},"subject":{"description":"Subject is what the note is about.","type":"string"}},"type":"object"},"patrol.patrolNoteList":{"properties":{"data":{"description":"Data is the matching notes in store order.","items":{"$ref":"#/components/schemas/patrol.patrolNote"},"type":"array"}},"type":"object"},"patrol.patrolNoteOut":{"properties":{"data":{"$ref":"#/components/schemas/patrol.patrolNote","description":"Data is the note as written."}},"type":"object"},"patrol.patrolReport":{"properties":{"at":{"description":"At is when it was filed.","type":"string"},"body":{"description":"Body is the report as text.","type":"string"},"client":{"description":"Client is the customer it is about, or empty.","type":"string"},"from":{"description":"From is the start of the window the report covers.","type":"string"},"incident":{"description":"Incident is the incident it is about, or empty.","type":"string"},"kind":{"description":"Kind is shift, incident or client.","type":"string"},"name":{"description":"Name is the report's document name and the segment\n/v1/patrol/report/{name} addresses it by.","type":"string"},"to":{"description":"To is the end of that window.","type":"string"}},"type":"object"},"patrol.patrolReportIn":{"properties":{"client":{"description":"Client is the customer to report on, read by kind client. Naming one files\nan account that customer may download; leaving it empty covers every\ncustomer, which is an account of the operation and stays with it.","type":"string"},"from":{"description":"From is the start of the window to cover.","type":"string"},"incident":{"description":"Incident is the incident to report on, required for kind incident.","type":"string"},"kind":{"description":"Kind is shift, incident or client.","type":"string"},"to":{"description":"To is the end of that window.","type":"string"}},"type":"object"},"patrol.patrolReportOut":{"properties":{"data":{"$ref":"#/components/schemas/patrol.patrolReport","description":"Data is the report as filed."}},"type":"object"},"patrol.patrolSite":{"properties":{"account":{"description":"Account is the alarm-panel account number the receiving centre reports.","type":"string"},"cameras":{"description":"Cameras is how many cameras are registered here.","format":"int64","type":"integer"},"category":{"description":"Category is what kind of premises this is.","type":"string"},"client":{"description":"Client is the customer this site belongs to.","type":"string"},"contact":{"description":"Contact is the keyholder to reach.","type":"string"},"eircode":{"description":"Eircode is the postal code.","type":"string"},"hazards":{"description":"Hazards is the standing warnings, present on a single-site read.","items":{"type":"string"},"type":"array"},"keys":{"description":"Keys says whether the operation holds a key set for this site.","type":"boolean"},"lat":{"description":"Lat is the site's latitude in degrees.","format":"double","type":"number"},"lon":{"description":"Lon is the site's longitude in degrees.","format":"double","type":"number"},"name":{"description":"Name is the site's document name and the segment /v1/patrol/site/{name}\naddresses it by.","type":"string"},"notes":{"description":"Notes is the standing brief for the site.","type":"string"},"ref":{"description":"Ref is the site's number in the register.","format":"int64","type":"integer"},"risk":{"description":"Risk is the assessed risk score.","format":"int64","type":"integer"},"sector":{"description":"Sector is the patrol sector the site sits in.","type":"string"},"sla":{"description":"SLA is the contracted response time in minutes.","format":"int64","type":"integer"},"status":{"description":"Status is ok, fault, alarm or offline.","type":"string"},"tier":{"description":"Tier is the contracted service tier.","type":"string"},"town":{"description":"Town is the town the site is in.","type":"string"},"unit":{"description":"Unit is the call sign of the unit that covers the site, or empty.","type":"string"},"visits":{"description":"Visits is how many patrol visits the contract calls for.","format":"int64","type":"integer"},"zones":{"description":"Zones is the panel's detection zones, present on a single-site read.","items":{"$ref":"#/components/schemas/patrol.patrolZone"},"type":"array"}},"type":"object"},"patrol.patrolSiteEdit":{"properties":{"category":{"description":"Category is what kind of premises this is.","type":"string"},"contact":{"description":"Contact is the keyholder to reach.","type":"string"},"eircode":{"description":"Eircode is the postal code.","type":"string"},"name":{"description":"Name is the site's document name, from the path.","type":"string"},"notes":{"description":"Notes is the standing brief for the site.","type":"string"},"sector":{"description":"Sector is the patrol sector the site sits in.","type":"string"},"sla":{"description":"SLA is the contracted response time in minutes.","format":"int64","type":"integer"},"status":{"description":"Status is ok, fault, alarm or offline.","type":"string"},"tier":{"description":"Tier is the contracted service tier.","type":"string"},"town":{"description":"Town is the town the site is in.","type":"string"}},"type":"object"},"patrol.patrolSiteList":{"properties":{"data":{"description":"Data is the matching sites, without their zones and hazards.","items":{"$ref":"#/components/schemas/patrol.patrolSite"},"type":"array"}},"type":"object"},"patrol.patrolSiteOut":{"properties":{"data":{"$ref":"#/components/schemas/patrol.patrolSite","description":"Data is the site with its zones and hazards."}},"type":"object"},"patrol.patrolSnapshotOut":{"properties":{"data":{"$ref":"#/components/schemas/patrol.patrolEstate","description":"Data is the whole estate as one read."}},"type":"object"},"patrol.patrolStream":{"properties":{"expires":{"description":"Expires is when that address stops working.","type":"string"},"url":{"description":"URL is the address to open the stream at.","type":"string"}},"type":"object"},"patrol.patrolStreamOut":{"properties":{"data":{"$ref":"#/components/schemas/patrol.patrolStream","description":"Data is the stream address and its expiry."}},"type":"object"},"patrol.patrolTenant":{"properties":{"brand":{"description":"Brand is the look: names, colours, logo references."},"company":{"description":"Company is the legal entity behind the operation — name, address, licence."},"features":{"description":"Features says which parts of the product this tenant runs."},"operations":{"description":"Operations is how the operation runs: coverage, timezone, SLA targets."},"terminology":{"description":"Terminology is the words this tenant's screens use for site, unit and\nofficer."}},"type":"object"},"patrol.patrolTenantOut":{"properties":{"data":{"$ref":"#/components/schemas/patrol.patrolTenant","description":"Data is the tenant's public configuration."}},"type":"object"},"patrol.patrolTicketOut":{"properties":{"data":{"$ref":"#/components/schemas/patrol.patrolStream","description":"Data is the address that opens the camera and when the ticket stops working."}},"type":"object"},"patrol.patrolTour":{"properties":{"date":{"description":"Date is the day the round belongs to.","type":"string"},"end":{"description":"End is when it finished.","type":"string"},"name":{"description":"Name is the tour's document name.","type":"string"},"points":{"description":"Points is the round's checkpoints in store order.","items":{"$ref":"#/components/schemas/patrol.patrolCheckpoint"},"type":"array"},"start":{"description":"Start is when the round began.","type":"string"},"unit":{"description":"Unit is the call sign running the round.","type":"string"}},"type":"object"},"patrol.patrolTourList":{"properties":{"data":{"description":"Data is the matching rounds, each with its checkpoints.","items":{"$ref":"#/components/schemas/patrol.patrolTour"},"type":"array"}},"type":"object"},"patrol.patrolUnit":{"properties":{"due":{"description":"Due is the lone-worker deadline, or empty when none is set.","type":"string"},"lat":{"description":"Lat is the unit's last latitude in degrees.","format":"double","type":"number"},"lon":{"description":"Lon is the unit's last longitude in degrees.","format":"double","type":"number"},"name":{"description":"Name is the unit's call sign, which is its document name and the segment\n/v1/patrol/unit/{name}/fix addresses it by.","type":"string"},"officer":{"description":"Officer is who is crewing it.","type":"string"},"sector":{"description":"Sector is the patrol sector it works.","type":"string"},"seen":{"description":"Seen is when the unit last reported.","type":"string"},"state":{"description":"State is available, assigned, enroute, onsite, offline, break or emergency.","type":"string"},"trail":{"description":"Trail is the tail of the unit's recorded positions, oldest first.","items":{"$ref":"#/components/schemas/patrol.patrolFix"},"type":"array"}},"type":"object"},"patrol.patrolUnitList":{"properties":{"data":{"description":"Data is every unit in the org, each with its position trail.","items":{"$ref":"#/components/schemas/patrol.patrolUnit"},"type":"array"}},"type":"object"},"patrol.patrolUnitOut":{"properties":{"data":{"$ref":"#/components/schemas/patrol.patrolUnit","description":"Data is the unit as it now stands."}},"type":"object"},"patrol.patrolUnitStateIn":{"properties":{"name":{"description":"Name is the unit's call sign, from the path.","type":"string"},"state":{"description":"State is available, assigned, enroute, onsite, offline, break or emergency.","type":"string"}},"type":"object"},"patrol.patrolZone":{"properties":{"device":{"description":"Device is the detector type.","type":"string"},"location":{"description":"Location is where in the building the zone is.","type":"string"},"ref":{"description":"Ref is the zone number the panel reports.","type":"string"},"state":{"description":"State is the zone's last known condition.","type":"string"}},"type":"object"},"plan.planEntitlements":{"properties":{"entitlements":{"description":"Entitlements is the canonical namespaced entitlement block derived from the\nplan's limits and addons, where -1 means unlimited."},"id":{"description":"ID is the plan id or slug that was resolved, as it was requested.","type":"string"},"license_features":{"description":"LicenseFeatures is the flat, sorted feature list a signed license carries,\nderived from the entitlements.","items":{"type":"string"},"type":"array"}},"type":"object"},"plan.planHealth":{"properties":{"service":{"description":"Service names the subsystem that answered.","type":"string"},"status":{"description":"Status is \"ok\" whenever this subsystem is mounted.","type":"string"}},"type":"object"},"plan.planList":{"properties":{"plans":{"description":"Plans are the plans in this section, each an opaque object exactly as the\n@hanzo/plans catalog emits it — typically id, name, description,\npriceMonthly, category, a feature list, a limits block and a price_ref.","items":{},"type":"array"}},"type":"object"},"plan.planRegionList":{"properties":{"regions":{"description":"Regions are the regions cloud capacity is offered in, each an opaque object\nexactly as the catalog emits it — typically id, name, location and flag.","items":{},"type":"array"}},"type":"object"},"plan.planResolution":{"properties":{"entitlements":{"description":"Entitlements is the canonical namespaced entitlement block derived from the\nplan's limits and addons — keys like \"ai.tokens_per_min\" and\n\"world.api_rate_limit\", where -1 means unlimited."},"id":{"description":"ID is the plan's catalog id.","type":"string"},"license_features":{"description":"LicenseFeatures is the flat, sorted feature list a signed license carries,\nderived from the entitlements — \"ai.premium\", \"licensing.product:team\".","items":{"type":"string"},"type":"array"},"price_ref":{"description":"PriceRef is the plan's billing reference — currency, the recurring monthly\nand annual amounts, whether it prices per seat, its Stripe lookup key and\nits metered components."},"tenant_id":{"description":"TenantID is the catalog the record came from: \"hanzo\" for the canonical\ncatalog, a reseller org for that reseller's override.","type":"string"}},"type":"object"},"plan.planSchemas":{"properties":{"entitlements":{"description":"Entitlements is entitlements.schema.json — the JSON Schema every\nentitlement key is declared in, including its type, unit and enum."},"plan":{"description":"Plan is plan.schema.json — the JSON Schema a catalog plan record conforms\nto."}},"type":"object"},"plan.planTierList":{"properties":{"tiers":{"description":"Tiers are the rentable GPU configurations, each an opaque object exactly as\nthe catalog emits it — typically id, name, GPU count and model, VRAM, vCPUs,\nhost memory and hourly price.","items":{},"type":"array"}},"type":"object"},"plan.planToolList":{"properties":{"tools":{"description":"Tools are the metered tools, each an opaque object exactly as the catalog\nemits it — typically name, billing unit and price.","items":{},"type":"array"}},"type":"object"},"plan.planVocab":{"properties":{"engine_features":{"description":"EngineFeatures are the inference-engine capabilities a license can grant:\ninference, embeddings, rerank, training, vision, audio, tools.","items":{"type":"string"},"type":"array"},"keys":{"additionalProperties":{},"description":"Keys maps every entitlement key to its descriptor — key, namespace, JSON\ntype(s), nullability, unit, enum and title, as the schema declares them.","type":"object"},"namespaces":{"description":"Namespaces are the entitlement key namespaces: the prefix before the dot in\n\"ai.tokens_per_min\".","items":{"type":"string"},"type":"array"}},"type":"object"},"platform.AppView":{"properties":{"app":{"description":"service / CR name, e.g. iam","type":"string"},"cluster":{"description":"always \"hanzo-k8s\"; cross-cluster federation is a follow-up phase","type":"string"},"declaredTag":{"description":"spec.image.tag — the tag the CR SAYS to run; anything but vX.Y.Z is red drift","type":"string"},"drift":{"$ref":"#/components/schemas/platform.Verdict","description":"declared vs running vs latest as flags, plus their rolled-up severity"},"endpoints":{"description":"status.endpoints the operator published for this service; empty until it reconciles","items":{"type":"string"},"type":"array"},"env":{"description":"main|test|dev","type":"string"},"health":{"description":"green|yellow|red|\"\" (unknown)","type":"string"},"id":{"description":"\u003corg\u003e/\u003capp\u003e/\u003cenv\u003e, e.g. hanzoai/iam/main","type":"string"},"latestTag":{"description":"newest released tag; \"\" until the GH release reader lands, so \"stale\" cannot fire yet","type":"string"},"namespace":{"description":"namespace the row was scanned from: a platform one (hanzo, hanzo-testnet, …) or a tenant-\u003corg\u003e","type":"string"},"org":{"description":"image namespace, e.g. hanzoai","type":"string"},"phase":{"description":"operator status.phase (Running/…)","type":"string"},"registry":{"description":"spec.image.repository verbatim (ghcr.io/hanzoai/iam); Org and Repo are read off it","type":"string"},"repo":{"description":"owner/repo, e.g. hanzoai/iam","type":"string"},"role":{"description":"operator spec.role (sql|kv|generic|ingress|…) or \"\" — the one declared class field","type":"string"},"runningTag":{"description":"the tag the live Deployment actually runs; \"\" when unreadable — unknown, not a guess","type":"string"}},"type":"object"},"platform.CDApp":{"properties":{"applied":{"description":"Applied is the universe commit CD last synced, from its deploy history. It\ntrails Revision exactly while a sync is pending.","type":"string"},"automated":{"description":"Automated is whether CD applies git without being asked. It is\ncd.automated in the values file, rendered by the ApplicationSet's\ntemplatePatch — false means the Application reports drift and nothing moves.","type":"boolean"},"cluster":{"description":"Cluster is where the Application deploys: its destination cluster's name,\nelse its server URL (https://kubernetes.default.svc is CD's own cluster).","type":"string"},"health":{"description":"Health is the workload's verdict: Healthy, Progressing, Degraded, Missing.","type":"string"},"message":{"description":"Message is why, when Health is not Healthy.","type":"string"},"name":{"description":"Name is the Application name the generator mints: \u003cnamespace\u003e-\u003capp\u003e. It is\nthe join key against a Declaration.","type":"string"},"namespace":{"description":"Namespace is the DESTINATION namespace as the CR declares it — where the\nworkload lands. For a fleet Application that is the org, but this is the\nOBSERVED field and not our model of it: the two can disagree, and a board\nwhose whole job is drift must be able to show that they do.","type":"string"},"operationMessage":{"type":"string"},"path":{"description":"Path is the values file CD renders against, relative to the chart source.","type":"string"},"phase":{"description":"Phase is the last sync operation's phase (Running, Succeeded, Failed) and\nOperationMessage is its message. A Failed phase with a Synced verdict is\nthe shape a stuck Application takes.","type":"string"},"project":{"description":"Project is the AppProject fence the sync is admitted under.","type":"string"},"reconciledAt":{"description":"ReconciledAt is when CD last compared this Application.","type":"string"},"revision":{"description":"Revision is the universe commit CD last compared the cluster against — what\na sync applies. Empty means it has compared none; never assume it means main.","type":"string"},"selfHeal":{"description":"SelfHeal is whether CD also corrects drift the cluster introduced.","type":"boolean"},"sync":{"description":"Sync is CD's verdict on git-versus-cluster: Synced, OutOfSync, or Unknown.","type":"string"}},"type":"object"},"platform.Declaration":{"properties":{"application":{"description":"Application is the CD Application name the generator mints from the path —\nthe directory joined to the file name, less any words the two share\n(applicationName). It is how cd.hanzo.ai names the app.","type":"string"},"automated":{"description":"Automated is cd.automated: false means the Application reports drift and\nNOTHING moves. It is off by default for a new file on purpose.","type":"boolean"},"component":{"description":"Component is the app's role within its project (`component`), \"\" when unnamed.","type":"string"},"digest":{"description":"image.digest — wins over tag","type":"string"},"env":{"description":"Env is the declared container environment, as the chart's list of\n{name,value}. It is read back so a re-declare of an identical body is a\nno-op rather than a refusal — idempotency is what makes a retry safe.","items":{"$ref":"#/components/schemas/platform.declareEnv"},"type":"array"},"hosts":{"description":"ingress.hosts, both shapes flattened","items":{"type":"string"},"type":"array"},"name":{"description":"the Helm release name — the file's basename","type":"string"},"org":{"description":"Org is the owner. It is ALSO the values directory and the destination\nnamespace, because those are one value under one name — see the header.","type":"string"},"partOf":{"description":"PartOf is the platform project this app belongs to: the values file's own\n`partOf` key, which the chart also stamps on every object it renders as\napp.kubernetes.io/part-of. It is the ONE declaration of membership — there is\nno project table — and \"\" means the file names none.","type":"string"},"path":{"description":"Path is the file, relative to the repository root.","type":"string"},"project":{"description":"Project is the AppProject the sync is admitted under, derived from the\ndirectory exactly as the ApplicationSet derives it. It differs from Org\nfor a reserved directory, which syncs under the platform fence.","type":"string"},"replicas":{"format":"int64","type":"integer"},"repository":{"description":"image.repository","type":"string"},"secrets":{"description":"Secrets are the KMS coordinates the app reads — kmsSecrets and secrets.paths\n— as paths and key names. A values file never carries a secret value, so\nneither does this.","items":{"$ref":"#/components/schemas/platform.SecretRef"},"type":"array"},"tag":{"description":"image.tag","type":"string"}},"type":"object"},"platform.DriftFlag":{"properties":{"kind":{"description":"Kind is which finding this is, one of stale, un-rolled, floating-declared,\nfloating-running, no-release or zero-assets. It is what code matches on, and\nthe kinds are independent — one row can carry several at once.","type":"string"},"message":{"description":"Message is the finding in words, naming the tags that produced it (\"running\nv1.2.3 has not rolled to declared v1.2.4\"). For display: match on Kind.","type":"string"},"severity":{"description":"Severity is this ONE finding's weight — yellow for stale and un-rolled, red\nfor the other four. It is a constant of the kind (severityOf), never a\njudgement about the row, so the same kind always weighs the same.","type":"string"}},"type":"object"},"platform.EnvVarJSON":{"properties":{"key":{"description":"Key is the variable's name in the container, which must match\n`^[A-Za-z_][A-Za-z0-9_]*$`. For a sealed value it is also the last segment\nof the KMS ref, so it is what identifies the value across a round trip.","type":"string"},"secret":{"description":"Secret says the value lives in KMS and never in the database. A caller may\nonly ADD secrecy: the server seals a value whose key or shape looks like a\ncredential anyway (secretshape.go), so an entry can come back secret that\nwas not sent that way.","type":"boolean"},"value":{"description":"Value is the plaintext, and it is WRITE-ONLY once the entry is secret: a\nsealed value reads back as \"\", and sending \"\" again KEEPS what is sealed\nrather than wiping it. Only a non-empty value seals a new one.","type":"string"}},"type":"object"},"platform.Project":{"properties":{"apps":{"description":"Apps is how many declarations name the project.","format":"int64","type":"integer"},"drift":{"$ref":"#/components/schemas/platform.driftTally","description":"Drift counts its apps by drift severity."},"health":{"$ref":"#/components/schemas/platform.healthTally","description":"Health counts its apps by CD's health verdict."},"name":{"description":"Name is the project, as the values files spell it in `partOf`.","type":"string"},"namespaces":{"description":"Namespaces are the namespaces its apps deploy into, sorted.","items":{"type":"string"},"type":"array"},"org":{"description":"Org is the organization that owns the project. Absent for the platform's own\nprojects, whose apps live in the platform's directories.","type":"string"},"sync":{"$ref":"#/components/schemas/platform.syncTally","description":"Sync counts its apps by CD's sync verdict."}},"type":"object"},"platform.ProjectApp":{"properties":{"application":{"description":"Application is the CD Application name the generator mints from the path —\nthe directory joined to the file name, less any words the two share\n(applicationName). It is how cd.hanzo.ai names the app.","type":"string"},"automated":{"description":"Automated is cd.automated: false means the Application reports drift and\nNOTHING moves. It is off by default for a new file on purpose.","type":"boolean"},"cd":{"$ref":"#/components/schemas/platform.CDApp","description":"CD is the Application reconciling it; null when CD has none for this file."},"component":{"description":"Component is the app's role within its project (`component`), \"\" when unnamed.","type":"string"},"digest":{"description":"image.digest — wins over tag","type":"string"},"drift":{"$ref":"#/components/schemas/platform.Verdict","description":"Drift is declared versus reconciled versus running versus latest, as flags."},"env":{"description":"Env is the declared container environment, as the chart's list of\n{name,value}. It is read back so a re-declare of an identical body is a\nno-op rather than a refusal — idempotency is what makes a retry safe.","items":{"$ref":"#/components/schemas/platform.declareEnv"},"type":"array"},"hosts":{"description":"ingress.hosts, both shapes flattened","items":{"type":"string"},"type":"array"},"image":{"description":"Image is the image the declaration names: repository@digest when it pins a\ndigest, else repository:tag. Empty for a declaration that owns no workload.","type":"string"},"latest":{"description":"Latest is the newest semver tag the registry publishes for its repository,\n\"\" when that cannot be read.","type":"string"},"name":{"description":"the Helm release name — the file's basename","type":"string"},"org":{"description":"Org is the owner. It is ALSO the values directory and the destination\nnamespace, because those are one value under one name — see the header.","type":"string"},"partOf":{"description":"PartOf is the platform project this app belongs to: the values file's own\n`partOf` key, which the chart also stamps on every object it renders as\napp.kubernetes.io/part-of. It is the ONE declaration of membership — there is\nno project table — and \"\" means the file names none.","type":"string"},"path":{"description":"Path is the file, relative to the repository root.","type":"string"},"project":{"description":"Project is the AppProject the sync is admitted under, derived from the\ndirectory exactly as the ApplicationSet derives it. It differs from Org\nfor a reserved directory, which syncs under the platform fence.","type":"string"},"replicas":{"format":"int64","type":"integer"},"repository":{"description":"image.repository","type":"string"},"running":{"$ref":"#/components/schemas/platform.Running","description":"Running is what the cluster runs for it; null when no pod carries its\nselector or the cluster could not be read."},"secrets":{"description":"Secrets are the KMS coordinates the app reads — kmsSecrets and secrets.paths\n— as paths and key names. A values file never carries a secret value, so\nneither does this.","items":{"$ref":"#/components/schemas/platform.SecretRef"},"type":"array"},"tag":{"description":"image.tag","type":"string"}},"type":"object"},"platform.Record":{"properties":{"name":{"description":"the record name the customer creates","type":"string"},"type":{"description":"TXT | CNAME","type":"string"},"value":{"description":"the record value","type":"string"}},"type":"object"},"platform.Running":{"properties":{"digest":{"description":"Digest is the digest the kubelet resolved that image to, \"\" when no pod\nhas reported one yet.","type":"string"},"image":{"description":"Image is the image the app's container runs, as the pod spec names it.\nWhen pods disagree — a rollout in flight — it is the one most of them run.","type":"string"},"pods":{"description":"Pods is how many pods carry the app's selector.","format":"int64","type":"integer"},"ready":{"description":"Ready is how many of them report every container ready.","format":"int64","type":"integer"}},"type":"object"},"platform.SecretRef":{"properties":{"env":{"description":"Env is the KMS environment slug.","type":"string"},"keys":{"description":"Keys are the names read from the path; empty means the whole path.","items":{"type":"string"},"type":"array"},"path":{"description":"Path is the secret path, always absolute.","type":"string"},"project":{"description":"Project is the KMS project slug the path lives in.","type":"string"}},"type":"object"},"platform.Verdict":{"properties":{"flags":{"description":"Flags are the findings behind the severity, in detection order:\nfloating-declared, floating-running, stale, un-rolled, then the\nrelease-artifact ones. Always present — `[]` for a row that runs what it\ndeclares, never null.","items":{"$ref":"#/components/schemas/platform.DriftFlag"},"type":"array"},"severity":{"description":"Severity is the roll-up over Flags — red if any flag is red, else yellow if\nany is yellow, else ok. It is the column a board sorts and filters on, and\n\"ok\" is exactly what no flags means.","type":"string"}},"type":"object"},"platform.addDomainReq":{"properties":{"app":{"description":"App is the application's slug, from the path.","type":"string"},"host":{"description":"Host is the hostname to attach. Required, and must be a valid DNS hostname.","type":"string"},"project":{"description":"Project is the project the application lives under, from the path.","type":"string"}},"type":"object"},"platform.appMove":{"properties":{"app":{"description":"App is the declaration's name, from the path.","type":"string"},"mode":{"description":"Mode is `branch` (the default) or `commit`.","type":"string"},"org":{"description":"Org is the values directory the app lives in, defaulting to the caller's own\norg.","type":"string"},"partOf":{"description":"PartOf is the project to move it to. A name nothing names yet creates it.","type":"string"}},"type":"object"},"platform.appOut":{"properties":{"buildType":{"description":"BuildType is how a git app builds: `pack`, the zero-config default that\ndetects the project, or `dockerfile`. An image app carries `image`, which\nmeans it never builds.","type":"string"},"createdAt":{"description":"CreatedAt is when the app was created, unix seconds.","format":"int64","type":"integer"},"currentDeploymentId":{"description":"CurrentDeploymentID is the deployment that is live — the pointer a deploy\nadvances monotonically by version, so it never regresses to an older one.\nEmpty until the first deploy reaches the cluster.","type":"string"},"description":{"description":"Description is free text about what the app is. Nothing derives from it.","type":"string"},"dockerfile":{"description":"Dockerfile is the path inside the repo to build from, for buildType\n`dockerfile`. The build path keys off its presence, and it is validated at\ncreate against the same allowlist the privileged build enforces.","type":"string"},"domains":{"description":"Domains are the ingress hosts rendered into the app's CR, its own\n`\u003cslug\u003e.\u003csites host\u003e` first. That one is seeded at create and cannot be\nremoved; a custom host joins only after add-domain and DNS verification.","items":{"type":"string"},"type":"array"},"env":{"description":"Env is the app's environment variables, with every SECRET value masked to \"\"\n— the plaintext is in KMS and this surface never echoes it. That masking is\nwhy an empty secret value means \"keep what is sealed\" when posted back.","items":{"$ref":"#/components/schemas/platform.EnvVarJSON"},"type":"array"},"environment":{"description":"Environment is the deploy target this app names, `production` when none was\ngiven. It is a LABEL: /v1/platform/environments derives the environment list\nfrom the apps that name one, so an environment exists as long as an app\npoints at it and no route creates or deletes one.","type":"string"},"health":{"description":"Health rolls ready-vs-desired replicas up to a colour: green (all ready),\nyellow (some ready, or deliberately scaled to zero), red (none), or \"\" when\nthe cluster reports no replica counts at all — unknown, never a guessed green.","type":"string"},"id":{"description":"ID is the server-minted application id (`app_…`). Routes address an app by\nproject and slug; this is the key its deployments and builds carry.","type":"string"},"image":{"$ref":"#/components/schemas/platform.imageView","description":"Image is the image a source `image` app runs. For a git app only the tag is\nfilled, stamped by the deploy that went live; the built ref is on the\ndeployment."},"name":{"description":"Name is the display name. It is not an address — the slug is.","type":"string"},"namespace":{"description":"Namespace is where the app's cluster objects live, `tenant-\u003corg\u003e`. It is\nderived from the validated org and is never accepted from a request.","type":"string"},"org":{"description":"Org is the tenant that owns the app. It comes from the validated identity,\nnever from the request, and it is the boundary every route is scoped to.","type":"string"},"phase":{"description":"Phase is the operator's own `status.phase` for the app's Service CR, read\nfrom the cluster on this request. Empty when there is no CR yet or the\ncluster could not be read.","type":"string"},"port":{"description":"Port is the container port traffic is sent to. 8080 when the create asked\nfor none, or for one outside 1–65535.","format":"int64","type":"integer"},"projectId":{"description":"ProjectID is the IAM project the app lives under, and it is that project's\nNAME — the (org,name) key IAM identifies it by, which is also what the\n`:project` path segment carries. There is no platform-minted project id.","type":"string"},"replicas":{"description":"Replicas is how many copies the CR declares. It is CLAMPED to the\ndeployment's ceiling rather than refused, so it can be below what was asked.","format":"int64","type":"integer"},"repo":{"$ref":"#/components/schemas/platform.gitSource","description":"Repo is the git origin a source `git` app builds from, and the repo+branch a\nlanded push has to match to build it."},"secretSync":{"description":"SecretSync is how far the app's secret env has got into the cluster:\n\"\"|pending|syncing|ready|failed (secrets.go). It is best-effort and never\nfails a deploy, so `pending` is ordinary right after one.","type":"string"},"secretSyncDetail":{"description":"SecretSyncDetail is the honest reason when the sync is not ready — a missing\nCRD, an RBAC grant, a per-tenant credential. Empty when it is.","type":"string"},"slug":{"description":"Slug is the app's identity in the cluster: the operator CR's name, the first\nlabel of its default host, and the `:app` path segment. Unique per project.","type":"string"},"source":{"description":"Source is what the app deploys FROM: `git`, which builds Repo, or `image`,\nwhich runs Image as it is. It decides whether a deploy builds at all.","type":"string"},"status":{"description":"Status is the lifecycle THIS store records: draft (created, nothing in the\ncluster yet), building, deploying, live, stopped or error. What the cluster\nitself says is Phase and Health.","type":"string"},"storageGb":{"description":"StorageGB is the persistent volume size in GiB. Absent means stateless —\nno volume at all — and it is clamped like Replicas.","format":"int64","type":"integer"},"updatedAt":{"description":"UpdatedAt is when it last changed, unix seconds. Every lifecycle transition\nmoves it, so it tracks deploys as well as edits.","format":"int64","type":"integer"}},"type":"object"},"platform.binarySpec":{"properties":{"image":{"description":"Image is the toolchain image the recipe runs in, a Go bookworm image by\ndefault. It is the one field the GitHub lane ignores: there the runner IS\nthe toolchain, and a cluster has to be told what a runner already is.","type":"string"},"ldflags":{"description":"Ldflags are the Go linker flags, `-s -w` when the recipe names none, on one\nline. Go lane only.","type":"string"},"main":{"description":"Main is the Go package to build, repo-relative (`.` or `./cmd/x`), and it\nselects the GO LANE. Defaults to `.` when neither lane is named; declaring\nit together with `run` is refused.","type":"string"},"name":{"description":"Name is the artifact's base name: the prefix of every file published for\nthis entry, and the name a host later asks for. It must match\n`^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$`, which is what makes it safe as both a\nfilename and a URL path segment.","type":"string"},"out":{"description":"Out is the glob of files `run` produced, relative to the repo root; matching\nnothing FAILS the build rather than publishing an empty entry. It expands\nunquoted, so it is bounded to path and glob characters. The Go lane names\nits own files and ignores this.","type":"string"},"platforms":{"description":"Platforms are the `\u003cos\u003e/\u003carch\u003e` pairs the Go lane cross-compiles, [linux/amd64]\nby default. Each one publishes as `\u003cname\u003e-\u003cos\u003e-\u003carch\u003e`, which is the shape a\nhost resolves a binary BY — so the list is what a caller can ask for later.","items":{"type":"string"},"type":"array"},"run":{"description":"Run is any other toolchain's build command, run by `sh -c` in this entry's\nimage, and it selects the OTHER LANE. Arbitrary shell is the point — it is\nthe same trust as a Dockerfile RUN — which is why it executes with no\nobject-store credential and no service-account token. It requires `out`.","type":"string"}},"type":"object"},"platform.buildBoard":{"properties":{"builds":{"description":"Builds are the org's real BuildKit build records, newest first.","items":{"$ref":"#/components/schemas/platform.buildRow"},"type":"array"}},"type":"object"},"platform.buildRow":{"properties":{"commit":{"description":"Commit is the short git ref the build pinned.","type":"string"},"duration":{"description":"Duration is the wall time of a TERMINAL build; empty while it still runs.","type":"string"},"id":{"description":"ID is the build record's id.","type":"string"},"repo":{"description":"Repo is the repo the build built, or the image it produced.","type":"string"},"startedAt":{"description":"StartedAt is when the build was recorded, RFC3339 UTC.","type":"string"},"status":{"description":"Status is the build's real state: queued, building, succeeded or failed.","type":"string"}},"type":"object"},"platform.cdResp":{"properties":{"applications":{"items":{"$ref":"#/components/schemas/platform.CDApp"},"type":"array"}},"type":"object"},"platform.createAppReq":{"properties":{"buildType":{"description":"BuildType is `pack` — the zero-config default that detects any project —\nor `dockerfile`, the explicit escape hatch. An image app never builds.","type":"string"},"description":{"description":"Description is free text about what the application is.","type":"string"},"dockerfile":{"description":"Dockerfile is the path to build from, for buildType `dockerfile`.","type":"string"},"domains":{"description":"Domains are extra ingress hosts. The canonical default host is always\nattached; a bare custom host is refused here and must go through\nadd-domain → verify first.","items":{"type":"string"},"type":"array"},"env":{"description":"Env is the application's environment. Keys must match\n`^[A-Za-z_][A-Za-z0-9_]*$`; a variable marked `secret: true` is sealed into\nKMS and its plaintext is never written to the database.","items":{"$ref":"#/components/schemas/platform.EnvVarJSON"},"type":"array"},"environment":{"description":"Environment is the deploy target this app names (\"production\" by default).","type":"string"},"image":{"$ref":"#/components/schemas/platform.imageOrigin","description":"Image is the container image to run, for source `image`."},"name":{"description":"Name is the application's display name. Required; the slug is derived from\nit when none is given.","type":"string"},"port":{"description":"Port is the container port the app listens on.","format":"int64","type":"integer"},"project":{"description":"Project is the project to create the application under, from the path.","type":"string"},"replicas":{"description":"Replicas is how many copies to run; clamped to the deployment's limit\nrather than refused.","format":"int64","type":"integer"},"repo":{"$ref":"#/components/schemas/platform.gitOrigin","description":"Repo is the git source to build from, for source `git`."},"slug":{"description":"Slug is the app's identity in the cluster — its CR name and part of its\nhost. Given or derived from Name, it must match\n`^[a-z0-9]([a-z0-9-]{0,38}[a-z0-9])?$`, and one already used in this\nproject is 409.","type":"string"},"source":{"description":"Source is `git`, which requires repo.url, or `image`, which requires\nimage.repository. Anything else is 400.","type":"string"},"storageGb":{"description":"StorageGB is the persistent volume size in GiB; absent means stateless.\nClamped to the deployment's limit rather than refused.","format":"int64","type":"integer"}},"type":"object"},"platform.declRef":{"properties":{"name":{"description":"Name is the declaration's name, the file's basename.","type":"string"},"org":{"description":"Org is the values directory the declaration lives in.","type":"string"}},"type":"object"},"platform.declareEnv":{"properties":{"name":{"type":"string"},"public":{"description":"Public marks a value that may be WRITTEN INTO GIT. Absent, it is false,\nand the value is sealed into KMS and referenced.\n\n★ THE DEFAULT IS SECRET, AND THE POLARITY IS THE WHOLE DESIGN. This lane's\noutput is a commit in a repository replicated to every clone, so a value\nwritten there stays there. Sealing by default means the worst outcome of a\nwrong guess is a config value an operator reads back from KMS rather than\nfrom git, and nothing sensitive ever depends on recognising its shape.\n\nIt is also the only rule that needs no list: a password, a kubeconfig or an\nMFA seed is sealed whatever it looks like, because only an explicit public\nmark writes a value into git.","type":"boolean"},"value":{"type":"string"}},"type":"object"},"platform.declared":{"properties":{"application":{"description":"Application is the CD Application name the generator mints from the path —\nthe directory joined to the file name, less any words the two share\n(applicationName). It is how cd.hanzo.ai names the app.","type":"string"},"automated":{"description":"Automated is cd.automated: false means the Application reports drift and\nNOTHING moves. It is off by default for a new file on purpose.","type":"boolean"},"cd":{"$ref":"#/components/schemas/platform.CDApp"},"component":{"description":"Component is the app's role within its project (`component`), \"\" when unnamed.","type":"string"},"digest":{"description":"image.digest — wins over tag","type":"string"},"env":{"description":"Env is the declared container environment, as the chart's list of\n{name,value}. It is read back so a re-declare of an identical body is a\nno-op rather than a refusal — idempotency is what makes a retry safe.","items":{"$ref":"#/components/schemas/platform.declareEnv"},"type":"array"},"hosts":{"description":"ingress.hosts, both shapes flattened","items":{"type":"string"},"type":"array"},"name":{"description":"the Helm release name — the file's basename","type":"string"},"org":{"description":"Org is the owner. It is ALSO the values directory and the destination\nnamespace, because those are one value under one name — see the header.","type":"string"},"partOf":{"description":"PartOf is the platform project this app belongs to: the values file's own\n`partOf` key, which the chart also stamps on every object it renders as\napp.kubernetes.io/part-of. It is the ONE declaration of membership — there is\nno project table — and \"\" means the file names none.","type":"string"},"path":{"description":"Path is the file, relative to the repository root.","type":"string"},"project":{"description":"Project is the AppProject the sync is admitted under, derived from the\ndirectory exactly as the ApplicationSet derives it. It differs from Org\nfor a reserved directory, which syncs under the platform fence.","type":"string"},"replicas":{"format":"int64","type":"integer"},"repository":{"description":"image.repository","type":"string"},"secrets":{"description":"Secrets are the KMS coordinates the app reads — kmsSecrets and secrets.paths\n— as paths and key names. A values file never carries a secret value, so\nneither does this.","items":{"$ref":"#/components/schemas/platform.SecretRef"},"type":"array"},"tag":{"description":"image.tag","type":"string"}},"type":"object"},"platform.declaredResp":{"properties":{"apps":{"items":{"$ref":"#/components/schemas/platform.declared"},"type":"array"},"cdUnavailable":{"$ref":"#/components/schemas/platform.unreadable"},"org":{"description":"Org is the directory read — the caller's own, or another when a SuperAdmin\nasked to act as it.","type":"string"},"unreadable":{"description":"Unreadable are the org's values files that do not parse, so they are not\namong apps. Absent when every file parsed.","items":{"$ref":"#/components/schemas/platform.unreadableFile"},"type":"array"}},"type":"object"},"platform.deployLogs":{"properties":{"deploymentId":{"description":"DeploymentID is the deployment these logs belong to.","type":"string"},"logs":{"description":"Logs is the recorded status timeline followed by the streamed pod output,\nnewline-separated.","type":"string"},"source":{"description":"Source says which pod the log body carries — `build`, `app`, or `none` when\nneither pod was reachable — so a console can label the pane honestly.","type":"string"}},"type":"object"},"platform.deployReq":{"properties":{"app":{"description":"App is the application's slug, from the path.","type":"string"},"commit":{"description":"Commit is the git commit or ref to build, for a git-source app. Defaults to\nthe app's branch.","type":"string"},"project":{"description":"Project is the project the application lives under, from the path.","type":"string"},"tag":{"description":"Tag is the image tag to deploy, for an image-source app. Defaults to the\napp's tag, then `latest`.","type":"string"}},"type":"object"},"platform.deploymentView":{"properties":{"applicationId":{"description":"ApplicationID is the app this deployed — the app's `id`, not its slug.","type":"string"},"buildId":{"description":"BuildID is the build record behind a git deploy, whose logs and status live\nat /v1/platform/builds. Empty for an image deploy.","type":"string"},"commit":{"description":"Commit is the git ref this built — the commit a deploy or a push named,\nelse the app's branch. Empty for an image deploy, which builds nothing.","type":"string"},"createdAt":{"description":"CreatedAt is when the attempt was recorded, unix seconds.","format":"int64","type":"integer"},"id":{"description":"ID is the deployment's id (`dep_…`), minted when the attempt is recorded.\nThe app's currentDeploymentId points at one of these.","type":"string"},"image":{"description":"Image is the full `repo:tag` this deployment put in the CR. For a git deploy\nit is the ref the in-cluster build pushes to, known before the build runs.","type":"string"},"message":{"description":"Message is why this attempt is not live: the failure, or the note that a\nnewer deployment went live before this build finished. Empty while it is fine.","type":"string"},"org":{"description":"Org is the tenant the deployment belongs to, from the validated identity.","type":"string"},"source":{"description":"Source is which lane produced it: `git` (built from the repo) or `image`\n(an already-built ref deployed as-is, including promote and rollback).","type":"string"},"status":{"description":"Status is where the attempt got to: `building` while its image is being\nbuilt, `deploying` once its CR reached the cluster — which is the terminal\nsuccess state, the app's own status is what turns `live` — `error` with the\nreason in Message, or `superseded` when a newer version went live first.","type":"string"},"updatedAt":{"description":"UpdatedAt is its last transition, unix seconds — so for a terminal\ndeployment it is when it reached that state.","format":"int64","type":"integer"},"version":{"description":"Version counts this app's deployments, from 1 and monotonically. It is what\nORDERS them: a deploy only goes live if no higher version already is, so a\nbuild that finishes late is superseded instead of overwriting a newer one.","format":"int64","type":"integer"}},"type":"object"},"platform.domainView":{"properties":{"createdAt":{"description":"CreatedAt is the unix second the custom claim was made.","format":"int64","type":"integer"},"detail":{"description":"Detail says why a claim is still pending, in the resolver's own words.","type":"string"},"host":{"description":"Host is the hostname itself.","type":"string"},"kind":{"description":"Kind is `default` (the app's own name) or `custom` — how the org came to\nown it.","type":"string"},"primary":{"description":"Primary marks the app's permanent default host.","type":"boolean"},"records":{"description":"Records are the DNS records to publish while a custom claim is pending.","items":{"$ref":"#/components/schemas/platform.Record"},"type":"array"},"status":{"description":"Status is `live`, `provisioning`, `pending_deploy` or `pending`, derived\nfrom the operator CR and never fabricated.","type":"string"},"url":{"description":"URL is the host as an HTTPS address.","type":"string"},"verified":{"description":"Verified is whether ownership is settled — always true for a host the org\nstructurally owns.","type":"boolean"}},"type":"object"},"platform.driftBoard":{"properties":{"apps":{"description":"Apps are the service rows, ordered by org, then app, then env.","items":{"$ref":"#/components/schemas/platform.AppView"},"type":"array"},"summary":{"$ref":"#/components/schemas/platform.fleetSummary","description":"Summary counts the board by drift severity."}},"type":"object"},"platform.driftTally":{"properties":{"ok":{"description":"OK is how many rows run what they declare.","format":"int64","type":"integer"},"red":{"description":"Red is how many have drifted badly.","format":"int64","type":"integer"},"yellow":{"description":"Yellow is how many have drifted within tolerance.","format":"int64","type":"integer"}},"type":"object"},"platform.environmentBoard":{"properties":{"environments":{"description":"Environments are the org's deploy targets, in first-seen order.","items":{"$ref":"#/components/schemas/platform.environmentRow"},"type":"array"}},"type":"object"},"platform.environmentRow":{"properties":{"id":{"description":"ID is the environment's name, which is also its identity — an environment\nis derived from the apps that target it, so it has no id of its own.","type":"string"},"name":{"description":"Name is the environment's name as an app declared it.","type":"string"},"services":{"description":"Services are the apps that target this environment, by name.","items":{"type":"string"},"type":"array"},"status":{"description":"Status rolls up the real states of this environment's apps: degraded,\nactive, idle or empty.","type":"string"},"type":{"description":"Type buckets the name for display: production, staging, development or\ncustom.","type":"string"},"updatedAt":{"description":"UpdatedAt is when any of them last changed, RFC3339 UTC; empty when unset.","type":"string"}},"type":"object"},"platform.fleetSummary":{"properties":{"byDrift":{"$ref":"#/components/schemas/platform.driftTally","description":"ByDrift counts those rows green, yellow and red."},"total":{"description":"Total is how many rows the board returned, after filtering.","format":"int64","type":"integer"}},"type":"object"},"platform.gitOrigin":{"properties":{"branch":{"description":"Branch is the branch to build; defaults to `main` for a git source.","type":"string"},"url":{"description":"URL is the repository clone URL. Required for source `git`, and validated\nagainst the same allowlist the privileged build enforces.","type":"string"}},"type":"object"},"platform.gitSource":{"properties":{"branch":{"description":"Branch is the branch a push-to-deploy build tracks, `main` when the create\nnamed none — a push to any other branch, and every tag push, builds nothing\nhere. A deploy may name a commit instead, for that deploy alone.","type":"string"},"provider":{"description":"Provider is derived from the URL — github, gitlab, bitbucket, or `git` for\nanything else. It is a label for display; no behaviour keys on it.","type":"string"},"url":{"description":"URL is the clone URL a git app builds from, stored as sent once the build\npath's allowlist accepted it (validateRepoURL). It is also what a landed\npush is MATCHED against, so a push to any other repo never builds this app.","type":"string"}},"type":"object"},"platform.healthTally":{"properties":{"degraded":{"description":"Degraded is how many CD reports Degraded.","format":"int64","type":"integer"},"healthy":{"description":"Healthy is how many CD reports Healthy.","format":"int64","type":"integer"},"missing":{"description":"Missing is how many have no live objects at all.","format":"int64","type":"integer"},"progressing":{"description":"Progressing is how many are still rolling out.","format":"int64","type":"integer"},"unknown":{"description":"Unknown is every other verdict, and apps CD could not be asked about.","format":"int64","type":"integer"}},"type":"object"},"platform.imageOrigin":{"properties":{"repository":{"description":"Repository is the image repository. Required for source `image`.","type":"string"},"tag":{"description":"Tag is the image tag to deploy; `latest` when omitted.","type":"string"}},"type":"object"},"platform.imageView":{"properties":{"repository":{"description":"Repository is the image path without a tag (ghcr.io/acme/api). Required for\nsource `image`, which runs it as-is. A git app's built image is NOT this: the\nbuild pushes to a path derived from the org and slug, and the deployment\nrecords that full ref.","type":"string"},"tag":{"description":"Tag is the tag to run: what the create declared, then RE-STAMPED on every\ntransition to live with the tag that actually went live. So after a deploy\nit names what is running, not what was asked for.","type":"string"}},"type":"object"},"platform.pipelineBoard":{"properties":{"pipelines":{"description":"Pipelines are one per application in the caller's org.","items":{"$ref":"#/components/schemas/platform.pipelineRow"},"type":"array"}},"type":"object"},"platform.pipelineRow":{"properties":{"duration":{"description":"Duration is how long that run took; empty while it is still queued or\nbuilding.","type":"string"},"id":{"description":"ID is the application id — one pipeline is one application.","type":"string"},"lastRun":{"description":"LastRun is when the most recent deployment started, RFC3339 UTC.","type":"string"},"name":{"description":"Name is the application's name.","type":"string"},"repo":{"description":"Repo is the git repo or image the pipeline builds from.","type":"string"},"status":{"description":"Status is the latest deployment's status, or the app's when it has none.","type":"string"}},"type":"object"},"platform.previewReq":{"properties":{"app":{"description":"App is the parent application's slug, from the path.","type":"string"},"branch":{"description":"Branch is the branch to preview; defaults to the parent app's branch.","type":"string"},"image":{"description":"Image is the already-built image ref to deploy. Required — a preview never\nbuilds.","type":"string"},"project":{"description":"Project is the project the parent application lives under, from the path.","type":"string"}},"type":"object"},"platform.previewView":{"properties":{"app":{"description":"App is the preview application's own slug, `\u003capp\u003e-\u003cbranch\u003e`.","type":"string"},"branch":{"description":"Branch is the branch this preview maps.","type":"string"},"deployment":{"$ref":"#/components/schemas/platform.deploymentView","description":"Deployment is the deployment the preview recorded."},"url":{"description":"URL is the preview's live HTTPS address.","type":"string"}},"type":"object"},"platform.projectBoard":{"properties":{"cdUnavailable":{"$ref":"#/components/schemas/platform.unreadable","description":"CD says why the reconciliation columns are missing, when they are."},"clusterUnavailable":{"$ref":"#/components/schemas/platform.unreadable","description":"Cluster says why the running columns are missing, when they are."},"projects":{"description":"Projects are sorted by owner, then name.","items":{"$ref":"#/components/schemas/platform.Project"},"type":"array"},"unassigned":{"description":"Unassigned are declarations that name no project. Every declaration names\none, so a non-empty list is drift in git itself.","items":{"$ref":"#/components/schemas/platform.declRef"},"type":"array"},"unreadable":{"description":"Unreadable are the values files in the caller's scope that do not parse, so\ntheir projects are unknown. Absent when every file parsed.","items":{"$ref":"#/components/schemas/platform.unreadableFile"},"type":"array"}},"type":"object"},"platform.projectCreate":{"properties":{"apps":{"description":"Apps are the declarations it starts with, each by values directory (`org`,\ndefaulting to the caller's own) and name. At least one: a project is the apps\nthat name it.","items":{"$ref":"#/components/schemas/platform.declRef"},"type":"array"},"mode":{"description":"Mode is `branch` (the default: a review branch, nothing deploys) or `commit`\n(main).","type":"string"},"name":{"description":"Name is the project, a DNS-1123 label; it becomes each app's `partOf`.","type":"string"},"org":{"description":"Org names the project's owner, defaulting to the caller's own scope; naming\nanother is an act-as only a SuperAdmin has.","type":"string"}},"type":"object"},"platform.projectRename":{"properties":{"mode":{"description":"Mode is `branch` (the default) or `commit`.","type":"string"},"name":{"description":"Name is its new name, which no app may already name.","type":"string"},"org":{"description":"Org names the project's owner, defaulting to the caller's own scope.","type":"string"},"project":{"description":"Project is the project to rename, from the path.","type":"string"}},"type":"object"},"platform.projectView":{"properties":{"apps":{"description":"Apps is how many declarations name the project.","format":"int64","type":"integer"},"cdUnavailable":{"$ref":"#/components/schemas/platform.unreadable","description":"CD says why the reconciliation columns are missing, when they are."},"clusterUnavailable":{"$ref":"#/components/schemas/platform.unreadable","description":"Cluster says why the running columns are missing, when they are."},"drift":{"$ref":"#/components/schemas/platform.driftTally","description":"Drift counts its apps by drift severity."},"health":{"$ref":"#/components/schemas/platform.healthTally","description":"Health counts its apps by CD's health verdict."},"members":{"description":"Members are the project's apps, sorted by namespace then name.","items":{"$ref":"#/components/schemas/platform.ProjectApp"},"type":"array"},"name":{"description":"Name is the project, as the values files spell it in `partOf`.","type":"string"},"namespaces":{"description":"Namespaces are the namespaces its apps deploy into, sorted.","items":{"type":"string"},"type":"array"},"org":{"description":"Org is the organization that owns the project. Absent for the platform's own\nprojects, whose apps live in the platform's directories.","type":"string"},"sync":{"$ref":"#/components/schemas/platform.syncTally","description":"Sync counts its apps by CD's sync verdict."},"unreadable":{"description":"Unreadable are the values files in the owner's scope that do not parse, any\nof which may name this project. Absent when every file parsed.","items":{"$ref":"#/components/schemas/platform.unreadableFile"},"type":"array"}},"type":"object"},"platform.projectWrite":{"properties":{"commit":{"description":"Commit is the sha the change created, \"\" when nothing had to move.","type":"string"},"live":{"description":"Live says whether the generator will see it: true only on main.","type":"boolean"},"mode":{"description":"Mode is branch (a review; nothing deploys) or commit (main).","type":"string"},"moved":{"description":"Moved are the declarations whose partOf moved, and from what.","items":{"$ref":"#/components/schemas/platform.relabel"},"type":"array"},"project":{"description":"Project is the project the change leaves the moved apps in.","type":"string"},"ref":{"description":"Ref is the branch the change was pushed to, main for a commit.","type":"string"},"review":{"description":"Review is where to open the pull request for a branch.","type":"string"}},"type":"object"},"platform.promoteReq":{"properties":{"app":{"description":"App is the application's slug, from the path.","type":"string"},"deploymentId":{"description":"DeploymentID promotes that deployment's exact built image. One of this and\nTag is required.","type":"string"},"project":{"description":"Project is the project the application lives under, from the path.","type":"string"},"tag":{"description":"Tag promotes an image tag, resolved the same way a deploy resolves one.","type":"string"}},"type":"object"},"platform.readiness":{"properties":{"crd":{"description":"CRD is whether the operator App CRD was found, and is absent when no\ncluster client resolved and the question could not be asked.","type":"boolean"},"error":{"description":"Error is the real reason the plane is degraded; absent when it is not.","type":"string"},"k8s":{"description":"K8s is whether a cluster client resolved at all. False means no kubeconfig.","type":"boolean"},"service":{"description":"Service is always \"platform\" — which control plane answered.","type":"string"},"status":{"description":"Status is \"ok\" when this plane can deploy, \"degraded\" when it cannot.","type":"string"}},"type":"object"},"platform.relabel":{"properties":{"from":{"type":"string"},"name":{"type":"string"},"org":{"type":"string"},"to":{"type":"string"}},"type":"object"},"platform.releaseBoard":{"properties":{"releases":{"description":"Releases are the deployments that genuinely reached the cluster.","items":{"$ref":"#/components/schemas/platform.releaseRow"},"type":"array"}},"type":"object"},"platform.releaseRow":{"properties":{"environment":{"description":"Environment is the deploy target the application names.","type":"string"},"id":{"description":"ID is the deployment's id — a release IS a deployment that reached the\ncluster.","type":"string"},"name":{"description":"Name is the application the release belongs to.","type":"string"},"releasedAt":{"description":"ReleasedAt is when the deployment last changed, RFC3339 UTC.","type":"string"},"status":{"description":"Status is deploying or live — the two states that mean released.","type":"string"},"version":{"description":"Version is the released image tag, or v\u003cn\u003e when the image carries none.","type":"string"}},"type":"object"},"platform.rollbackReq":{"properties":{"app":{"description":"App is the application's slug, from the path.","type":"string"},"deploymentId":{"description":"DeploymentID is the deployment to redeploy. Omit it to return to the\nprevious release.","type":"string"},"project":{"description":"Project is the project the application lives under, from the path.","type":"string"}},"type":"object"},"platform.runReq":{"properties":{"env":{"description":"Env is the run's environment. Keys must match `^[A-Za-z_][A-Za-z0-9_]*$`;\na variable marked `secret: true` is sealed into KMS.","items":{"$ref":"#/components/schemas/platform.EnvVarJSON"},"type":"array"},"gpu":{"description":"GPU is how many GPUs the run asks for; a negative value is 400.","format":"int64","type":"integer"},"image":{"description":"Image is the container image to run. Required.","type":"string"},"maxScale":{"description":"MaxScale above the floor declares an autoscaling ceiling; 0 means no\nautoscaler at all — a fixed run at the floor.","format":"int64","type":"integer"},"minScale":{"description":"MinScale is the replica floor, clamped to the deployment's limit.","format":"int64","type":"integer"},"name":{"description":"Name is the run's name, and the slug is derived from it. Required, and it\nmust resolve to `^[a-z0-9]([a-z0-9-]{0,38}[a-z0-9])?$`. Re-running the same\nname updates that run in place.","type":"string"},"port":{"description":"Port is the container port the run listens on.","format":"int64","type":"integer"},"runtime":{"description":"Runtime is accepted for the client contract and echoed nowhere: the image\nIS the runtime unit.","type":"string"},"shape":{"description":"Shape is a compute size label, echoed back; sizing is the operator's\ndefault. Defaults to \"auto\".","type":"string"}},"type":"object"},"platform.runView":{"properties":{"id":{"description":"ID is the application id the run created or converged.","type":"string"},"name":{"description":"Name is the run's name, as stored.","type":"string"},"shape":{"description":"Shape is the compute size label the request asked for, or \"auto\".","type":"string"},"status":{"description":"Status is the application's state — `deploying` on a fresh accept.","type":"string"},"url":{"description":"URL is the run's live HTTPS address.","type":"string"}},"type":"object"},"platform.runnerBuildReq":{"properties":{"arch":{"description":"Arch is the target architecture for the artifact lane.","type":"string"},"args":{"additionalProperties":{"type":"string"},"description":"Args are --build-arg values. They are what lets several images off ONE\nDockerfile mean different things — the sandbox classes are three entries\ndiffering only by STAGE. Validated at the k8s choke point, with VERSION and\nREVISION taking precedence: those are receipts the builder derives from the\ntag and the commit, and a caller that could overwrite them could make an\nimage lie about which commit it is.","type":"object"},"binaries":{"description":"Binaries selects the ARTIFACT lane (artifact.go): build what the repo's\nhanzo.yml `binaries:` block declares — a Go binary, an npm tarball, a Rust\nbinary — and publish it to hanzoai/s3 instead of pushing an image. It is the\nsame recipe hanzoai/ci reads, sent verbatim, so `image` is meaningless here\nand must be absent.","items":{"$ref":"#/components/schemas/platform.binarySpec"},"type":"array"},"branch":{"description":"Branch is the branch to build when no SHA or Ref is given.","type":"string"},"bucket":{"description":"Bucket mirrors hanzo.yml's `bucket:` — where the artifact lane publishes.","type":"string"},"context":{"description":"Context is the build context path within the repo.","type":"string"},"dockerTarget":{"description":"DockerTarget is the multi-stage build target to stop at.","type":"string"},"dockerfile":{"description":"Dockerfile is the path to build from; empty uses the zero-config frontend.","type":"string"},"image":{"description":"Image is the output image ref to push. Required on the image lane, and it\nmust target a registry namespace the caller's org owns.","type":"string"},"os":{"description":"OS is the target operating system for the artifact lane.","type":"string"},"platforms":{"description":"Platforms are the `\u003cos\u003e/\u003carch\u003e` pairs the image is built for. EMPTY MEANS\nEVERY ARCHITECTURE THE FLEET HAS — each built on a node of that\narchitecture, joined by ONE manifest index, so a single tag serves both.\nName one to build only that one.","items":{"type":"string"},"type":"array"},"ref":{"description":"Ref is the git ref to build when no SHA is given.","type":"string"},"repo":{"description":"Repo is the repository clone URL to build. Required on the image lane.","type":"string"},"sha":{"description":"SHA is the commit to pin; it wins over Ref and Branch.","type":"string"},"tag":{"description":"Tag is the publish path segment, so both entry points write ONE index at ONE\nURL. It defaults to the pinned ref, and must be named explicitly for a\nbranch.","type":"string"},"tags":{"description":"Tags are more tags of Image's own repository, pushed onto the same manifest\nby the same export, so every one names the digest Image does — by\nconstruction, not by a second push agreeing with the first. Bare tags\n(`v1.2.3`, `latest`), at most 8, and only beside a tag Image: a digest names\nan image that already exists. Duplicates and Image's own tag are dropped;\nthe answer's `tags` lists what will be written.","items":{"type":"string"},"type":"array"}},"type":"object"},"platform.runnerBuildResp":{"properties":{"buildJobId":{"description":"BuildJobID is the queued build's id, and what its progress is read by.","type":"string"},"image":{"description":"Image is the ref the image lane will push.","type":"string"},"index":{"description":"Index is the binaries.json URL the artifact lane will publish.","type":"string"},"platforms":{"description":"Platforms are the architectures the image lane will publish, echoed back.","items":{"type":"string"},"type":"array"},"reason":{"description":"Reason is why a failed build failed, as the cluster said it: the solve's\nerror line (`error: failed to solve: ...`), a container waiting on what it\ncannot have, or the deadline.","type":"string"},"runnerPool":{"description":"RunnerPool is the runner class the build was placed on.","type":"string"},"status":{"description":"Status is `queued` until the build finishes, then `succeeded` or `failed`.\nThe POST answers `queued`: a build that is accepted has not finished.","type":"string"},"tags":{"description":"Tags are the extra tags the image lane will write beside Image, onto the\nsame manifest: the request's, deduplicated. This is the promise — a tag\nabsent here will not be written.","items":{"type":"string"},"type":"array"},"target":{"description":"Target is the multi-stage build target, echoed back.","type":"string"}},"type":"object"},"platform.setEnvReq":{"properties":{"app":{"description":"App is the application's slug, from the path.","type":"string"},"env":{"description":"Env is the app's whole environment set, REPLACING what it had. Keys must\nmatch `^[A-Za-z_][A-Za-z0-9_]*$`; a variable marked `secret: true` is\nsealed into KMS and blanked in the database.","items":{"$ref":"#/components/schemas/platform.EnvVarJSON"},"type":"array"},"project":{"description":"Project is the project the application lives under, from the path.","type":"string"}},"type":"object"},"platform.syncTally":{"properties":{"outOfSync":{"description":"OutOfSync is how many differ from git until someone syncs them.","format":"int64","type":"integer"},"synced":{"description":"Synced is how many run what git declares.","format":"int64","type":"integer"},"unknown":{"description":"Unknown is how many CD holds no verdict for, or could not be read.","format":"int64","type":"integer"}},"type":"object"},"platform.unreadable":{"properties":{"reason":{"description":"Reason is why: the cause for a SuperAdmin, and which plane for anyone else.","type":"string"}},"type":"object"},"platform.unreadableFile":{"properties":{"path":{"description":"Path is the values file, relative to the repository root.","type":"string"},"reason":{"description":"Reason is why it could not be read. A SuperAdmin reads the parser's own\nwords; anyone else reads that it does not parse, because those words can\nname the platform's cluster overlay.","type":"string"}},"type":"object"},"pref.prefsView":{"properties":{"prefs":{"description":"Prefs is the caller's preference document: an opaque JSON object whose keys\nthe surfaces own, returned verbatim. `{}` when nothing has been saved."},"updatedAt":{"description":"UpdatedAt is when the document was last written, unix seconds. Absent when\nnothing has been saved.","format":"int64","type":"integer"}},"type":"object"},"pricing.Card":{"properties":{"components":{"description":"Components are the four things a bill is made of.","items":{"$ref":"#/components/schemas/pricing.Component"},"type":"array"},"rates":{"description":"Rates are the priced lines, each in micro-USD per its own unit.","items":{"$ref":"#/components/schemas/pricing.Rate"},"type":"array"},"unit":{"description":"Unit is the unit every amount on this card is stated in.","type":"string"},"windows":{"description":"Speeds are the completion speeds, dearest first.","items":{"$ref":"#/components/schemas/pricing.Speed"},"type":"array"}},"type":"object"},"pricing.Component":{"properties":{"basis":{"description":"Basis is what it is metered by, in the fewest words that are true.","type":"string"},"name":{"description":"Name is the component's name on the spend breakdown.","type":"string"},"note":{"description":"Note is what the component means, in one sentence.","type":"string"},"quoted":{"description":"Quoted says whether a call is priced BEFORE it runs. A quoted component can\nrefuse a call that would breach a budget; a measured one is booked from what\nit used and is bounded by the headroom under the per-task cap instead.","type":"boolean"},"tiers":{"description":"Tiers are the disjoint tiers this component meters in, where it has them.","items":{"type":"string"},"type":"array"},"title":{"description":"Title is how it reads on a price list.","type":"string"}},"type":"object"},"pricing.Rate":{"properties":{"component":{"description":"Component is which of the four this line bills under.","type":"string"},"name":{"description":"Name addresses the rate.","type":"string"},"note":{"description":"Note is what the line covers.","type":"string"},"per":{"description":"Per names one unit, so a reader never has to guess what the number is per.","type":"string"},"rate_micro_usd":{"description":"Micros is the price of ONE unit, in micro-USD. It is the number the ledger\nbooks, resolved through the same authority the metering path reads.","format":"int64","type":"integer"},"title":{"description":"Title is how the line reads on a price list.","type":"string"}},"type":"object"},"pricing.Speed":{"properties":{"name":{"description":"Name is what a request asks for.","type":"string"},"note":{"description":"Note is what asking for this window buys.","type":"string"},"rank":{"description":"Rank orders the windows by price, 1 being the dearest.","format":"int64","type":"integer"}},"type":"object"},"pricing.enablementBoard":{"properties":{"items":{"description":"Items is every managed item, each resolved for the caller.","items":{"$ref":"#/components/schemas/pricing.userEnablementItem"},"type":"array"},"org":{"description":"Org is the org this view was resolved for; empty for a caller with no\nvalidated principal, who sees only the generally-available items.","type":"string"}},"type":"object"},"pricing.pricingHealth":{"properties":{"service":{"description":"Service names the subsystem that answered.","type":"string"},"status":{"description":"Status is \"ok\" whenever this subsystem is mounted.","type":"string"}},"type":"object"},"pricing.pricingModelList":{"properties":{"models":{"description":"Models are the catalog entries visible to the caller, each an opaque\nobject exactly as the pricing source emits it, with any admin override\nmerged on top. An admin additionally sees hidden entries, each annotated\nunder \"_overlay\".","items":{"additionalProperties":{},"type":"object"},"type":"array"},"total":{"description":"Total is how many models this answer carries — recounted over the visible\nset, not the catalog's own total.","format":"int64","type":"integer"},"updated":{"description":"Updated is when the catalog was last refreshed, as the pricing source\nrecorded it."}},"type":"object"},"pricing.pricingPlanList":{"properties":{"plans":{"description":"Plans are the plans in this section, each an opaque object exactly as the\npricing source emits it — typically id, name, description, price and a\nfeature list.","items":{"additionalProperties":{},"type":"object"},"type":"array"}},"type":"object"},"pricing.pricingPresetList":{"properties":{"presets":{"description":"Presets are the named compute sizes, each an opaque object exactly as the\npricing source emits it — typically id, name, provider slug, vCPU, memory,\ndisk and price.","items":{"additionalProperties":{},"type":"object"},"type":"array"}},"type":"object"},"pricing.pricingProviderList":{"properties":{"providers":{"additionalProperties":{},"description":"Providers maps a provider name to its opaque info object. A provider\nhidden for the caller's org is absent entirely.","type":"object"},"updated":{"description":"Updated is when the catalog was last refreshed, as the pricing source\nrecorded it."}},"type":"object"},"pricing.pricingRegionList":{"properties":{"regions":{"description":"Regions are the regions cloud instances can be placed in, each an opaque\nobject exactly as the pricing source emits it — typically id, name and\nlocation.","items":{"additionalProperties":{},"type":"object"},"type":"array"}},"type":"object"},"pricing.pricingTierList":{"properties":{"tiers":{"description":"Tiers are the rentable GPU configurations, each an opaque object exactly\nas the pricing source emits it — typically id, name, accelerator count and\nmodel, VRAM, vCPU, memory and hourly price.","items":{"additionalProperties":{},"type":"object"},"type":"array"}},"type":"object"},"pricing.pricingToolList":{"properties":{"tools":{"description":"Tools are the metered tools, each an opaque object exactly as the pricing\nsource emits it — typically name, billing unit and price.","items":{"additionalProperties":{},"type":"object"},"type":"array"}},"type":"object"},"pricing.userEnablementItem":{"properties":{"effective":{"description":"Effective is whether the caller may use the item right now, which is the\nfield to branch on: true for any ga item, for a beta item while the\nplatform's `beta` switch is on for the caller, and never for an off one.","type":"boolean"},"id":{"description":"ID is the item within that namespace — a model id, a provider name, or a\nfeature key.","type":"string"},"kind":{"description":"Kind is the namespace the id lives in: \"model\", \"provider\" or \"feature\".","type":"string"},"state":{"description":"State is the item's GLOBAL availability — \"off\", \"beta\" or \"ga\" — which is\nthe operator's setting and not this caller's answer. Effective is that.","type":"string"}},"type":"object"},"principal.AgentBrief":{"properties":{"id":{"description":"ID is the agent id — the ref a run names and the value a member id derives\nfrom, so it must be stable across a reconcile.","type":"string"},"name":{"description":"Name is the display name a person reads in a member list.","type":"string"},"parent":{"description":"Parent is the agent that spawned this one; empty for an agent a person\ndefined.","type":"string"},"status":{"description":"Status is the registry status VERBATIM, never a boolean. The caller decides\nwhat counts as live: apps/team reads empty/active/ready as a live member and\nanything else as one that keeps its authorship and drops out of the roster,\nand folding that judgement into a bool here would move the policy to the\nwrong side of the wire.","type":"string"}},"type":"object"},"principal.Attestation":{"properties":{"agent":{"$ref":"#/components/schemas/principal.AgentBrief","description":"Agent is the agent."},"expires":{"description":"Expires is when the statement stops being valid, unix seconds.","format":"int64","type":"integer"},"kid":{"description":"Kid is the key that signed it.","type":"string"},"org":{"description":"Org is the principal it answers to — the org it was defined in.","type":"string"},"parents":{"description":"Parents are the agents that spawned it, nearest first.","items":{"$ref":"#/components/schemas/principal.AgentBrief"},"type":"array"},"statement":{"description":"Statement is the same, signed: a JWS a verifier checks offline against GET\n/v1/principal/keys.","type":"string"}},"type":"object"},"principal.Clearance":{"properties":{"allowed":{"description":"Allowed is true when nothing is required first and no fact blocks.","type":"boolean"},"amount":{"description":"Amount is the gross amount, U.S. dollars.","type":"string"},"category":{"description":"Category is what is bought: services, attorney, rents, royalties, other or\nmerchandise.","type":"string"},"decidedAt":{"description":"DecidedAt is when, unix seconds.","format":"int64","type":"integer"},"facts_required":{"description":"Facts are what a rule turns on that the platform does not know.","items":{"$ref":"#/components/schemas/principal.Fact"},"type":"array"},"id":{"description":"ID is the clearance, \"clr_\"-prefixed.","type":"string"},"notice":{"description":"Notice is what a clearance is and is not.","type":"string"},"payee":{"description":"Payee is the org to be paid.","type":"string"},"payer":{"description":"Payer is the caller's org.","type":"string"},"performed":{"description":"Performed is where the service is performed, as stated.","type":"string"},"platform":{"description":"Platform is whether the caller operates the payee's platform, as stated.","type":"boolean"},"rail":{"description":"Rail is how it moves.","type":"string"},"reporting_obligations":{"description":"Reporting are the returns this payment makes someone owe.","items":{"$ref":"#/components/schemas/principal.Obligation"},"type":"array"},"required_before_payment":{"description":"Required are the steps before the payment.","items":{"$ref":"#/components/schemas/principal.Step"},"type":"array"},"rules":{"description":"Rules names the rule behind each field above.","items":{"$ref":"#/components/schemas/principal.Decided"},"type":"array"},"settlement_methods":{"description":"Settlement are the ways it may settle, net of what is withheld.","items":{"$ref":"#/components/schemas/principal.Method"},"type":"array"},"status":{"description":"Status is what the payer may treat the payee as: us, foreign or unknown —\nread off the form the payee granted the payer, and unknown without one.","type":"string"},"withholding":{"$ref":"#/components/schemas/principal.Withholding","description":"Withholding is what must be withheld."}},"type":"object"},"principal.Decided":{"properties":{"field":{"type":"string"},"rule":{"$ref":"#/components/schemas/principal.Rule"}},"type":"object"},"principal.Entity":{"properties":{"ein":{"description":"EIN is on_file when the org's W-9 carries an EIN, and absent otherwise.","type":"string"},"founders":{"description":"Founders are its beneficial owners with their verification status —\nanswered to the org's admins.","items":{"$ref":"#/components/schemas/principal.Founder"},"type":"array"},"imported":{"description":"Imported is an entity that existed before and was imported.","type":"boolean"},"jurisdiction":{"description":"Jurisdiction is the U.S. state of formation.","type":"string"},"name":{"description":"Name is the company name.","type":"string"},"stage":{"description":"Stage is the formation's stage; \"company\" is formed.","type":"string"},"structure":{"description":"Structure is c-corp, llc or dao-llc.","type":"string"}},"type":"object"},"principal.Fact":{"properties":{"blocks":{"description":"Blocks is whether the payment waits on it.","type":"boolean"},"code":{"description":"Code is the fact's stable name.","type":"string"},"question":{"description":"Question is what must be answered.","type":"string"},"rule":{"$ref":"#/components/schemas/principal.Rule","description":"Rule is the rule that turns on it."}},"type":"object"},"principal.Form":{"properties":{"certified":{"description":"Certified is whether the signature covers the current facts.","type":"boolean"},"chapter3":{"description":"Chapter3 and Chapter4 are a W-8BEN-E's statuses — to the org's admins.","type":"string"},"chapter4":{"type":"string"},"country":{"description":"Country is US for a W-9, or the country of citizenship or incorporation.","type":"string"},"expires":{"description":"Expires is when a W-8 stops being valid, unix seconds.","format":"int64","type":"integer"},"foreignTin":{"type":"string"},"form":{"description":"Form is w9, w8ben or w8bene.","type":"string"},"residence":{"description":"Residence is the country of the permanent residence address.","type":"string"},"tin":{"description":"TIN and ForeignTIN are masked — answered to the org's admins.","type":"string"},"treaty":{"$ref":"#/components/schemas/principal.Treaty","description":"Treaty is a W-8's treaty claim — to the org's admins."},"usPerson":{"description":"USPerson is true for a W-9.","type":"boolean"},"valid":{"description":"Valid is whether it establishes what it certifies today.","type":"boolean"}},"type":"object"},"principal.Founder":{"properties":{"equityBps":{"description":"EquityBps is ownership in basis points, 0–10000.","format":"int64","type":"integer"},"kyc":{"description":"KYC is pending, verified, reviewer_confirmed or failed, verbatim.","type":"string"},"name":{"description":"Name is the full legal name.","type":"string"}},"type":"object"},"principal.Hit":{"properties":{"kind":{"description":"Kind is name (matched fuzzily), address (matched exactly) or jurisdiction.","type":"string"},"role":{"description":"Role is where it came from: entity, founder, form, wallet, or — for a\ncountry — citizenship, organization or residence.","type":"string"},"subject":{"description":"Subject is the name, address or country as the org stated it.","type":"string"}},"type":"object"},"principal.Identity":{"properties":{"reason":{"description":"Reason says which founders, and what is outstanding.","type":"string"},"status":{"description":"Status is verified (every founder of its formation passed identity\nverification through the licensed provider, or a platform reviewer\nconfirmed them), pending, failed, or none (no formation, or one naming no\nfounder).","type":"string"}},"type":"object"},"principal.JWK":{"properties":{"alg":{"description":"Alg is EdDSA.","type":"string"},"crv":{"description":"Crv is Ed25519.","type":"string"},"kid":{"description":"Kid names the key; a statement's header carries it.","type":"string"},"kty":{"description":"Kty is OKP, an octet key pair.","type":"string"},"use":{"description":"Use is sig.","type":"string"},"x":{"description":"X is the public key, base64url without padding.","type":"string"}},"type":"object"},"principal.JWKS":{"properties":{"keys":{"items":{"$ref":"#/components/schemas/principal.JWK"},"type":"array"}},"type":"object"},"principal.List":{"properties":{"attempted_at":{"description":"AttemptedAt is when the last attempt happened, successful or not.","format":"date-time","type":"string"},"designations":{"description":"Designations is how many entries the last successful load carried.","format":"int64","type":"integer"},"digest":{"description":"Digest is the digest of the payload that produced Designations.","type":"string"},"error":{"description":"Err is why the last attempt failed, empty if it succeeded.","type":"string"},"loaded_at":{"description":"LoadedAt is when that load happened. Zero means this list has never loaded,\nwhich is not the same as a publisher who designates nobody.","format":"date-time","type":"string"},"source":{"description":"Source is the publisher.","type":"string"}},"type":"object"},"principal.Match":{"properties":{"decidedAt":{"description":"DecidedAt is when, unix seconds.","format":"int64","type":"integer"},"decidedBy":{"description":"DecidedBy is the reviewer, or \"exact designated address\".","type":"string"},"entry":{"description":"Entry is the designated subject's primary name, or the jurisdiction's.","type":"string"},"foundAt":{"description":"FoundAt is when a screening first found it, unix seconds.","format":"int64","type":"integer"},"hits":{"description":"Hits are the org's names, addresses and countries that matched, in the order\nthey were first seen. A decision covers the hits it was made on.","items":{"$ref":"#/components/schemas/principal.Hit"},"type":"array"},"id":{"description":"ID addresses the match for a reviewer's decision. It is the org and the\ndesignation together, so a decision is about the org whatever it is called.","type":"string"},"list":{"description":"List is the publisher — ofac, un, eu or ofsi — or jurisdiction for an\nembargoed place.","type":"string"},"note":{"description":"Note is the reviewer's reason.","type":"string"},"org":{"description":"Org is the org the match names.","type":"string"},"reason":{"description":"Reason is what first matched, and which identifiers agreed or conflicted.","type":"string"},"ref":{"description":"Ref is the entry's reference on that list, or the country code.","type":"string"},"score":{"description":"Score is the highest similarity seen, 0 to 1; an address or a jurisdiction\nis 1.","format":"double","type":"number"},"status":{"description":"Status is open (a reviewer decides), cleared (a namesake, decided) or\nconfirmed (the designated person, decided — or a designated address).","type":"string"}},"type":"object"},"principal.Method":{"properties":{"net":{"description":"Net is what the payee receives, U.S. dollars.","type":"string"},"rail":{"description":"Rail is the rail: ledger or chain.","type":"string"},"rule":{"$ref":"#/components/schemas/principal.Rule","description":"Rule is why."},"withheld":{"description":"Withheld is what the payer keeps back and deposits itself, U.S. dollars.","type":"string"}},"type":"object"},"principal.Obligation":{"properties":{"authority":{"description":"Authority is who it is filed with.","type":"string"},"code":{"description":"Code is the obligation's stable name.","type":"string"},"due":{"description":"Due is when.","type":"string"},"filer":{"description":"Filer is the org that files it. It is never Hanzo: Hanzo prepares what an org\nfiles, and files nothing itself.","type":"string"},"form":{"description":"Form is what is filed.","type":"string"},"jurisdiction":{"description":"Jurisdiction is where, ISO 3166-1 alpha-2 or \"EU\".","type":"string"},"rule":{"$ref":"#/components/schemas/principal.Rule","description":"Rule is why."},"when":{"description":"When is the condition it is owed on, when it is owed on one.","type":"string"}},"type":"object"},"principal.Rule":{"properties":{"code":{"description":"Code is the rule's stable name, for a caller that branches on it.","type":"string"},"reason":{"description":"Reason is the rule, stated.","type":"string"}},"type":"object"},"principal.Screening":{"properties":{"at":{"description":"At is when it ran, unix seconds.","format":"int64","type":"integer"},"lists":{"description":"Lists is each publisher's readiness at the moment of screening.","items":{"$ref":"#/components/schemas/principal.List"},"type":"array"},"matches":{"description":"Matches are what matched — answered to the org's own admins and to a\nreviewer, never to another org.","items":{"$ref":"#/components/schemas/principal.Match"},"type":"array"},"reason":{"description":"Reason says why, in words.","type":"string"},"status":{"description":"Status is clear, review (a possible match awaits a platform reviewer),\nblocked (a confirmed match), unscreened (the org states nothing to screen),\nor unavailable (the lists are not fit to screen against).","type":"string"}},"type":"object"},"principal.Source":{"properties":{"app":{"description":"App names it: company, tax, wallet or agent.","type":"string"},"status":{"description":"Status is read, or absent when this deployment does not run it.","type":"string"}},"type":"object"},"principal.Statement":{"properties":{"agent":{"description":"Agent is the agent it is about.","type":"string"},"expires":{"description":"Expires is when it stops standing, unix seconds; zero for a W-9, which\nstands until the form changes.","format":"int64","type":"integer"},"form":{"description":"Form is the class of tax form it rests on: w9, w8ben or w8bene.","type":"string"},"id":{"description":"ID is the statement's jti.","type":"string"},"issued":{"description":"Issued is when it was signed, unix seconds.","format":"int64","type":"integer"},"jws":{"description":"JWS is the signed statement itself — the credential an agent presents —\nanswered only to the org it is about.","type":"string"},"kind":{"description":"Kind is what it states: tax.","type":"string"},"org":{"description":"Org is the principal the agent answers to.","type":"string"},"revoked":{"description":"Revoked is when it was withdrawn, unix seconds; zero while it stands.","format":"int64","type":"integer"},"status":{"description":"Status is live, expired or revoked.","type":"string"}},"type":"object"},"principal.Step":{"properties":{"code":{"description":"Code is the step's stable name, for a caller that branches on it.","type":"string"},"rule":{"$ref":"#/components/schemas/principal.Rule","description":"Rule is why."},"what":{"description":"What must happen, in words.","type":"string"},"where":{"description":"Where it is done, when it is done on this platform.","type":"string"},"who":{"description":"Who does it: payer, payee, or \"Hanzo platform reviewer\".","type":"string"}},"type":"object"},"principal.Summary":{"properties":{"missing":{"description":"Missing are the steps it owes, each with the rule that asks for it.","items":{"$ref":"#/components/schemas/principal.Step"},"type":"array"},"ready":{"description":"Ready is true when it lacks nothing its own facts decide.","type":"boolean"}},"type":"object"},"principal.Treaty":{"properties":{"article":{"description":"Article is the treaty article and paragraph claimed, e.g. \"12(2)\".","type":"string"},"conditions":{"description":"Conditions is the explanation the form asks for: the conditions of the\narticle the beneficial owner meets.","type":"string"},"country":{"description":"Country is the treaty country the beneficial owner is resident in.","type":"string"},"income":{"description":"Income is the type of income the claim covers: services, rents, royalties\nor other.","type":"string"},"lob":{"description":"LOB is W-8BEN-E line 14b: the treaty's limitation on benefits provision the\nentity meets. Required on a W-8BEN-E treaty claim; a W-8BEN has no line 14b.","type":"string"},"rateBps":{"description":"RateBps is the claimed withholding rate in basis points: 0 is exempt,\n1000 is 10%.","format":"int64","type":"integer"}},"type":"object"},"principal.View":{"properties":{"agents":{"description":"Agents are the agents that answer to it, spawned ones with their parent.","items":{"$ref":"#/components/schemas/principal.AgentBrief"},"type":"array"},"compliance":{"$ref":"#/components/schemas/principal.Summary","description":"Compliance is what it lacks to pay and be paid on the platform's rails."},"entity":{"$ref":"#/components/schemas/principal.Entity","description":"Entity is its legal entity, when it formed or imported one here."},"identity":{"$ref":"#/components/schemas/principal.Identity","description":"Identity is whether its founders are verified."},"org":{"description":"Org is the org — the principal itself.","type":"string"},"sanctions":{"$ref":"#/components/schemas/principal.Screening","description":"Sanctions is its screening against the OFAC, UN, EU and UK lists and the\nembargoed jurisdictions, run on this read and recorded by none: a match is\nrecorded for a reviewer when a payment to or from the org is cleared.\nMatches are answered to the org's admins."},"sources":{"description":"Sources says which owning apps answered.","items":{"$ref":"#/components/schemas/principal.Source"},"type":"array"},"tax":{"$ref":"#/components/schemas/principal.Form","description":"Tax is the form it certified about itself."},"wallets":{"description":"Wallets are its addresses.","items":{"$ref":"#/components/schemas/principal.WalletBrief"},"type":"array"}},"type":"object"},"principal.WalletBrief":{"properties":{"address":{"type":"string"},"agent":{"description":"Agent is the agent the wallet is scoped to, when it is one agent's.","type":"string"},"chain":{"type":"string"},"custody":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"type":"object"},"principal.Withholding":{"properties":{"amount":{"description":"Amount is the amount to withhold, U.S. dollars; empty when the rate is.","type":"string"},"chapter":{"description":"Chapter is \"3\" (IRC chapter 3, a payment to a foreign person) or \"backup\"\n(IRC §3406), and empty when nothing is withheld or it cannot yet be decided.","type":"string"},"rate":{"description":"Rate is the rate in percent: \"30\", \"24\", \"10\", \"0\". Empty when it cannot be\ndecided on the facts held — see facts_required.","type":"string"},"reason":{"description":"Reason says why, in words.","type":"string"},"rule":{"$ref":"#/components/schemas/principal.Rule","description":"Rule is the rule that decided it."}},"type":"object"},"principal.clearIn":{"properties":{"amount":{"description":"Amount is the gross amount in U.S. dollars, e.g. \"1250.00\".","type":"string"},"category":{"description":"Category is what is bought: services, attorney, rents, royalties, other or\nmerchandise. Services when omitted.","type":"string"},"payee":{"description":"Payee is the org id of the org to be paid.","type":"string"},"performed":{"description":"Performed is where the service is performed — for rents, where the property\nis; for royalties, where it is used — as an ISO 3166-1 alpha-2 code. It\ndecides the source of a foreign payee's income, and so its withholding.","type":"string"},"platform":{"description":"Platform is whether the caller operates the platform through which the payee\nprovides this to the platform's users, which decides platform-operator\nreporting. Omitted, it is asked back as a fact when it matters.","type":"boolean"},"rail":{"description":"Rail is how it will move: x402, ledger, chain, ach, wire, card, network or\nother — the rails an economic event names. Ledger when omitted.","type":"string"}},"type":"object"},"principal.clearanceList":{"properties":{"clearances":{"items":{"$ref":"#/components/schemas/principal.Clearance"},"type":"array"}},"type":"object"},"problem-details":{"description":"An RFC 9457 problem document.","properties":{"code":{"description":"A stable token a client can branch on, when the refusal names one.","type":"string"},"detail":{"description":"What was refused, for a person to read.","type":"string"},"status":{"description":"The HTTP status.","format":"int64","type":"integer"},"title":{"description":"The status's reason phrase.","type":"string"},"type":{"description":"about:blank","type":"string"}},"required":["type","status","detail"],"type":"object"},"project.Record":{"properties":{"name":{"description":"the record name the customer creates","type":"string"},"type":{"description":"TXT | CNAME","type":"string"},"value":{"description":"the record value","type":"string"}},"type":"object"},"project.edgeState":{"properties":{"configured":{"description":"Configured is whether the edge holds credentials to act at all. False means\nevery purge is a no-op.","type":"boolean"},"error":{"description":"Error is the blocker, so an operator reads it instead of guessing at it.","type":"string"},"freshness":{"description":"Freshness says, in one phrase, how long after a publish a reader sees it.\nIt is the sentence an operator actually wants; the booleans above are how\na machine reads the same fact.","type":"string"},"policy":{"additionalProperties":{"type":"string"},"description":"Policy is the Cache-Control this edge serves each class of object with. It\nis DERIVED from the one canonical function, never a second copy: half the\nconfusion when a publish looks stale is not knowing what the TTLs are, and\nreading them out of the source is not something an operator should have to\ndo to answer \"how long until this is live\".","type":"object"},"provider":{"description":"Provider is the CDN behind this edge, or \"none\". It is the first thing an\noperator wants and the only vendor name this API returns.","type":"string"},"reach":{"description":"Reach is the apexes a publish is invalidated on. A site is served on more\nthan one — the site plane's own and the first-party apex — and a purge that\ncovers one of them looks identical from here to a purge that covers both.","items":{"type":"string"},"type":"array"},"status":{"description":"Status is \"ok\" when a publish reaches readers immediately, else \"degraded\".","type":"string"}},"type":"object"},"project.projectsBoundDomains":{"properties":{"bound":{"description":"Bound is the result of THIS call, one row per host in the request: live for\nan already-vouched host, pending with the DNS records to publish otherwise.","items":{"$ref":"#/components/schemas/project.projectsDomain"},"type":"array"},"domains":{"description":"Domains are the hostnames that are VERIFIED and routing right now, after\nthis bind.","items":{"type":"string"},"type":"array"},"org":{"description":"Org is the organisation that owns the site.","type":"string"},"slug":{"description":"Slug is the site the hosts were bound to.","type":"string"}},"type":"object"},"project.projectsBuildSite":{"properties":{"brief":{"description":"Brief is what the site should be, in plain language. It is the whole input the\nmodel gets and it is size-bounded.","type":"string"},"model":{"description":"Model names which model writes the site. Absent takes the deployment's\ndefault — this route spends inference on the caller's org either way.","type":"string"},"name":{"description":"Name is the site's display name. Taken from what the model writes when omitted.","type":"string"},"slug":{"description":"Slug is the handle and public host label to publish under. Derived from the\nname, or from the brief, when omitted.","type":"string"}},"type":"object"},"project.projectsComplete":{"properties":{"bytes":{"description":"Bytes is their total size in bytes.","format":"int64","type":"integer"},"commit":{"description":"Commit is the revision that was built, recorded on the deployment.","type":"string"},"copy":{"description":"Copy lists the keys to take from CopyFrom's prefix, relative to it. They are\nalso named in Keys, which stays the whole release.","items":{"type":"string"},"type":"array"},"copyFrom":{"description":"CopyFrom names another site of the same org whose prefix already holds the\nbytes of Copy. A host that shares a build with another differs from it by a\npage or two, so CI uploads those and asks for the rest to be copied inside\nthe object store instead of sent again over the runner's link.","type":"string"},"files":{"description":"Files is how many objects CI published.","format":"int64","type":"integer"},"id":{"description":"ID is the queued deployment to complete, from the path.","type":"string"},"keys":{"description":"Keys is the manifest CI just uploaded, RELATIVE to the deployment prefix. It\nis what replaces `aws s3 sync --delete`: an upload grant authorizes writes\nonly, so CI cannot remove a file, and cloud reconciles the prefix against\nthis list instead (grant.go). Omit it and nothing is deleted — the prefix\nonly grows, which is the old pre-grant behaviour and a safe default.","items":{"type":"string"},"type":"array"},"liveUrl":{"description":"LiveURL is a HINT at the address the site should serve at. The public host is\nclaimed by cloud first, so this can refine the URL a deployment reports but\ncan never assert a subdomain another tenant holds.","type":"string"},"message":{"description":"Message is what happened, in words — on an error completion, why it failed.","type":"string"},"slug":{"description":"Slug is the project the deployment belongs to, from the path.","type":"string"},"status":{"description":"Status is how the build ended: `live` if it succeeded, `error` if it did not.\nNothing else is accepted.","type":"string"}},"type":"object"},"project.projectsCreate":{"properties":{"analytics":{"description":"Analytics is the opt-OUT for the wired-by-default analytics beacon: absent\n(nil) ⇒ ON (the default); explicit false ⇒ off. A pointer so \"unset\" is\ndistinguishable from \"false\" — the only way to turn the default off.","type":"boolean"},"description":{"description":"Description is the one-line summary, copied onto anything forked from this\nproject.","type":"string"},"framework":{"description":"Framework is a BUILD HINT from a closed set, defaulting to static. It tells CI\nhow to build a linked repo and never gates a deploy.","type":"string"},"license":{"description":"License is the terms that upstream work carries.","type":"string"},"name":{"description":"Name is the project's display name and the only REQUIRED field. When slug is\nomitted it is also what the slug is derived from.","type":"string"},"repo":{"description":"Repo links a git source, so pushes to it rebuild this project. Omit it for a\nproject deployed by uploading an artifact.","properties":{"branch":{"type":"string"},"url":{"type":"string"}},"type":"object"},"slug":{"description":"Slug is the handle everything else addresses this project by: the public host\n`\u003cslug\u003e.hanzo.app`, the object-store key segment, and the path parameter of\nevery later call. Derived from the name when omitted. It is a hostname label,\nso it is constrained and reserved labels such as `api` or `admin` are refused.","type":"string"},"upstream":{"description":"Upstream credits the third-party work this project was published from. It is\naccepted from any caller: giving away credit can only cost the publisher, so\nit needs no gate.","type":"string"},"visibility":{"description":"Visibility is \"public\" (the default when absent) or \"private\". Publishing\npublicly is ungated — that is the point of a community. Going PRIVATE is\nthe paid feature, so an unfunded org asking for it is refused rather than\nsilently downgraded (see resolve).","type":"string"}},"type":"object"},"project.projectsDeploySite":{"properties":{"files":{"description":"Files is the whole site, inline — every file it consists of. It REPLACES what\nis there rather than merging, so an omitted file is a deleted one.","items":{"$ref":"#/components/schemas/project.projectsFile"},"type":"array"},"name":{"description":"Name is the site's display name.","type":"string"},"slug":{"description":"Slug is the handle and public host label to publish under.","type":"string"}},"type":"object"},"project.projectsDeployStart":{"properties":{"commit":{"description":"Commit is the git sha this build was produced from, recorded on the\ndeployment so a released site can be traced back to its source. Optional.\n\nIt is the ONLY field here, and deliberately: the predecessor also accepted\n`source` and `branch`. `source` was the Content-Type discriminator this\nsplit removed. `branch` was accepted and DISCARDED — there is no branch\ncolumn on a deployment, and the lifecycle event derives the branch from the\nproject's own linked one — so declaring it would publish a settable field\nthat does nothing into the document, every generated SDK and the MCP input\nschema. A field that is read by nothing is not described as if it were.\n\n`url:\"-\"` because zip binds the query string OVER a decoded body, so\nwithout it a `?commit=` the caller never sent would outrank the one it did.","type":"string"},"slug":{"description":"Slug is the site to deploy, from the path.","type":"string"}},"type":"object"},"project.projectsDeployment":{"properties":{"bucket":{"description":"Bucket is the object-store bucket its files were written to.","type":"string"},"bytes":{"description":"Bytes is their total size in bytes.","format":"int64","type":"integer"},"commit":{"description":"Commit is the revision that was built, for a deployment that came from a\nrepository. Absent for an uploaded artifact, which has no revision.","type":"string"},"createdAt":{"description":"CreatedAt is when the deployment was queued, as Unix seconds.","format":"int64","type":"integer"},"files":{"description":"Files is how many objects the deployment published.","format":"int64","type":"integer"},"id":{"description":"ID identifies this one deployment attempt, and is what CI quotes back to\ncomplete it.","type":"string"},"liveUrl":{"description":"LiveURL is where this deployment serves, once it is live.","type":"string"},"message":{"description":"Message is what happened, in words — the build's own note, or on a failure\nwhy it failed.","type":"string"},"prefix":{"description":"Prefix is the key prefix within that bucket holding EXACTLY this deployment's\nobjects — the unit an upload grant is scoped to, so a grant for one deployment\ncannot write over another.","type":"string"},"projectId":{"description":"ProjectID is the project this deployment belongs to.","type":"string"},"source":{"description":"Source is what caused the deployment — a git push, an uploaded artifact, a\ngenerated site.","type":"string"},"status":{"description":"Status is where the attempt got to — queued, live, or failed. A deployment\nthat is live is not necessarily the one SERVING: the project's own\ncurrentDeploymentId says which is.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it last changed state, as Unix seconds — so the gap between\nthe two is how long the build took.","format":"int64","type":"integer"},"upload":{"$ref":"#/components/schemas/project.projectsUploadGrant","description":"Upload is the prefix-scoped, short-lived S3 write grant handed to CI with a\nqueued git deployment, so it needs no bucket credential (grant.go). Present\nONLY on the 202 that creates the deployment — it is never stored and never\nreplayed on a later read, so a grant cannot outlive the build it was minted\nfor by being fetched again."},"version":{"description":"Version counts deployments of this project from 1, so the history reads as an\nordered sequence rather than by timestamp. It is per project, not global.","format":"int64","type":"integer"}},"type":"object"},"project.projectsDomain":{"properties":{"createdAt":{"description":"CreatedAt is when the host was claimed, as Unix seconds — not when it went live.","format":"int64","type":"integer"},"detail":{"description":"Detail is what is holding the claim up, in words a person can act on.","type":"string"},"host":{"description":"Host is the custom hostname claimed for this site.","type":"string"},"records":{"description":"Records are EXACTLY the DNS records to publish to prove ownership and route\nthe host. Present only while pending, because a live host has already proved\nit; absent is therefore \"nothing left to do\", not \"we cannot say what to do\".","items":{"$ref":"#/components/schemas/project.Record"},"type":"array"},"status":{"description":"Status is `live` when the edge answers for this host now, `pending` while the\nclaim is waiting on DNS proof of ownership. A pending host is claimed but\nserves nothing.","type":"string"},"url":{"description":"URL is where the host will serve once it is live — present on a pending claim\ntoo, so a console can show the destination before it works.","type":"string"},"verified":{"description":"Verified is the same fact as a boolean, for a caller that only needs the yes\nor no. It cannot disagree with status.","type":"boolean"}},"type":"object"},"project.projectsDomains":{"properties":{"claims":{"description":"Claims is one row per host — live, or pending with the DNS records it still\nowes.","items":{"$ref":"#/components/schemas/project.projectsDomain"},"type":"array"},"domains":{"description":"Domains are the hostnames that are VERIFIED and routing right now.","items":{"type":"string"},"type":"array"},"org":{"description":"Org is the organisation that owns the site.","type":"string"},"slug":{"description":"Slug is the site the panel belongs to.","type":"string"}},"type":"object"},"project.projectsDomainsBind":{"properties":{"domains":{"description":"Domains are the custom hostnames to attach, in order. An empty list is a\n400 rather than a clear — releasing a host is its own call.","items":{"type":"string"},"type":"array"},"slug":{"description":"Slug is the site the hosts attach to, from the path.","type":"string"}},"type":"object"},"project.projectsFile":{"properties":{"content":{"description":"Content is the file's whole text, inline. There is no upload step and no\nreference to fetch: a site is sent as its bytes, and each file and the site as\na whole are size-bounded.","type":"string"},"path":{"description":"Path is where the file lands in the site, RELATIVE to its root — so\n\"index.html\" is the page served at /. Leading slashes and any attempt to\nescape the root are refused.","type":"string"}},"type":"object"},"project.projectsFork":{"properties":{"name":{"description":"target project name (optional; defaults to the parent's title)","type":"string"},"slug":{"description":"parent slug to fork — catalog template or published project (required)","type":"string"},"target":{"description":"Target overrides the derived project slug (optional; defaults to the\nparent slug). Kept distinct from Slug so callers can rename on fork.","type":"string"},"variant":{"description":"Variant picks a template's format/page/theme (optional; defaults to the\ntemplate's first shape). This is the axis the catalog used to spend\nsibling slugs on, so it is expressed here, where the user's preference is.","type":"string"}},"type":"object"},"project.projectsProject":{"properties":{"analytics":{"description":"Analytics is whether the web-analytics beacon is injected into this site's\npages. It is ON by default — a project has to opt out — and it is what the\nstatic builder reads to decide whether to inject at all.","type":"boolean"},"bucket":{"description":"Bucket is the object-store bucket the site's files are served out of.","type":"string"},"cacheControl":{"description":"CacheControl is the Cache-Control policy the edge serves this site's HTML\nunder — how long a reader may hold a stale page before asking again. Assets\nare content-addressed and are not governed by it.","type":"string"},"createdAt":{"description":"CreatedAt is when the project was created, as Unix seconds.","format":"int64","type":"integer"},"currentDeploymentId":{"description":"CurrentDeploymentID names the deployment currently serving, so a caller can\nask what is live without scanning the history.","type":"string"},"description":{"description":"Description is the one-line summary, which is copied onto forks of this\nproject and shown on a gallery card.","type":"string"},"dropLocal":{"description":"DropLocal is whether events a developer's own machine sends (localhost, 127.0.0.1,\n*.local) are dropped at ingest. ON by default.","type":"boolean"},"forkedFrom":{"description":"ForkedFrom is the parent this project was forked from (\"\u003corg\u003e/\u003cslug\u003e\" of a\npublished project, or a catalog template slug) — the attribution edge a\ngallery credits.","type":"string"},"framework":{"description":"Framework is a BUILD HINT from a closed set, defaulting to static. It tells CI\nhow to build a linked repo and never gates a deploy, so a wrong value costs a\nbuild rather than access.","type":"string"},"hidden":{"description":"Hidden is PLATFORM MODERATION, and it is a different axis from visibility: it\npulls a public project out of the catalogue without editing the publisher's\nown choice, so un-hiding restores exactly what they asked for. A project is\nlisted only when it is public AND not hidden. Always present, never omitted,\nfor the same reason as visibility.","type":"boolean"},"hiddenReason":{"description":"HiddenReason is why moderation hid it. Absent when it is not hidden.","type":"string"},"id":{"description":"ID is the project's internal identifier. It is stable across a rename, but it\nis not what the API addresses this project by — `slug` is.","type":"string"},"internalNetworks":{"description":"InternalNetworks are the site's own addresses, as CIDRs (\"203.0.113.0/24\"). A\nvisit from one is the site's team: the tag config answers audience \"internal\"\n(Google Analytics tagged internal, no ad pixel) and its events are stamped\ninternal and forwarded to no ad platform. Empty unless set.","items":{"type":"string"},"type":"array"},"key":{"description":"Key is the project's publishable ingest key, minted at create. It is the\nvalue the injected beacon carries and the ONE thing that attributes this\nsite's events; the static-builder reads it beside analytics.\n\nPublishable means it belongs in a page's source: it names a write scope and\nmints no principal, so it is returned in full rather than masked. Masking it\nwould only mean every caller needed a second endpoint to get the thing the\npage already ships.","type":"string"},"lastPurgeAt":{"description":"LastPurgeAt is when the edge cache was last cleared, as Unix seconds, so a\nconsole can say how fresh what readers see actually is. Absent means never.","format":"int64","type":"integer"},"license":{"description":"License is the terms that upstream work carries. Absent has the same reading:\nundeclared, not unencumbered.","type":"string"},"liveUrl":{"description":"LiveURL is where the site answers today. Absent until something has been\ndeployed.","type":"string"},"name":{"description":"Name is the project's display name, free text a person chose.","type":"string"},"namespace":{"description":"Namespace is where the site's files are kept: `\u003cnamespace\u003e/\u003cslug\u003e/` in the\nsites bucket. It is the GitHub org the project's repository lives in when this\norg holds that GitHub account, and the org otherwise, decided when the\nrepository is linked.","type":"string"},"org":{"description":"Org is the organisation that owns the project, and therefore who pays for it\nand who may change it. It is also the AUTHORSHIP line a gallery credits;\nthere is no separate author field.","type":"string"},"repo":{"$ref":"#/components/schemas/project.projectsRepo","description":"Repo is the git source this project builds from, empty when it is deployed by\nuploading an artifact instead."},"slug":{"description":"Slug is the identifier that MATTERS: the handle every later call addresses,\nthe S3 key segment the site's objects live under, and the label of the public\nhost `\u003cslug\u003e.hanzo.app`. Because it is a hostname it is constrained and\nreserved labels such as `api` are refused.","type":"string"},"space":{"description":"Space is the project's Base data space, which is where a deployed site's form,\nforum and data submissions land. Absent means the site stores nothing.","type":"string"},"starred":{"description":"Starred is THIS CALLER's star, not a property of the project — two people\nin the same org see different values for the same row, which is the whole\npoint of it. Always present so a client can tell \"not starred\" from \"this\nAPI is too old to say\", the same reason visibility and hidden are.","type":"boolean"},"status":{"description":"Status is where the project stands — whether a build has ever succeeded and\nwhether anything is serving right now.","type":"string"},"tags":{"additionalProperties":{"type":"string"},"description":"Tags is the site's browser tag config: platform slug → non-secret pixel id (GA\nmeasurement, Meta pixel, …) — what track.js injects and the server CAPI reads,\nper site. Omitted when none are set. The API SECRET is never here (KMS).","type":"object"},"updatedAt":{"description":"UpdatedAt is when the project's own record last changed, as Unix seconds. A\ndeploy is not an edit of the project, so this does not move on every publish.","format":"int64","type":"integer"},"upstream":{"description":"Upstream credits the third-party work this project was published from — a\nfree-text line, because the honest answer is a name and a title that no enum\ncould hold. Absent means NOBODY HAS SAID, not that there is nothing to say.","type":"string"},"visibility":{"description":"Visibility is \"public\" or \"private\", and Hidden reports platform\nmoderation. Both are always present (never omitempty) so a consumer can\ntell a real answer from \"this API is too old to say\" — and so a console\nnever renders a project as public because a field was missing.\n\nAuthorship is deliberately absent: it is Org, above.","type":"string"}},"type":"object"},"project.projectsPublish":{"properties":{"slug":{"description":"Slug is the site to publish, from the path.","type":"string"},"source":{"description":"Source is the build output to promote, as a path RELATIVE to your org's own\nstorage space — never a URL and never a bucket. The org segment is prepended\nserver-side from the validated principal, so the worst a hostile source can\naddress is something your own org already owns.","type":"string"}},"type":"object"},"project.projectsRelease":{"properties":{"active":{"description":"Active is whether this is the release the site is SERVING right now. Exactly\none release of a site is active; the others are kept so they can be activated\nagain, until retention reclaims them.","type":"boolean"},"bytes":{"description":"Bytes is their total size in bytes.","format":"int64","type":"integer"},"createdAt":{"description":"CreatedAt is when the release was cut, as Unix seconds — not when it was last\nactivated.","format":"int64","type":"integer"},"objects":{"description":"Objects is how many files the release holds.","format":"int64","type":"integer"},"releaseId":{"description":"ReleaseID is derived from a DIGEST of the release's own manifest, so identical\ncontent is the same release and a release can never be confused with another\none. Activating an older id IS the rollback.","type":"string"},"slug":{"description":"Slug is the site this release belongs to.","type":"string"},"source":{"description":"Source is what the release was cut from — the build output or upload it was\npromoted out of.","type":"string"},"url":{"description":"URL is where the site serves. Present only on the ACTIVE release, since an\ninactive one is not answering anywhere.","type":"string"}},"type":"object"},"project.projectsRepo":{"properties":{"branch":{"description":"Branch is the ref a push has to touch for this project to rebuild. Pushes to\nany other branch are ignored.","type":"string"},"provider":{"description":"Provider is the forge the URL was recognised as — it decides which webhook\nand which credential reach the repository, and is DERIVED from the URL rather\nthan chosen by the caller.","type":"string"},"url":{"description":"URL is the clone address of the repository this project builds from.","type":"string"}},"type":"object"},"project.projectsSite":{"properties":{"name":{"description":"Name is the site's display name.","type":"string"},"slug":{"description":"Slug is the site's handle — also the label of the host it serves at.","type":"string"},"status":{"description":"Status is the project's state behind the site — whether it is serving, still\nbuilding, or failed its last build. A site that is listed is not necessarily\none that answers.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the project last changed, as Unix seconds.","format":"int64","type":"integer"},"url":{"description":"URL is the pretty address readers use, not the object-store path behind it.","type":"string"}},"type":"object"},"project.projectsSiteDeploy":{"properties":{"deploymentId":{"description":"DeploymentID is the deployment this publish recorded, for the history.","type":"string"},"files":{"description":"Files are the site-relative paths that were uploaded, sorted.","items":{"type":"string"},"type":"array"},"name":{"description":"Name is the project's display name.","type":"string"},"slug":{"description":"Slug is the project the site was published into, created on the fly when\nthe slug was free.","type":"string"},"status":{"description":"Status is the deployment status, \"live\" on success.","type":"string"},"url":{"description":"URL is the canonical live URL, https://\u003cslug\u003e.\u003capex\u003e — empty when the\nsubdomain belongs to another tenant and this site has none.","type":"string"}},"type":"object"},"project.projectsStar":{"properties":{"starred":{"description":"Starred is whether THIS caller has starred the project after the toggle —\ntheir own bookmark, not a property the project carries, so two people see\ntwo answers for one project.","type":"boolean"}},"type":"object"},"project.projectsUpdate":{"properties":{"cacheControl":{"description":"CacheControl replaces the Cache-Control policy the edge serves this site's\nHTML under. Absent leaves it.","type":"string"},"description":{"description":"Description replaces the one-line summary. Absent leaves it.","type":"string"},"dropLocal":{"description":"DropLocal turns the drop of localhost events at ingest on or off. Absent leaves it.","type":"boolean"},"framework":{"description":"Framework replaces the build hint. It affects the NEXT build only — nothing\nalready deployed is rebuilt.","type":"string"},"hidden":{"description":"Hidden is MODERATION, and the only admin-gated field on this body: it pulls\na public project out of the catalogue from admin.hanzo.ai without editing\nthe publisher's own visibility choice, so un-hiding restores exactly what\nthey asked for. A tenant sending it is ignored.","type":"boolean"},"hiddenReason":{"description":"HiddenReason records WHY moderation hid it, so the action can be explained\nand reviewed later. Admin-gated like hidden itself.","type":"string"},"internalNetworks":{"description":"InternalNetworks replaces the site's own addresses: CIDRs or bare addresses, at\nmost 64. Absent leaves them; send [] to clear.","items":{"type":"string"},"type":"array"},"license":{"description":"License is the terms that upstream work carries, with the same clear-versus-\nleave rule.","type":"string"},"name":{"description":"Name replaces the display name. Absent leaves it; the slug never moves with it.","type":"string"},"repo":{"description":"Repo relinks the git source. Absent leaves the existing link.","properties":{"branch":{"type":"string"},"url":{"type":"string"}},"type":"object"},"slug":{"description":"Slug is the project to update, from the path. The URL is the addressing\nauthority — a `slug` in the body cannot move the write to another project.","type":"string"},"tags":{"additionalProperties":{"type":"string"},"description":"Tags sets the site's browser tag config: platform slug → non-secret pixel id\n(e.g. {\"ga4\":\"G-…\",\"meta\":\"…\"}). track.js injects these first-party and the\nserver CAPI reads them, per site. Absent LEAVES them; a present object REPLACES\nthe set (send {} to clear). The ids are public — they ship in the page — so this\nis not the SECRET path (a CAPI token is sealed via POST /v1/destination).","type":"object"},"upstream":{"description":"Upstream credits the third-party work this project was published from, and is\nsettable after the fact because the live demos are the ones that most need\ncrediting. An explicit empty string CLEARS the credit; absent leaves it.","type":"string"},"visibility":{"description":"Visibility flips an existing project between \"public\" and \"private\". Same\nONE rule as at create: public is free, private needs a paid plan.","type":"string"}},"type":"object"},"project.projectsUploadGrant":{"properties":{"copy":{"description":"Copy is true when the completion of this deployment accepts copyFrom and\ncopy. A client that does not see it uploads every object itself, since a\nserver that ignores those fields would leave the copied keys missing.","type":"boolean"},"expiresAt":{"description":"ExpiresAt is when the grant stops being accepted, as Unix seconds. It is\nshort-lived by design and is handed out ONCE, on the response that queues the\ndeployment — a later read of that deployment does not carry it, so a grant\ncannot be fetched again after the build it was minted for.","format":"int64","type":"integer"},"fields":{"additionalProperties":{"type":"string"},"description":"Fields are form values every POST must carry VERBATIM, alongside `key` and\n`file`. The signature covers them, so altering any one of them — including\nwidening the key to reach outside the prefix — invalidates the grant rather\nthan extending it.","type":"object"},"maxBytes":{"description":"MaxBytes bounds ONE object, not the upload as a whole.","format":"int64","type":"integer"},"prefix":{"description":"Prefix is the only place this grant can write: the deployment's own key\nprefix. It authorizes WRITES ONLY, which is why completing a deployment\nreconciles the prefix against a manifest instead of letting CI delete.","type":"string"},"url":{"description":"URL is the address to POST each object to. It is signed for the PUBLIC\nendpoint, because the signature covers the host and CI posts from outside the\ncluster.","type":"string"}},"type":"object"},"projectsDeployment":{"properties":{"bucket":{"type":"string"},"bytes":{"type":"integer"},"commit":{"type":"string"},"createdAt":{"type":"integer"},"files":{"type":"integer"},"id":{"type":"string"},"liveUrl":{"type":"string"},"message":{"type":"string"},"prefix":{"type":"string"},"projectId":{"type":"string"},"source":{"type":"string"},"status":{"type":"string"},"updatedAt":{"type":"integer"},"upload":{"$ref":"#/components/schemas/projectsUploadGrant"},"version":{"type":"integer"}},"type":"object"},"projectsUploadGrant":{"properties":{"copy":{"type":"boolean"},"expiresAt":{"type":"integer"},"fields":{"additionalProperties":{"type":"string"},"type":"object"},"maxBytes":{"type":"integer"},"prefix":{"type":"string"},"url":{"type":"string"}},"type":"object"},"prompt.CatalogEntry":{"properties":{"labels":{"description":"Labels is the starter's second suggested taxonomy, same treatment as Tags.","items":{"type":"string"},"type":"array"},"name":{"description":"Name is the starter's suggested handle. It is NOT taken in your org: the\ncatalog is shared reference content, so this name is free until you import it,\nand posting it under a name you already use appends a version to yours.","type":"string"},"prompt":{"description":"Prompt is the starter's full template body, ready to POST as-is. Entries too\nlarge to create (over 64 KiB) are dropped from this list rather than offered.","type":"string"},"tags":{"description":"Tags is the starter's suggested taxonomy, carried through unchanged if you\nimport it.","items":{"type":"string"},"type":"array"},"type":{"description":"Type labels the template's kind, defaulted to \"text\" for entries that declare\nnone.","type":"string"}},"type":"object"},"prompt.catalogList":{"properties":{"data":{"description":"Data is every starter prompt, each importable as-is with POST /v1/prompt.","items":{"$ref":"#/components/schemas/prompt.CatalogEntry"},"type":"array"}},"type":"object"},"prompt.metricList":{"properties":{"data":{"description":"Data is one row per prompt the org owns.","items":{"$ref":"#/components/schemas/prompt.metricRow"},"type":"array"}},"type":"object"},"prompt.metricRow":{"properties":{"createdAt":{"description":"CreatedAt is when version 1 was written, RFC 3339 UTC.","type":"string"},"currentVersion":{"description":"CurrentVer is the version number served as current. It always equals\n`versions`: numbering is dense from 1, and deleting a prompt takes its whole\nhistory with it rather than leaving a gap.","format":"int64","type":"integer"},"lastUpdatedAt":{"description":"LastUpdatedAt is when the newest version was appended, RFC 3339 UTC — the age\nof the template you would get today.","type":"string"},"name":{"description":"Name is the prompt this row is about — its org-unique handle.","type":"string"},"type":{"description":"Type is the current version's kind.","type":"string"},"versions":{"description":"Versions is how many revisions the prompt has, COUNTED in the store and\nuncapped — so it can exceed the 100 entries a list row or a detail response\ncarries. Note the type: here `versions` is a number, while on a list row it is\nthe list of version numbers.","format":"int64","type":"integer"}},"type":"object"},"prompt.promptDetail":{"properties":{"createdAt":{"description":"CreatedAt is when version 1 was written, RFC 3339 UTC. Appending a version\ndoes not move it.","type":"string"},"labels":{"description":"Labels is the current version's free-form taxonomy. `[]` when none, never\nnull.","items":{"type":"string"},"type":"array"},"lastUpdatedAt":{"description":"UpdatedAt is when the current version was appended, RFC 3339 UTC. Equal to\ncreatedAt for a prompt that has only ever had one version.","type":"string"},"name":{"description":"Name is the prompt's org-unique handle and the URL segment it is addressed by.","type":"string"},"prompt":{"description":"Prompt is the CURRENT version's template body — the only content this service\nreturns. Earlier versions are listed in versionHistory by number and date, and\ntheir bodies are not served in bulk.","type":"string"},"tags":{"description":"Tags is the second free-form taxonomy, same rules as Labels.","items":{"type":"string"},"type":"array"},"type":{"description":"Type labels the current version's kind; \"text\" unless the creator said\notherwise.","type":"string"},"version":{"description":"Version is the current version number, starting at 1 and incremented by one on\nevery create against an existing name.","format":"int64","type":"integer"},"versionHistory":{"description":"Versions is the history METADATA, newest first, capped at the last 100 — no\nbodies, so a long history cannot inflate this response. It always includes the\ncurrent version as its first entry.","items":{"$ref":"#/components/schemas/prompt.versionView"},"type":"array"}},"type":"object"},"prompt.promptList":{"properties":{"data":{"description":"Data is one row per prompt the org owns, each with its version numbers and\ntaxonomy — never the template bodies.","items":{"$ref":"#/components/schemas/prompt.promptMeta"},"type":"array"}},"type":"object"},"prompt.promptMeta":{"properties":{"labels":{"description":"Labels is the creator's free-form taxonomy, stored as given after trimming and\nde-duplication. Always present, `[]` when none — never null.","items":{"type":"string"},"type":"array"},"lastUpdatedAt":{"description":"LastUpdatedAt is when the newest version was appended, RFC 3339 UTC. Empty\nonly if the record carries no timestamp at all.","type":"string"},"name":{"description":"Name is the prompt's org-unique handle and the URL segment it is fetched by:\nGET /v1/prompt/\u003cname\u003e.","type":"string"},"tags":{"description":"Tags is the second free-form taxonomy under the same rules as Labels. Nothing\nin this service interprets either; they are yours to organize by.","items":{"type":"string"},"type":"array"},"type":{"description":"Type labels the template's kind, \"text\" unless the creator said otherwise. It\nis the CURRENT version's type; earlier versions may carry a different one.","type":"string"},"versions":{"description":"Versions lists every version NUMBER this prompt has, newest first, capped at\nthe last 100. The highest is the current one. (On a metrics row the same key\nis a count, not a list.)","items":{"format":"int64","type":"integer"},"type":"array"}},"type":"object"},"prompt.promptReq":{"properties":{"labels":{"description":"Labels is free-form taxonomy, each up to 64 characters, capped at 32 entries.","items":{"type":"string"},"type":"array"},"name":{"description":"Name is the org-unique handle AND the URL segment the prompt is addressed by:\n1-64 characters matching ^[A-Za-z0-9][A-Za-z0-9._-]*$. \"metrics\", \"new\" and\n\"catalog\" are reserved. A name that already exists appends a new version.","type":"string"},"prompt":{"description":"Prompt is the template body, capped at 64 KiB. It holds template text only —\nnever a secret.","type":"string"},"tags":{"description":"Tags is free-form taxonomy under the same bounds as Labels.","items":{"type":"string"},"type":"array"},"type":{"description":"Type labels the template's kind; defaults to \"text\".","type":"string"}},"type":"object"},"prompt.versionView":{"properties":{"createdAt":{"description":"CreatedAt is when this revision was appended, RFC 3339 UTC.","type":"string"},"type":{"description":"Type is the kind this revision was written with, which may differ from the\ncurrent one.","type":"string"},"version":{"description":"Version is this revision's number, 1 for the first. Numbers are dense and\nnever reused: deleting the prompt drops the whole history with it.","format":"int64","type":"integer"}},"type":"object"},"provider.Field":{"properties":{"default":{"description":"Default is what an empty input stands for.","type":"string"},"help":{"description":"Help is the connector's own instruction for finding the value.","type":"string"},"label":{"description":"Label is what the input is called on the form.","type":"string"},"name":{"description":"Name is the key the value is submitted under.","type":"string"},"options":{"description":"Options are the values a choice field accepts.","items":{"$ref":"#/components/schemas/provider.FieldOption"},"type":"array"},"required":{"description":"Required is whether the form refuses to submit without it.","type":"boolean"},"secret":{"description":"Secret masks the input; its value is sealed and never read back.","type":"boolean"},"type":{"description":"Type is \"number\", \"boolean\" or \"text\" (multi-line) when the value is\nnot a single line of text.","type":"string"}},"type":"object"},"provider.FieldOption":{"properties":{"label":{"description":"Label is what the choice is called.","type":"string"},"value":{"description":"Value is what submitting it sends.","type":"string"}},"type":"object"},"provider.PropSpec":{"properties":{"description":{"description":"Description says what the value is.","type":"string"},"displayName":{"description":"DisplayName is what a form calls it.","type":"string"},"name":{"description":"Name is the input's key in the action's input object.","type":"string"},"required":{"description":"Required is whether the action refuses to run without it.","type":"boolean"},"type":{"description":"Type is the JSON type the value takes: string|number|boolean|object|array.","type":"string"}},"type":"object"},"provider.authorizeOut":{"properties":{"authorizeUrl":{"description":"AuthorizeURL is the provider consent (or bot deep-link) URL.","type":"string"}},"type":"object"},"provider.connectIn":{"properties":{"accountId":{"description":"AccountID is the provider account the credential should be scoped to, for the\nproviders whose Verify needs one (Cloudflare). Ignored by the OAuth path.","type":"string"},"fields":{"additionalProperties":{"type":"string"},"description":"Fields are the named inputs of a credential connector whose form is more\nthan one key (the connector's published fields). Their presence selects\nthe credential path exactly as Token's does. Never logged or echoed.","type":"object"},"provider":{"description":"Provider is the connector's registry id, from the :provider path segment.","type":"string"},"return":{"description":"Return is the page the OAuth callback sends the person back to, with\nconnected=\u003cprovider\u003e\u0026account=\u003clabel\u003e or error=\u003cprovider\u003e\u0026reason=\u003cwhy\u003e added\nto its query. It must name one of this deployment's return pages (on\napi.hanzo.ai: https://hanzo.ai/?at=-/settings/integrations,\nhttps://console.hanzo.ai/connectors, https://platform.hanzo.ai/connectors);\nanything else, or nothing, returns to the console's /connectors. Ignored by\nthe credential path.","type":"string"},"token":{"description":"Token is the customer's provider credential. Its PRESENCE — not its value —\nis what selects the apikey seal over the OAuth flow for a provider that\noffers both: {\"token\":\"…\"}, even empty, is an apikey attempt (→ verify, which\nanswers the \"token required\" 400 on an empty value), while a body with no\ntoken key (the console Connect button, `hanzo connector add` with no --token)\nstarts OAuth. Read on STDIN by the CLI, never argv; never logged or echoed.","type":"string"}},"type":"object"},"provider.connectOut":{"properties":{"account":{"description":"Account is the account label the provider reported for the credential.\napikey path only; a pointer because \"\" is a real answer the provider gave.","type":"string"},"authorizeUrl":{"description":"AuthorizeURL is the provider consent URL to send the user to. OAuth path only.","type":"string"},"connected":{"description":"Connected is true on the apikey path once the credential verified and sealed.","type":"boolean"},"externalId":{"description":"ExternalID is the provider's account id for the credential. apikey path only.","type":"string"},"provider":{"description":"Provider is the connector's registry id. apikey path only.","type":"string"},"scopes":{"description":"Scopes are the permissions the credential carries. apikey path only; never\nnull on that path ([] when the provider reported none).","items":{"type":"string"},"type":"array"}},"type":"object"},"provider.connectionView":{"properties":{"account":{"description":"Account is the human label of the connected third-party account (the Slack\nteam name, the GitHub org login). Provider-supplied and sanitized on ingest.","type":"string"},"connectedAt":{"description":"ConnectedAt is when the connection was last (re)established, RFC 3339 UTC.","type":"string"},"expiresAt":{"description":"ExpiresAt is when the access token expires, RFC 3339 UTC; empty for a\ncredential that does not expire. Reading the token rotates it inside the\nwindow, so a reader never sees an expired one.","type":"string"},"externalId":{"description":"ExternalID is the provider's own id for the account (Slack team.id, GitHub\ninstallation_id) — the value inbound webhooks are mapped back to this org by.","type":"string"},"id":{"description":"ID is provider + \":\" + label, the address every connection route takes.\nEmpty on the org plane, where a provider's connection is addressed by the\nprovider alone.","type":"string"},"kind":{"description":"Kind is personal or page for a social account that has one. Empty for\nevery other connector.","type":"string"},"label":{"description":"Label is the caller's own name for this connection (\"default\", \"work\").","type":"string"},"provider":{"description":"Provider is the connected provider's registry id. Empty where the reader\nalready knows it, which is every org-plane card.","type":"string"},"scopes":{"description":"Scopes are the permissions the provider granted. Never null; [] when none.","items":{"type":"string"},"type":"array"}},"type":"object"},"provider.connectionsOut":{"properties":{"connections":{"description":"Connectors is the caller's own set. Never null; [] when they have none.","items":{"$ref":"#/components/schemas/provider.connectionView"},"type":"array"}},"type":"object"},"provider.credentialIn":{"properties":{"accountId":{"description":"AccountID scopes the credential where the provider's Verify needs one.","type":"string"},"label":{"description":"Label names this connection; empty means \"default\".","type":"string"},"oauth":{"$ref":"#/components/schemas/provider.oauthBundleIn","description":"OAuth is a bundle the CLI already obtained through its own local PKCE flow.\nPresent ⇒ the Adopt path; absent ⇒ the Token path."},"provider":{"description":"Provider is the user-scoped provider's registry id, from the path.","type":"string"},"token":{"description":"Token is the customer-held credential for the Verify path. Read on STDIN by\nthe CLI, never argv; never logged, echoed, or stored outside KMS.","type":"string"}},"type":"object"},"provider.credentialOut":{"properties":{"connected":{"description":"Connected is always true — a failed verification is a 400 and stores nothing.","type":"boolean"},"connector":{"$ref":"#/components/schemas/provider.connectionView","description":"Connection is the connector as it now stands."}},"type":"object"},"provider.devicePollOut":{"properties":{"connector":{"$ref":"#/components/schemas/provider.connectionView","description":"Connection is the connected connector. Present only on \"connected\"."},"interval":{"description":"Interval is the seconds to wait before the next poll. Present only while\npending, and it may rise when the provider asks the client to slow down.","format":"int64","type":"integer"},"status":{"description":"Status is the flow's state. \"pending\" means poll again after Interval.","type":"string"}},"type":"object"},"provider.deviceStartIn":{"properties":{"label":{"description":"Label names this connection so one user can hold several per provider\n(\"work\", \"personal\"). Empty means \"default\". 1-64 of [A-Za-z0-9._-].","type":"string"},"provider":{"description":"Provider is the user-scoped provider's registry id, from the path.","type":"string"}},"type":"object"},"provider.deviceStartOut":{"properties":{"expiresAt":{"description":"ExpiresAt is when the flow dies, RFC 3339 UTC.","type":"string"},"flow":{"description":"Flow is the id to poll with.","type":"string"},"interval":{"description":"Interval is the seconds to wait between polls.","format":"int64","type":"integer"},"userCode":{"description":"UserCode is the short code the user types at VerifyURL.","type":"string"},"verifyUrl":{"description":"VerifyURL is the page the user opens to enter UserCode.","type":"string"}},"type":"object"},"provider.disconnectIn":{"properties":{"account":{"description":"Account names ONE account to disconnect — the label the connection carries\n(a GitHub login, for the App). Empty disconnects every account the org holds\nfor the provider. An account the org does not hold disconnects nothing.","type":"string"},"provider":{"description":"Provider is the connector's registry id, from the :provider path segment.","type":"string"}},"type":"object"},"provider.disconnectOut":{"properties":{"accounts":{"description":"Accounts are the account labels this disconnect removed. Omitted when none\nwas connected.","items":{"type":"string"},"type":"array"},"disconnected":{"description":"Disconnected is always true — the org's secrets and connection row are gone.","type":"boolean"},"uninstalled":{"description":"Uninstalled are the accounts whose provider installation was removed too,\nbecause no other org held them. An account another org still holds keeps its\ninstallation and is absent here.","items":{"type":"string"},"type":"array"}},"type":"object"},"provider.githubBackfillIn":{"properties":{"repo":{"description":"Repo narrows the pass to ONE granted repository, named `owner/name` or\nbare `name` (case-insensitive). Empty walks every granted repository. A\nproject page syncs its own issues with this; the org-wide pass stays the\ndefault. A name the connection does not grant is a 404, never a silent\nempty pass that reads as \"this repository has no issues\".","type":"string"},"state":{"description":"State is the GitHub issue state to walk: \"open\" (the default), \"closed\" or\n\"all\". Anything else is a 400.","type":"string"}},"type":"object"},"provider.githubBackfillResult":{"properties":{"created":{"description":"Created is how many native issues this pass created.","format":"int64","type":"integer"},"failed":{"description":"Failed is how many repos or issues errored; the pass continues past each.","format":"int64","type":"integer"},"issues":{"description":"Issues is how many upstream issues were seen.","format":"int64","type":"integer"},"repos":{"description":"Repos is how many granted repos were walked (archived/disabled are skipped).","format":"int64","type":"integer"},"truncated":{"description":"Truncated is set when the time budget or the issue cap stopped the pass early.\nRe-run to continue — the mirror is idempotent by ExtRef, so nothing duplicates.","type":"boolean"},"updated":{"description":"Updated is how many existing native issues this pass refreshed.","format":"int64","type":"integer"}},"type":"object"},"provider.githubBranch":{"properties":{"commit":{"description":"Commit is the sha the branch points at.","type":"string"},"default":{"description":"Default is whether it is the repository's default branch, which always\nleads the first page when it matches.","type":"boolean"},"name":{"description":"Name is the branch's short name (\"main\", \"feat/login\").","type":"string"}},"type":"object"},"provider.githubBranchesOut":{"properties":{"branches":{"description":"Branches is this page: the default branch first, then the rest by name.\nNever null.","items":{"$ref":"#/components/schemas/provider.githubBranch"},"type":"array"},"next":{"description":"Next is the cursor for the page after this one; empty on the last page.","type":"string"},"total":{"description":"Total is how many branches match q, across every page.","format":"int64","type":"integer"}},"type":"object"},"provider.githubForkOut":{"properties":{"clone_url":{"description":"CloneURL is the fork's https git remote. GitHub populates a new fork in the\nbackground, so a clone issued the moment this answers can still find it empty.","type":"string"},"default_branch":{"description":"DefaultBranch is the branch the fork checks out, inherited from upstream.","type":"string"},"existing":{"description":"Existing reports that the fork was already there. GitHub answers 202 either\nway, so without this a caller cannot tell \"made you one\" from \"you had one\".","type":"boolean"},"full_name":{"description":"FullName is the fork's \"owner/repo\". The owner is the account it landed in\n— the request's org, or the installation's own account when none was named.","type":"string"},"html_url":{"description":"HTMLURL is the fork's page on github.com.","type":"string"}},"type":"object"},"provider.githubForkReq":{"properties":{"org":{"description":"Org is the GitHub account to fork INTO; empty forks to the installation's\nown account, which is the common case.","type":"string"},"repo":{"description":"Repo is a repository the org's installation was GRANTED, by name.","type":"string"}},"type":"object"},"provider.githubImportIn":{"properties":{"all":{"description":"All imports every repository the installation grants, instead of naming\nthem. Archived and disabled repositories are skipped either way — they\ncannot be fetched.","type":"boolean"},"repos":{"description":"Repos names the repositories to import, either owner-qualified\n(\"hanzo-apps/ai\") or as a bare name (\"ai\"); a trailing \".git\" is stripped.\nA bare name that matches more than one granted repository is an error\nrather than a guess, because one Hanzo org may hold several GitHub\ninstallations and a name is only unique within an owner.\nIgnored when all is true.","items":{"type":"string"},"type":"array"}},"type":"object"},"provider.githubImportOut":{"properties":{"codebases":{"description":"Codebases are the names they take in the org's code workspace, in the same\norder: poll GET /v1/git/repos for each to appear.","items":{"type":"string"},"type":"array"},"queued":{"description":"Queued is how many repositories were handed to the background importer.","format":"int64","type":"integer"},"repos":{"description":"Repos names those repositories, in the installation's listing order.","items":{"type":"string"},"type":"array"}},"type":"object"},"provider.githubInstallationView":{"properties":{"connected":{"description":"Connected reports whether THIS org has already bound this account.","type":"boolean"},"grant":{"description":"Grant is \"all\" or \"selected\" — how many of the account's repositories the\ninstall covers. A reader deciding what to import needs the reach, not just\nthe name.","type":"string"},"htmlUrl":{"description":"HTMLURL is the account's page on GitHub.","type":"string"},"login":{"description":"Login is the GitHub account name — the org or user the App is installed on.","type":"string"},"type":{"description":"Type is \"Organization\" or \"User\".","type":"string"}},"type":"object"},"provider.githubInstallationsOut":{"properties":{"installUrl":{"description":"InstallURL is where to grant a new account, so a UI with an empty list has\nsomewhere to send the reader instead of a dead end.","type":"string"},"installations":{"description":"Installations is every account the caller may see: the ones its own org has\nbound, or — for a super admin — every account the App is installed on.\nNever null; [] when none.","items":{"$ref":"#/components/schemas/provider.githubInstallationView"},"type":"array"}},"type":"object"},"provider.githubPagesBuildOut":{"properties":{"repo":{"description":"Repo is the repository the build was queued for.","type":"string"},"status":{"description":"Status is GitHub's build state at the moment it was queued (\"queued\").","type":"string"},"url":{"description":"URL is GitHub's API URL for the build, for polling it there.","type":"string"}},"type":"object"},"provider.githubPagesDisabledOut":{"properties":{"disabled":{"description":"Disabled is always true — a failure is an HTTP error, never this shape.","type":"boolean"},"repo":{"description":"Repo is the repository whose site was deleted.","type":"string"}},"type":"object"},"provider.githubPagesEnableReq":{"properties":{"branch":{"description":"Branch is the legacy source branch; empty defaults to the repo's own default\nbranch. Ignored when buildType is \"workflow\".","type":"string"},"buildType":{"description":"BuildType selects the builder: \"workflow\" builds via GitHub Actions, anything\nelse builds from the branch source above.","type":"string"},"path":{"description":"Path is the source directory within the branch: \"/\" (the default) or \"/docs\".\nGitHub allows no others.","type":"string"},"repo":{"description":"Repo is the repository, from the :repo path segment.","type":"string"}},"type":"object"},"provider.githubPagesSource":{"properties":{"branch":{"description":"Branch is the branch the site builds from.","type":"string"},"path":{"description":"Path is the directory within that branch: \"/\" or \"/docs\".","type":"string"}},"type":"object"},"provider.githubPagesUpdateReq":{"properties":{"branch":{"description":"Branch switches the legacy source branch. Empty leaves the source alone.","type":"string"},"buildType":{"description":"BuildType switches the builder: \"legacy\" or \"workflow\". Empty leaves it.","type":"string"},"cname":{"description":"CNAME is the custom domain. Omit to leave it alone, \"\" to clear it, or a\nvalid FQDN to set it.","type":"string"},"httpsEnforced":{"description":"HTTPSEnforced toggles GitHub's enforce-HTTPS bit. Omit to leave it alone.","type":"boolean"},"path":{"description":"Path is the source directory to pair with Branch: \"/\" (the default) or\n\"/docs\". Read only when Branch is given.","type":"string"},"repo":{"description":"Repo is the repository, from the :repo path segment.","type":"string"}},"type":"object"},"provider.githubPagesUpdatedOut":{"properties":{"repo":{"description":"Repo is the repository that was updated.","type":"string"},"updated":{"description":"Updated is always true — a failure is an HTTP error, never this shape.","type":"boolean"}},"type":"object"},"provider.githubPagesView":{"properties":{"buildType":{"description":"BuildType is the builder in use: \"legacy\" (branch source) or \"workflow\".","type":"string"},"cname":{"description":"CNAME is the custom domain, absent when none is set.","type":"string"},"custom404":{"description":"Custom404 is whether the repo ships its own 404 page.","type":"boolean"},"httpsEnforced":{"description":"HTTPSEnforced is GitHub's enforce-HTTPS bit.","type":"boolean"},"repo":{"description":"Repo is the repository the site belongs to.","type":"string"},"source":{"$ref":"#/components/schemas/provider.githubPagesSource","description":"Source is the branch + path the site builds from. Absent under \"workflow\"."},"status":{"description":"Status is GitHub's build state: \"built\", \"building\" or \"errored\". Absent\nbefore the first build.","type":"string"},"url":{"description":"URL is the live site (GitHub's html_url).","type":"string"}},"type":"object"},"provider.githubRepoItem":{"properties":{"codebase":{"description":"Codebase is the name it has in the org's code workspace once brought in\n(POST /v1/provider/github/repos/import): listed by GET /v1/git/repos when\nit is there.","type":"string"},"default_branch":{"description":"DefaultBranch is the branch GitHub opens it on.","type":"string"},"full_name":{"description":"FullName is owner/name, the address a coding run, a branch listing and a\ndeploy take.","type":"string"},"installation_id":{"description":"InstallationID is the installation of the Hanzo Platform App that reaches\nit — the grant a run on it is minted from.","format":"int64","type":"integer"},"name":{"description":"Name is its name within that account.","type":"string"},"owner":{"description":"Owner is the GitHub account that holds it.","type":"string"},"private":{"description":"Private is GitHub's visibility bit.","type":"boolean"},"pushed_at":{"description":"PushedAt is when anything was last pushed to it, RFC 3339 UTC. Absent for a\nrepository nothing was ever pushed to.","type":"string"}},"type":"object"},"provider.githubReposOut":{"properties":{"connected":{"description":"Connected is whether this answer is the caller's OWN GitHub. False with\nrepositories is an org admin seeing the org's installations; false with none\nis the cue to connect.","type":"boolean"},"next":{"description":"Next is the cursor for the page after this one; empty on the last page.","type":"string"},"repos":{"description":"Repos is this page, most recently pushed first. Never null.","items":{"$ref":"#/components/schemas/provider.githubRepoItem"},"type":"array"},"total":{"description":"Total is how many repositories match q and owner, across every page.","format":"int64","type":"integer"},"unread":{"description":"Unread names the installations that could not be read, so a short list is\ndistinguishable from a complete one. Absent when the answer is whole.","items":{"type":"string"},"type":"array"}},"type":"object"},"provider.githubSearchHit":{"properties":{"clone_url":{"description":"CloneURL is the repository's https git remote.","type":"string"},"default_branch":{"description":"DefaultBranch is the branch a clone checks out.","type":"string"},"description":{"description":"Description is the blurb the repository's owner wrote. Empty when it has none.","type":"string"},"full_name":{"description":"FullName is the repository's \"owner/repo\" on GitHub. Finding it here does\nNOT make it forkable: githubFork takes a repo the org's installation was\ngranted, and a hit from the public index usually is not one.","type":"string"},"html_url":{"description":"HTMLURL is the repository's page on github.com.","type":"string"},"language":{"description":"Language is the primary language GitHub detected from the file mix (\"Go\",\n\"TypeScript\"). Empty when GitHub attributes none.","type":"string"},"private":{"description":"Private is GitHub's visibility flag, passed through. This op reads the\npublic index — the org's token only charges the rate limit to the\ninstallation — so it is false for everything a search can reach.","type":"boolean"},"stars":{"description":"Stars is GitHub's stargazers_count as the SEARCH INDEX held it when the\nquery ran — a snapshot, not a live count off the repository.","format":"int64","type":"integer"}},"type":"object"},"provider.githubSearchOut":{"properties":{"count":{"description":"Count is how many hits Repos carries. It is that array's length, NOT\nGitHub's total_count, so it never exceeds limit and says nothing about how\nmany more repositories matched.","format":"int64","type":"integer"},"repos":{"description":"Repos are the matching repositories in GitHub's own relevance order, capped\nat limit. Always an array, never null.","items":{"$ref":"#/components/schemas/provider.githubSearchHit"},"type":"array"}},"type":"object"},"provider.githubSearchReq":{"properties":{"limit":{"description":"Limit caps the answer; 0 takes the default and anything above the ceiling\nis clamped rather than refused.","format":"int64","type":"integer"},"q":{"description":"Q is GitHub's own search syntax, passed through: \"tetris language:go\",\n\"org:hanzoai stars:\u003e10\". Passing it through rather than inventing a\nvocabulary means one thing to learn, and it is theirs.","type":"string"}},"type":"object"},"provider.githubUserCompleteIn":{"properties":{"grant":{"description":"Grant is the id the callback handed the console in its redirect. It is\nsingle-use, lives ten minutes, and is readable only by the person who\nstarted the flow.","type":"string"}},"type":"object"},"provider.githubUserConnectIn":{"properties":{"return":{"description":"Return is the page the callback sends the person back to, with\ncomplete=github\u0026grant=\u003cid\u003e (or error=github\u0026reason=\u003cwhy\u003e) added to its\nquery. It must name one of this deployment's return pages (on\napi.hanzo.ai: https://hanzo.ai/?at=-/settings/integrations,\nhttps://console.hanzo.ai/connectors, https://platform.hanzo.ai/connectors);\nanything else, or nothing, returns to the console's /connectors.","type":"string"}},"type":"object"},"provider.githubUserConnectOut":{"properties":{"authorizeUrl":{"description":"AuthorizeURL is GitHub's authorization page for the App. GitHub returns the\nbrowser to the callback, which parks the answer and sends it on with\ncomplete=github\u0026grant=\u003cid\u003e — to the return page the connect named, or the\nconsole's /connectors — and that page POSTs the grant to\n/v1/provider/github/user/complete.","type":"string"}},"type":"object"},"provider.githubUserDisconnectOut":{"properties":{"disconnected":{"description":"Disconnected is always true: the sealed token and the connection are gone\nfrom this deployment. A custody failure is an HTTP error instead.","type":"boolean"},"revoked":{"description":"Revoked is whether GitHub confirmed the token is dead. False means GitHub\ncould not be told — the token lives until it expires or is revoked from\nthe person's GitHub settings — or there was no token to revoke.","type":"boolean"}},"type":"object"},"provider.githubUserOut":{"properties":{"configured":{"description":"Configured is whether this deployment holds the App's OAuth client. False\nmeans nobody can connect here yet, and connect answers 503.","type":"boolean"},"connected":{"description":"Connected is whether the caller has connected their own GitHub account in\nthis org. False means their repositories come from nowhere: an org admin\nstill sees the org's installations, and everyone else is asked to connect.","type":"boolean"},"connectedAt":{"description":"ConnectedAt is when the connection was made, RFC 3339 UTC.","type":"string"},"expiresAt":{"description":"ExpiresAt is when the current access token expires, RFC 3339 UTC. It is\nrotated before it does; absent for a token GitHub does not expire.","type":"string"},"login":{"description":"Login is the GitHub account they connected. Absent when not connected.","type":"string"}},"type":"object"},"provider.gitlabProjectView":{"properties":{"cloneUrl":{"description":"CloneURL is the https remote to clone.","type":"string"},"defaultBranch":{"description":"DefaultBranch is the branch a clone lands on (\"main\" when GitLab names none,\nwhich is what an empty project reports).","type":"string"},"description":{"description":"Description is the project's own, empty when it has none.","type":"string"},"fullName":{"description":"FullName is the namespace path (\"acme/widgets\", \"acme/team/widgets\" for a\nsubgroup) — the string GitLab calls path_with_namespace.","type":"string"},"htmlUrl":{"description":"HTMLURL is the project's page.","type":"string"},"name":{"description":"Name is the project's path segment (\"widgets\"), not its display name.","type":"string"},"private":{"description":"Private is true for anything not publicly visible (private or internal).","type":"boolean"},"pushedAt":{"description":"PushedAt is RFC3339 last activity, so a client can sort or say \"2h ago\".","type":"string"}},"type":"object"},"provider.gitlabProjectsOut":{"properties":{"account":{"description":"Account is the connected GitLab username, so a client can label the list\nwithout a second call. Empty when the connection recorded none.","type":"string"},"projects":{"description":"Projects is every project the token reaches, newest activity first. Never\nnull; [] when the account has none.","items":{"$ref":"#/components/schemas/provider.gitlabProjectView"},"type":"array"}},"type":"object"},"provider.googleUserCompleteIn":{"properties":{"grant":{"description":"Grant is the id the callback handed the page in its redirect. It is\nsingle-use, lives ten minutes, and is readable only by the person who\nstarted the flow.","type":"string"}},"type":"object"},"provider.googleUserConnectIn":{"properties":{"return":{"description":"Return is the page the callback sends the person back to, with\ncomplete=google\u0026grant=\u003cid\u003e (or error=google\u0026reason=\u003cwhy\u003e) added to its\nquery. It must name one of this deployment's return pages; anything else,\nor nothing, returns to the console's /connectors.","type":"string"}},"type":"object"},"provider.googleUserConnectOut":{"properties":{"authorizeUrl":{"description":"AuthorizeURL is Google's consent page. Google returns the browser to the\ncallback, which parks the answer and sends it on with\ncomplete=google\u0026grant=\u003cid\u003e — to the return page the connect named, or the\nconsole's /connectors — and that page POSTs the grant to\n/v1/provider/google/user/complete.","type":"string"}},"type":"object"},"provider.googleUserDisconnectOut":{"properties":{"disconnected":{"description":"Disconnected is always true: the sealed tokens and the connection are gone\nfrom this deployment. A custody failure is an HTTP error instead.","type":"boolean"},"revoked":{"description":"Revoked is whether Google confirmed the grant is dead. False means Google\ncould not be told — the grant lives until the person removes it from their\nGoogle account — or there was nothing to revoke.","type":"boolean"}},"type":"object"},"provider.googleUserOut":{"properties":{"configured":{"description":"Configured is whether this deployment holds the OAuth client. False means\nnobody can connect here yet, and connect answers 503.","type":"boolean"},"connected":{"description":"Connected is whether the caller has connected their own Google account in\nthis org.","type":"boolean"},"connectedAt":{"description":"ConnectedAt is when the connection was made, RFC 3339 UTC.","type":"string"},"email":{"description":"Email is the Google account they connected: the From of every message sent\nas them. Absent when not connected.","type":"string"},"expiresAt":{"description":"ExpiresAt is when the current access token expires, RFC 3339 UTC. It is\nrotated before it does.","type":"string"},"send":{"description":"Send is whether the grant lets Hanzo send mail as them. A connection is only\nkept when it does, so this is Connected unless the person later narrowed\nthe grant at Google.","type":"boolean"}},"type":"object"},"provider.joinFailure":{"properties":{"channel":{"description":"Channel is Slack's id for the room that refused.","type":"string"},"error":{"description":"Error is Slack's own code, carried through unchanged.","type":"string"},"name":{"description":"Name is that room's human name, so the operator does not have to look the id up.","type":"string"}},"type":"object"},"provider.linearBackfillIn":{"properties":{"state":{"description":"State is the set of issues to walk: \"open\" (the default), \"closed\" or \"all\".","type":"string"}},"type":"object"},"provider.linearBackfillResult":{"properties":{"created":{"description":"Created is how many native issues this pass created.","format":"int64","type":"integer"},"failed":{"description":"Failed is how many issues errored; the pass continues past each.","format":"int64","type":"integer"},"issues":{"description":"Issues is how many Linear issues were seen.","format":"int64","type":"integer"},"truncated":{"description":"Truncated is set when the time budget or the issue cap stopped the pass early.\nRe-run to continue — the mirror is idempotent by ExtRef, so nothing duplicates.","type":"boolean"},"updated":{"description":"Updated is how many existing native issues this pass refreshed.","format":"int64","type":"integer"}},"type":"object"},"provider.linearClaimIn":{"properties":{"secret":{"description":"Secret is the signing secret configured on the webhook in Linear. Claiming\nagain with a new value rotates it.","type":"string"}},"type":"object"},"provider.linearClaimOut":{"properties":{"name":{"description":"Name is the organization's URL key.","type":"string"},"organization":{"description":"Organization is the Linear organization id now bound to this org.","type":"string"},"path":{"description":"Path is the address to configure in Linear, on this deployment's origin.","type":"string"}},"type":"object"},"provider.linearCommentIn":{"properties":{"body":{"description":"Body is the comment, Markdown.","type":"string"},"issue":{"description":"Issue is the issue's identifier (ENG-123) or its id.","type":"string"}},"type":"object"},"provider.linearCommentOut":{"properties":{"id":{"description":"ID is the comment's id in Linear.","type":"string"},"url":{"description":"URL is the comment's address in Linear.","type":"string"}},"type":"object"},"provider.listOut":{"properties":{"providers":{"description":"Providers is the whole catalog. Never null; [] when nothing is registered.","items":{"$ref":"#/components/schemas/provider.providerView"},"type":"array"}},"type":"object"},"provider.oauthBundleIn":{"properties":{"access":{"description":"Access is the access token.","type":"string"},"account":{"description":"Account is the account label the flow reported; sanitized on ingest.","type":"string"},"refresh":{"description":"Refresh is the refresh token. It is sealed and NEVER handed back out.","type":"string"}},"type":"object"},"provider.opView":{"properties":{"description":{"description":"Description says what it does. Only on GET /v1/provider/{provider}.","type":"string"},"displayName":{"description":"DisplayName is what the card calls it.","type":"string"},"name":{"description":"Name is the action's id — what a run or a flow step names.","type":"string"},"props":{"description":"Props are its inputs — what POST /v1/provider/{provider}/run takes as\ninput. Only on GET /v1/provider/{provider}; the list names actions only.","items":{"$ref":"#/components/schemas/provider.PropSpec"},"type":"array"}},"type":"object"},"provider.providerView":{"properties":{"accounts":{"description":"Accounts is every account this org has connected for the provider, each\nwith its own platform id. Tokens never appear here.","items":{"$ref":"#/components/schemas/provider.connectionView"},"type":"array"},"actions":{"description":"Actions are what the connector can be asked to do, by a flow step or an\nagent (POST /v1/provider/{provider}/run when Runnable).","items":{"$ref":"#/components/schemas/provider.opView"},"type":"array"},"app":{"description":"App names the OAuth app registration its sign-in uses (\"GOOGLE\"), for a\nconnector whose sign-in awaits one.","type":"string"},"available":{"description":"Available is whether THIS DEPLOYMENT has the provider's app credentials, so\nconnect can succeed. False renders the card without a working Connect button.","type":"boolean"},"category":{"description":"Category groups the card (\"Communication\", \"Developer\", \"Marketing\").","type":"string"},"checks":{"description":"Checks is whether a pasted credential is checked with the provider before\nit is stored. False means it is sealed on its shape and checked on use.","type":"boolean"},"connected":{"description":"Connected is whether this org has a live connection to the provider.","type":"boolean"},"connection":{"$ref":"#/components/schemas/provider.connectionView","description":"Connection is the connected account's non-secret detail. Absent when the org\nhas no connection; tokens NEVER appear here (they live only in KMS).\nWhen the org holds several accounts, this is the first and Accounts is\nevery one of them."},"description":{"description":"Description is the one-line pitch the console card shows.","type":"string"},"fields":{"description":"Fields is the form a credential connector asks for. Absent otherwise.","items":{"$ref":"#/components/schemas/provider.Field"},"type":"array"},"id":{"description":"ID is the provider's registry id and the :provider path segment (\"slack\").","type":"string"},"kind":{"description":"Kind is how a reader connects it NOW: \"oauth\" (send the browser to the\nprovider), \"credential\" (fill in Fields), \"device\" (enter a code), or\n\"none\" (nothing to connect — ready, or not connectable here; Note says).","type":"string"},"logo":{"description":"Logo is where the connector's logo is served. Absent when it has none.","type":"string"},"modes":{"description":"Modes are the ways this provider can be connected, derived from what it\nactually declares — \"managed\", \"oauth\", \"apikey\", \"device\", \"mcp\". One\nconsole page renders every card from this field rather than carrying a\ntable of its own, which is how a provider added here shows up there\nwithout a second edit.","items":{"type":"string"},"type":"array"},"name":{"description":"Name is the provider's display name (\"Slack\").","type":"string"},"note":{"description":"Note says why the connector cannot be connected here, when it cannot.","type":"string"},"runnable":{"description":"Runnable is whether its actions run on this deployment.","type":"boolean"},"scopes":{"description":"Scopes are the permissions a connection will ask for. Never null.","items":{"type":"string"},"type":"array"},"triggers":{"description":"Triggers are the events a flow can start on.","items":{"$ref":"#/components/schemas/provider.opView"},"type":"array"}},"type":"object"},"provider.refreshOut":{"properties":{"connector":{"$ref":"#/components/schemas/provider.connectionView","description":"Connection is the connector with its new expiry."},"refreshed":{"description":"Refreshed is always true — a failed rotation is an HTTP error.","type":"boolean"}},"type":"object"},"provider.runIn":{"properties":{"action":{"description":"Action is the action's name, as GET /v1/provider/{provider} lists it.","type":"string"},"input":{"additionalProperties":{},"description":"Input is the action's props, by name.","type":"object"},"provider":{"description":"Provider is the connector, from the path.","type":"string"}},"type":"object"},"provider.runOut":{"properties":{"error":{"description":"Error is why the action failed, when it did.","type":"string"},"ok":{"description":"Ok is whether the action ran to completion.","type":"boolean"},"output":{"description":"Output is the action's result when it ran; its shape is the action's own."}},"type":"object"},"provider.slackChannelsOut":{"properties":{"channels":{"description":"Channels contains one page of conversations visible to the bot.","items":{"$ref":"#/components/schemas/provider.slackConversation"},"type":"array"},"next_cursor":{"description":"NextCursor is empty when there are no more pages.","type":"string"}},"type":"object"},"provider.slackConversation":{"properties":{"id":{"description":"ID is the channel ID to pass to message reads and sends.","type":"string"},"is_im":{"description":"IsIM identifies a direct message.","type":"boolean"},"is_member":{"description":"IsMember reports whether Hanzo has joined this channel.","type":"boolean"},"is_mpim":{"description":"IsMPIM identifies a group direct message.","type":"boolean"},"is_private":{"description":"IsPrivate identifies a private channel or conversation.","type":"boolean"},"name":{"description":"Name is the channel name, without #. DMs may have no name.","type":"string"}},"type":"object"},"provider.slackDeleteMessageOut":{"properties":{"channel":{"description":"Channel is the resolved channel ID the message was in.","type":"string"},"ts":{"description":"TS is the deleted message's timestamp, which now addresses nothing.","type":"string"}},"type":"object"},"provider.slackFile":{"properties":{"id":{"description":"ID is the file's Slack ID and the handle the file read takes.","type":"string"},"mimetype":{"description":"Mimetype is the type Slack recorded at upload. It is the uploader's word,\nso it describes the file rather than deciding how the bytes are served.","type":"string"},"name":{"description":"Name is the filename as uploaded.","type":"string"},"permalink":{"description":"Permalink opens the file in Slack, for a person. It needs a Slack session\nand is never the bytes.","type":"string"},"size":{"description":"Size is the file's length in bytes.","format":"int64","type":"integer"},"title":{"description":"Title is the title Slack displays, which may differ from the filename.","type":"string"}},"type":"object"},"provider.slackJoinOut":{"properties":{"already":{"description":"Already counts the channels it was a member of before, kept apart from\nJoined because only one of the two is a change.","format":"int64","type":"integer"},"failed":{"description":"Failed is per-channel, so one refusal does not hide the rest of the walk.","items":{"$ref":"#/components/schemas/provider.joinFailure"},"type":"array"},"joined":{"description":"Joined names the channels this run walked into — the change it made.","items":{"type":"string"},"type":"array"},"listed":{"description":"Listed is every public, unarchived channel the workspace has.","format":"int64","type":"integer"}},"type":"object"},"provider.slackMessage":{"properties":{"bot_id":{"description":"BotID identifies a bot author when present.","type":"string"},"files":{"description":"Files are the files attached to this message. Read one's bytes with\nGET /v1/provider/slack/file?id=\u003cid\u003e; nothing here is the content.","items":{"$ref":"#/components/schemas/provider.slackFile"},"type":"array"},"reply_count":{"description":"ReplyCount indicates whether a parent has replies to fetch separately.","format":"int64","type":"integer"},"subtype":{"description":"Subtype distinguishes messages from channel events.","type":"string"},"text":{"description":"Text is the message in Slack's formatting.","type":"string"},"thread_ts":{"description":"ThreadTS is the parent timestamp for a threaded message.","type":"string"},"ts":{"description":"TS is Slack's exact message timestamp and ID; retain it as a string.","type":"string"},"user":{"description":"User is the author's Slack user ID.","type":"string"}},"type":"object"},"provider.slackMessagesOut":{"properties":{"channel":{"description":"Channel is the resolved channel ID, reusable for further reads and replies.","type":"string"},"has_more":{"description":"HasMore indicates that Slack has additional messages beyond this page.","type":"boolean"},"messages":{"description":"Messages is one page, newest first for history and oldest first for threads.","items":{"$ref":"#/components/schemas/provider.slackMessage"},"type":"array"},"next_cursor":{"description":"NextCursor continues this query; never assume one page is the whole history.","type":"string"}},"type":"object"},"provider.slackReactIn":{"properties":{"channel":{"description":"Channel is a Slack channel ID, name (#hanzo-gtm), or channel mention.","type":"string"},"name":{"description":"Name is the emoji's name WITHOUT colons — \"eyes\", not \":eyes:\".","type":"string"},"ts":{"description":"TS is the exact timestamp of the message to react to.","type":"string"}},"type":"object"},"provider.slackReactOut":{"properties":{"channel":{"description":"Channel is the resolved channel ID the message sits in.","type":"string"},"name":{"description":"Name is the emoji that was added, without colons.","type":"string"},"ts":{"description":"TS is the reacted-to message's exact Slack timestamp.","type":"string"}},"type":"object"},"provider.slackSearchHit":{"properties":{"channel":{"description":"Channel is the conversation ID the match sits in.","type":"string"},"channel_name":{"description":"ChannelName is that conversation's name, when Slack reports one.","type":"string"},"permalink":{"description":"Permalink addresses the message in a browser.","type":"string"},"text":{"description":"Text is the matching message's text.","type":"string"},"ts":{"description":"TS is the message's exact Slack timestamp, the handle for replying to or\nreacting to it.","type":"string"},"user":{"description":"User is the author's Slack user ID.","type":"string"},"username":{"description":"Username is the author's display name, when Slack reports one.","type":"string"}},"type":"object"},"provider.slackSearchIn":{"properties":{"count":{"description":"Count bounds the page, 1-100. Zero means 20.","format":"int64","type":"integer"},"page":{"description":"Page is the 1-based page of results. Zero means the first.","format":"int64","type":"integer"},"query":{"description":"Query is Slack's own search syntax — bare words, or in:#channel,\nfrom:@someone, before:2026-09-01, has:link.","type":"string"}},"type":"object"},"provider.slackSearchOut":{"properties":{"matches":{"description":"Matches are this page's hits, most relevant first.","items":{"$ref":"#/components/schemas/provider.slackSearchHit"},"type":"array"},"page":{"description":"Page is the page these matches came from.","format":"int64","type":"integer"},"pages":{"description":"Pages is how many pages the query has in total.","format":"int64","type":"integer"},"total":{"description":"Total is how many messages matched, across every page.","format":"int64","type":"integer"}},"type":"object"},"provider.slackSendMessageIn":{"properties":{"channel":{"description":"Channel is a Slack channel ID, name (#hanzo-gtm), or Slack channel mention.","type":"string"},"text":{"description":"Text is the message to post as Hanzo, up to 40000 characters.","type":"string"},"thread_ts":{"description":"ThreadTS optionally replies under this parent message's exact ts.","type":"string"}},"type":"object"},"provider.slackSendMessageOut":{"properties":{"channel":{"description":"Channel is the resolved channel ID where the message was posted.","type":"string"},"ts":{"description":"TS is the posted message's exact Slack timestamp.","type":"string"}},"type":"object"},"provider.slackUpdateMessageIn":{"properties":{"channel":{"description":"Channel is a Slack channel ID, name (#hanzo-gtm), or channel mention.","type":"string"},"text":{"description":"Text is the replacement, up to 40000 characters.","type":"string"},"ts":{"description":"TS is the exact timestamp of the message to rewrite.","type":"string"}},"type":"object"},"provider.slackUpdateMessageOut":{"properties":{"channel":{"description":"Channel is the resolved channel ID the message sits in.","type":"string"},"ts":{"description":"TS is the rewritten message's exact Slack timestamp, unchanged by an edit.","type":"string"}},"type":"object"},"provider.tokenOut":{"properties":{"expiresAt":{"description":"ExpiresAt is when this token expires, RFC 3339 UTC; empty if non-expiring.","type":"string"},"label":{"description":"Label is the connector's label.","type":"string"},"provider":{"description":"Provider is the connector's provider id.","type":"string"},"token":{"description":"Token is the access token, rotated first if it was within the refresh window.","type":"string"}},"type":"object"},"provider.userCatalogOut":{"properties":{"providers":{"description":"Providers is every USER-scoped provider, sorted by id. Never null.","items":{"$ref":"#/components/schemas/provider.providerView"},"type":"array"}},"type":"object"},"provider.verifyOut":{"properties":{"account":{"description":"Account is the account label the provider reported. Present only when active.","type":"string"},"active":{"description":"Active is whether the stored credential verified live against the provider.","type":"boolean"},"externalId":{"description":"ExternalID is the provider's account id. Present only when active.","type":"string"},"provider":{"description":"Provider is the connector's registry id.","type":"string"},"reason":{"description":"Reason is why the check failed. Present only when active is false.","type":"string"},"scopes":{"description":"Scopes are the permissions the credential carries. Present only when active.","items":{"type":"string"},"type":"array"}},"type":"object"},"provisioning.provisionRequest":{"properties":{"instance":{"description":"Instance binds a DEDICATED add-on to the app instance whose\n\u003cinstance\u003e-addons Secret receives the \u003cKIND\u003e_URL (e.g. \"commerce\").\nOptional: empty means \"not instance-bound\" — the DSN is returned once and\nwired by the caller.","type":"string"},"name":{"description":"Name is the org-unique slug for the new resource, matching\n^[a-z0-9]([a-z0-9-]{0,38}[a-z0-9])?$. Every physical name derives from it.","type":"string"}},"type":"object"},"provisioning.provisionResult":{"properties":{"connectionString":{"description":"ConnectionString is the ready-to-use DSN, credential included. RETURNED\nHERE ONCE: no read beside this one carries it, so a caller that does not\nkeep it must provision again.","type":"string"},"database":{"description":"Database is the logical database, collection, index or bucket this resource\nresolves to on its backend. It is derived from Name under an org-namespacing\nhash, so it is not Name and two orgs cannot land on one.","type":"string"},"host":{"description":"Host is the address that routes to this resource — a dedicated instance's\nown in-cluster Service, or the public gateway for a shared one. Never the\ninternal admin address of a shared backend.","type":"string"},"id":{"description":"ID is the resource's server-minted handle, \"rs_\"-prefixed. The caller does\nnot choose it, and it is what every read and the delete address.","type":"string"},"kind":{"description":"Kind is the product provisioned: sql, vector, datastore, kv, search, s3 or\ndocdb. It is the route that was called, not a body field.","type":"string"},"name":{"description":"Name is the org-unique slug the caller asked for, lower-cased. Every\nphysical name on the backend derives from it.","type":"string"},"password":{"description":"Password is the minted credential, in plaintext, for the kinds that have\none. RETURNED HERE ONCE — where KMS is configured it is sealed there and\nonly a reference is persisted; where it is not, it is stored nowhere at all.\nIt is never held in plaintext on either side.","type":"string"},"port":{"description":"Port is the port a client connects to on Host.","format":"int64","type":"integer"},"status":{"description":"Status is \"ready\", or \"provisioning\" while a dedicated instance is still\nbeing materialized by the operator. A shared-backend create is \"ready\" here;\na dedicated one answers 201 still launching, and reaches ready only when a\nlater read reconciles it against the operator's live CR — never fabricated.","type":"string"},"username":{"description":"Username is the credential's user, for the kinds that mint one per resource.\nAbsent for a kind whose backend authenticates with a shared, out-of-band key.","type":"string"}},"type":"object"},"provisioning.provisionedResource":{"properties":{"database":{"description":"Database is the logical database, collection, index or bucket this\nresource resolves to on its backend.","type":"string"},"host":{"description":"Host is the address that actually routes to this resource — a dedicated\ninstance's own in-cluster Service, or the public gateway for a shared one.","type":"string"},"id":{"description":"ID is the resource's server-minted handle, \"rs_\"-prefixed.","type":"string"},"kind":{"description":"Kind is the product: sql, vector, datastore, kv, search, s3 or docdb.","type":"string"},"name":{"description":"Name is the org-unique slug the caller provisioned the resource under.","type":"string"},"port":{"description":"Port is the port a client connects to on Host.","format":"int64","type":"integer"},"status":{"description":"Status is \"ready\", or \"provisioning\" while a dedicated instance is still\nbeing materialized. A dedicated resource's status is reconciled from the\noperator's live CR before this is answered, so it is never a stale ready.","type":"string"},"username":{"description":"Username is the credential's user, for the kinds that mint one per\nresource. Absent for a kind whose backend authenticates with a shared,\nout-of-band key.","type":"string"}},"type":"object"},"provisioning.provisionedSummary":{"properties":{"createdAt":{"description":"CreatedAt is when the resource was provisioned, in unix seconds.","format":"int64","type":"integer"},"host":{"description":"Host is the address that actually routes to this resource — a dedicated\ninstance's own in-cluster Service, or the public gateway for a shared one.\nNever the internal admin address of a shared backend.","type":"string"},"id":{"description":"ID is the resource's server-minted handle, \"rs_\"-prefixed.","type":"string"},"kind":{"description":"Kind is the product: sql, vector, datastore, kv, search, s3 or docdb.","type":"string"},"name":{"description":"Name is the org-unique slug the caller provisioned the resource under.","type":"string"},"port":{"description":"Port is the port a client connects to on Host.","format":"int64","type":"integer"},"status":{"description":"Status is \"ready\", or \"provisioning\" while a dedicated instance is still\nbeing materialized by the operator.","type":"string"}},"type":"object"},"pubsub.busAck":{"properties":{"duplicate":{"description":"Duplicate is true when JetStream deduplicated the message by its\nNats-Msg-Id instead of storing it again.","type":"boolean"},"ok":{"description":"OK is true when the bus accepted the message.","type":"boolean"},"seq":{"description":"Seq is the message's sequence in that stream.","format":"uint64","type":"integer"},"stream":{"description":"Stream is the stream that stored the message — absent when no stream\ncaptures the subject and the message went out core (fire-and-forget).","type":"string"}},"type":"object"},"pubsub.busMessage":{"properties":{"data":{"description":"Data is the payload as UTF-8 text.","type":"string"},"headers":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"description":"Headers are the message's headers, when it carries any.","type":"object"},"seq":{"description":"Seq is the message's stream sequence — fetched messages only.","format":"uint64","type":"integer"},"subject":{"description":"Subject is the message's subject in the org's own namespace.","type":"string"},"time":{"description":"Time is when the stream stored the message, RFC3339 — fetched messages\nonly.","type":"string"}},"type":"object"},"pubsub.busPublish":{"properties":{"data":{"description":"Data is the payload, carried verbatim as UTF-8 text (typically JSON).\nBinary payloads belong on the NATS port.","type":"string"},"headers":{"additionalProperties":{"type":"string"},"description":"Headers are optional message headers, one value per name. A Nats-Msg-Id\nheader is JetStream's deduplication key: a repeat within the stream's\ndedup window is acknowledged as duplicate rather than stored twice.","type":"object"},"subject":{"description":"Subject is the subject to publish to, in the org's own namespace — e.g.\norders.created. No wildcards.","type":"string"}},"type":"object"},"pubsub.busRequest":{"properties":{"data":{"description":"Data is the request payload, carried verbatim as UTF-8 text.","type":"string"},"headers":{"additionalProperties":{"type":"string"},"description":"Headers are optional request headers, one value per name.","type":"object"},"subject":{"description":"Subject is the subject a responder listens on, in the org's namespace.","type":"string"},"timeoutMs":{"description":"TimeoutMs bounds the wait for a reply. 0 or less means the default of\n5000; anything above 30000 is clamped to 30000.","format":"int64","type":"integer"}},"type":"object"},"reference.ClearReferenceOut":{"properties":{"cleared":{"description":"Cleared is false when your org held no such override — which is not an\nerror, it is the honest answer to a removal that had nothing to remove.","type":"boolean"},"key":{"description":"Key is the entry named.","type":"string"},"overrides":{"description":"Overrides is how many your org still holds in this set.","format":"int64","type":"integer"},"set":{"description":"Set is the set cleared in.","type":"string"}},"type":"object"},"reference.ReferenceAnswer":{"properties":{"age":{"description":"Age is how old that is, as a duration.","type":"string"},"asOf":{"description":"AsOf is when the oldest contributing publisher was current, RFC 3339.","type":"string"},"from":{"description":"From is override or baseline — which plane answered.","type":"string"},"hit":{"description":"Hit is whether the key is a member. It is meaningful ONLY when Refusal is\nempty: false with a refusal means the set could not be consulted, which is\nnot the same as the key being clean.","type":"boolean"},"key":{"description":"Key is the key as asked.","type":"string"},"matched":{"description":"Matched is the member that covered the key, which for a domain or a network\nis the enclosing entry rather than the key itself.","type":"string"},"refusal":{"description":"Refusal is why the set could not be consulted, when it could not: never\nloaded, held elsewhere, or a source we hold no licence for. Non-empty means\nHit must not be read as an answer.","type":"string"},"score":{"description":"Score is the published risk weight where the source expresses one.","format":"double","type":"number"},"set":{"description":"Set is the set consulted.","type":"string"},"stale":{"description":"Stale is whether the set is past its freshness bound. A stale set still\nanswers — yesterday's list beats none — and this is how a decision knows it\nleaned on one.","type":"boolean"},"value":{"additionalProperties":{"type":"string"},"description":"Value is what the publisher says about the member — class, operator,\nscheme, region.","type":"object"},"verdict":{"description":"Verdict is the tenant's own allow or deny, present only for an override.\nThe baseline never carries one: it states facts and leaves the decision to\nthe caller's policy.","type":"string"},"version":{"description":"Version is the exact baseline version consulted, composed of each\ncontributing publisher and its content digest. It is what makes a decision\nreproducible: an auditor takes this string and knows precisely what was\nconsulted.","type":"string"}},"type":"object"},"reference.ReferenceOut":{"properties":{"next":{"description":"Next is the key to page from, empty when this is the last page.","type":"string"},"overrides":{"description":"Overrides is YOUR org's entries over that baseline, in key order. They are\nheld in your organisation's own store and are not visible to any other.","items":{"$ref":"#/components/schemas/reference.ReferenceOverride"},"type":"array"},"set":{"$ref":"#/components/schemas/reference.ReferenceSet","description":"Set is the published set: its version, its freshness and its sources."}},"type":"object"},"reference.ReferenceOverride":{"properties":{"at":{"description":"At is when it was written, RFC 3339.","type":"string"},"by":{"description":"By is who wrote it.","type":"string"},"key":{"description":"Key is the member this organisation is speaking about.","type":"string"},"note":{"description":"Note is why, in the operator's own words. Optional, and bounded.","type":"string"},"verdict":{"description":"Verdict is allow or deny.","type":"string"}},"type":"object"},"reference.ReferenceOverrideIn":{"properties":{"key":{"description":"Key is the member: a domain, a CIDR or address, an issuer prefix, a\ndevice digest. It is matched the same way the baseline is, so a deny on\ntempbox.example also covers mail.tempbox.example.","type":"string"},"note":{"description":"Note is why, in your own words. Optional, bounded to 512 bytes.","type":"string"},"verdict":{"description":"Verdict is allow or deny, and nothing else. An override is a decision —\nunlike a baseline entry, which states facts and leaves the decision to your\npolicy — because your organisation is the only party entitled to say \"for\nus, this one is fine\".","type":"string"}},"type":"object"},"reference.ReferenceSet":{"properties":{"age":{"description":"Age is how long ago that was.","type":"string"},"asOf":{"description":"AsOf is when the OLDEST contributing publisher was current, RFC 3339. The\noldest and not the newest: a set is exactly as fresh as its weakest source.","type":"string"},"keys":{"description":"Keys is how many members the baseline carries.","format":"int64","type":"integer"},"kind":{"description":"Kind is how the baseline comes to exist: fetch (downloaded from a\npublisher), local (computed here), attest (held by the component that\nscreens against it, freshness reported), or gap (declared and NOT held,\nbecause the source needs a licence we do not have).","type":"string"},"match":{"description":"Match is how a key is tested: exact, domain, net, digits, pattern or range.","type":"string"},"maxAge":{"description":"MaxAge is how old this set may be before it is stale.","type":"string"},"overrides":{"description":"Overrides is how many entries YOUR org has laid over this baseline.","format":"int64","type":"integer"},"refusal":{"description":"Refusal names why the set cannot be relied on, when it cannot: never\nloaded, held elsewhere, or a licence we do not hold. Non-empty means a\nlookup against this set will not answer, rather than answering clean.","type":"string"},"set":{"description":"Set is the name this set is addressed by.","type":"string"},"sources":{"description":"Sources is each contributing publisher, its licence and its own freshness.","items":{"$ref":"#/components/schemas/reference.ReferenceSource"},"type":"array"},"stale":{"description":"Stale is whether it is past that bound. A stale set still answers and says\nso, because yesterday's list beats none.","type":"boolean"},"version":{"description":"Version is the exact baseline consulted — every contributing publisher and\nits content digest. A decision records this and an auditor resolves it back.","type":"string"},"what":{"description":"What the set holds, in one sentence.","type":"string"}},"type":"object"},"reference.ReferenceSetsOut":{"properties":{"refused":{"description":"Refused names the sets that cannot be consulted at all. A key checked\nagainst one of these is UNKNOWN, not clean.","items":{"type":"string"},"type":"array"},"sets":{"description":"Sets is the whole catalog, in a stable order.","items":{"$ref":"#/components/schemas/reference.ReferenceSet"},"type":"array"},"stale":{"description":"Stale names the sets past their freshness bound — the list to alarm on.","items":{"type":"string"},"type":"array"}},"type":"object"},"reference.ReferenceSource":{"properties":{"asOf":{"description":"AsOf is when this publisher was current, RFC 3339.","type":"string"},"basis":{"description":"Basis is the KIND of permission this publisher's data reaches you under:\nlicence (an explicit grant), registry (the registry of record publishing for\nanyone to consult), operator (an operator's own machine-readable statement\nabout its own network, published for third parties to filter by — not a\nlicence, and not claimed as one), own (computed here), or none (nothing\nreaches you: the membership is held by the component that screens against\nit). It is on the wire so the licence position is an audit you can run.","type":"string"},"keys":{"description":"Keys is how many members this publisher contributed.","format":"int64","type":"integer"},"origin":{"description":"Origin is exactly where it was taken from, so it can be taken again.","type":"string"},"refusal":{"description":"Refusal is why this publisher's last take failed, if it did. The set keeps\nits previous version of this source and ages out visibly rather than\nsilently shrinking.","type":"string"},"source":{"description":"Source is the publisher.","type":"string"},"terms":{"description":"Terms is the CITATION that basis points at — the licence identifier, the\nregistry, or the operator publication. A source with no stated terms is not\nin the catalog.","type":"string"},"version":{"description":"Version is the content digest of what this publisher last supplied. Two\nrefreshes that agree on it took the same data.","type":"string"}},"type":"object"},"reference.ReferenceVersion":{"properties":{"asOf":{"description":"AsOf is when the oldest of them was current, RFC 3339.","type":"string"},"refusal":{"description":"Refusal is why it could not be consulted, when it could not.","type":"string"},"set":{"description":"Set is the name the consulted set is addressed by.","type":"string"},"stale":{"description":"Stale is whether it is past its freshness bound.","type":"boolean"},"version":{"description":"Version is every contributing publisher and its content digest.","type":"string"}},"type":"object"},"reference.ResolveReferenceIn":{"properties":{"keys":{"description":"Keys are the values to look up, at most 100 per call: email addresses or\ndomains, IP addresses, card prefixes, user-agent strings, autonomous system\nnumbers, device digests.","items":{"type":"string"},"type":"array"},"sets":{"description":"Sets narrows which sets to consult. Empty consults every set whose matcher\ncan read the keys given.","items":{"type":"string"},"type":"array"}},"type":"object"},"reference.ResolveReferenceOut":{"properties":{"answers":{"description":"Answers is one entry per (set, key) consulted.","items":{"$ref":"#/components/schemas/reference.ReferenceAnswer"},"type":"array"},"consulted":{"description":"Consulted names the version of every set that took part, so a decision can\nrecord precisely what it leaned on. Record this with the decision: it is\nwhat makes the decision reproducible a year later.","items":{"$ref":"#/components/schemas/reference.ReferenceVersion"},"type":"array"},"refused":{"description":"Refused names the consulted sets that could not answer at all. A key that\nmissed in one of these is UNKNOWN, not clean.","items":{"type":"string"},"type":"array"},"stale":{"description":"Stale names the consulted sets past their freshness bound. Staleness is\nitself a risk signal — a decision taken against a three-week-old list is a\nweaker decision, and this is how it knows.","items":{"type":"string"},"type":"array"}},"type":"object"},"reference.SetReferenceIn":{"properties":{"entries":{"description":"Entries are the overrides to write, up to 1000 per call.","items":{"$ref":"#/components/schemas/reference.ReferenceOverrideIn"},"type":"array"}},"type":"object"},"reference.SetReferenceOut":{"properties":{"overrides":{"description":"Overrides is how many your org now holds in this set.","format":"int64","type":"integer"},"set":{"description":"Set is the set written in.","type":"string"},"written":{"description":"Written is how many entries this call wrote.","format":"int64","type":"integer"}},"type":"object"},"referral.claimRequest":{"properties":{"code":{"description":"Code is the referrer's referral code, as it appeared in their ?ref= link.\nCase and surrounding whitespace do not matter.","type":"string"},"invite":{"description":"Invite is the beta invite the referee's link carried (its utm_content),\nwhen it carried one. Optional; it only lets the referrer's invite be marked\njoined, and never changes who the referral credits.","type":"string"}},"type":"object"},"referral.claimView":{"properties":{"code":{"description":"Code is the referral code the referral was recorded against.","type":"string"},"created":{"description":"Created is true when this call recorded the referral and false when it found\none already recorded for this referee — the idempotent replay.","type":"boolean"},"createdAt":{"description":"CreatedAt is when the referral was first recorded, as a Unix timestamp.","format":"int64","type":"integer"},"id":{"description":"ID is the referral's handle.","type":"string"},"status":{"description":"Status is the referral's lifecycle state: \"signup\" until the referee\nmakes metered spend, then \"qualified\", then \"credited\".","type":"string"}},"type":"object"},"referral.myReferralView":{"properties":{"createdAt":{"description":"CreatedAt is when the referral was recorded, as a Unix timestamp.","format":"int64","type":"integer"},"id":{"description":"ID is the referral's handle.","type":"string"},"qualifiedAt":{"description":"QualifiedAt is when the referee first made metered spend, as a Unix\ntimestamp; 0 while the referral is still pending.","format":"int64","type":"integer"},"referee":{"description":"Referee is the org that signed up with my code.","type":"string"},"status":{"description":"Status is the referral's lifecycle state: \"signup\" until the referee makes\nmetered spend, then \"qualified\".","type":"string"}},"type":"object"},"referral.myReferrals":{"properties":{"code":{"description":"Code is the org's STABLE referral code — a deterministic function of the org\nid, so it never changes and never has to be stored to be reproduced.","type":"string"},"counts":{"$ref":"#/components/schemas/referral.statusCounts","description":"Counts tallies this org's referrals by status."},"link":{"description":"Link is the shareable signup link carrying the code, on the brand's own host.","type":"string"},"referrals":{"description":"Referrals is one row per org that signed up with this code.","items":{"$ref":"#/components/schemas/referral.myReferralView"},"type":"array"}},"type":"object"},"referral.setCodeRequest":{"properties":{"code":{"description":"Code is the custom referral code to assign to the caller's org (2-32 uppercase alphanumeric, hyphen, or underscore characters).","type":"string"}},"type":"object"},"referral.statusCounts":{"properties":{"qualified":{"description":"Qualified is how many referees have made metered spend.","format":"int64","type":"integer"},"signup":{"description":"Signup is how many referees have signed up but not yet spent.","format":"int64","type":"integer"},"total":{"description":"Total is every referral this org has made.","format":"int64","type":"integer"}},"type":"object"},"registry.registryImage":{"properties":{"name":{"description":"Name is the repository name inside the org's namespace (e.g. \"cloud\").","type":"string"},"ref":{"description":"Ref is the full pullable reference (host + org + name) the docker CLI\ntakes verbatim.","type":"string"}},"type":"object"},"registry.registryImageList":{"properties":{"data":{"description":"Data is the org's repositories.","items":{"$ref":"#/components/schemas/registry.registryImage"},"type":"array"},"truncated":{"description":"Truncated is true when the catalog walk hit its page bound before the\nregistry was exhausted — the list is a prefix, not the whole.","type":"boolean"}},"type":"object"},"registry.registryMint":{"properties":{"image":{"description":"Image is the repository name inside the org's namespace (e.g. \"cloud\").","type":"string"}},"type":"object"},"registry.registryPackage":{"properties":{"description":{"description":"Description says what the package is, as published.","type":"string"},"name":{"description":"Name is the package name (`\u003corg\u003e` or `@\u003corg\u003e/…`).","type":"string"},"updated":{"description":"Updated is when the package last changed, as the registry reports it.","type":"string"},"version":{"description":"Version is the latest published version.","type":"string"}},"type":"object"},"registry.registryPackageList":{"properties":{"data":{"description":"Data is the packages in the org's scope.","items":{"$ref":"#/components/schemas/registry.registryPackage"},"type":"array"}},"type":"object"},"registry.registryProject":{"properties":{"images":{"description":"Images is how many of the org's repositories the OCI catalog holds.","format":"int64","type":"integer"},"packages":{"description":"Packages is how many of the org's packages the npm registry reports.","format":"int64","type":"integer"},"project":{"description":"Project is the namespace: the org's slug, which prefixes its image names\nand scopes its npm packages.","type":"string"}},"type":"object"},"registry.registryProjectList":{"properties":{"data":{"description":"Data is the namespaces visible to the caller.","items":{"$ref":"#/components/schemas/registry.registryProject"},"type":"array"}},"type":"object"},"registry.registryStatus":{"properties":{"host":{"description":"Host is the OCI registry host clients push to and pull from.","type":"string"},"oci":{"description":"Oci is true when the OCI registry answered its /v2/ probe.","type":"boolean"},"pkg":{"description":"Pkg is true when the npm registry answered its ping.","type":"boolean"},"pkgHost":{"description":"PkgHost is the npm registry host.","type":"string"},"realm":{"description":"Realm is the token endpoint the OCI registry's challenge advertises,\npresent only when the registry is reachable and auth-gated.","type":"string"},"service":{"description":"Service is the token service name from the same challenge.","type":"string"}},"type":"object"},"registry.registryTagList":{"properties":{"data":{"description":"Data is the tag names, as the registry reports them.","items":{"type":"string"},"type":"array"},"image":{"description":"Image is the repository name inside the org's namespace.","type":"string"},"ref":{"description":"Ref is the full repository reference the tags belong to.","type":"string"}},"type":"object"},"registry.registryToken":{"properties":{"expires":{"description":"Expires is the token's lifetime in seconds.","format":"int64","type":"integer"},"ref":{"description":"Ref is the one repository reference the token can pull.","type":"string"},"token":{"description":"Token is the bearer to present on the OCI wire\n(`Authorization: Bearer …` against the host's /v2/ routes).","type":"string"}},"type":"object"},"replayBody":{"properties":{"consent":{},"distinctId":{"type":"string"},"events":{"items":{},"type":"array"},"sessionId":{"type":"string"},"windowId":{"type":"string"}},"type":"object"},"risk.riskAdoptIn":{"properties":{"address":{"description":"Address is one of YOUR organisation's own published values (GET\n/v1/risk/state reports them, and a search reports the one it fitted for you).\nAn address your organisation has not published is NOT FOUND — including one\nanother organisation published, because an address names a value and never\nauthorises reading it.","type":"string"}},"type":"object"},"risk.riskAggregates":{"properties":{"bound":{"description":"Bound is the most they can hold. It is a per-organisation bound: at it, this\norganisation degrades and no other one notices.","format":"int64","type":"integer"},"forgotten":{"description":"Forgotten is how many of its own subjects have been dropped to stay inside\nthat bound. Each one reads as inactive until it is active again.","format":"int64","type":"integer"},"saturated":{"description":"Saturated is whether the bound is binding right now. The two counts are its\nevidence; this is the state to act on.","type":"boolean"},"subjects":{"description":"Subjects is how many of this organisation's subjects the aggregates hold.","format":"int64","type":"integer"}},"type":"object"},"risk.riskAppetiteIn":{"properties":{"live":{"description":"Live turns the model out of shadow. It defaults to FALSE on every call, so\ngoing live is always an explicit act and never a side effect of changing a\nnumber.\n\nSetting it requires an ADMIN of this organisation. Arming decides whether the\nmodel may change an outcome at all — a payment frozen, a grant refused — for\nevery customer this organisation has, which is a governance act rather than a\ntuning one. Stating the appetite and the sample needs no admin.","type":"boolean"},"review":{"description":"Review is the share of the stream that may be sent for examination, in\n(0, 0.5]. The alert threshold is derived from it as a quantile of the scores\nactually observed, so the level is governed rather than tuned.","format":"double","type":"number"},"sample":{"description":"Sample is the share of below-the-line events retained for review, in\n[0, 1]. It is the instrument that measures what the model missed; there are\nno labels, so nothing else can.","format":"double","type":"number"}},"type":"object"},"risk.riskBand":{"properties":{"day":{"description":"Day is the day the band covers.","format":"date-time","type":"string"},"dim":{"description":"Dim is the dimension, named as this API publishes it.","type":"string"},"kind":{"description":"Kind is the subject kind it was computed over.","type":"string"},"n":{"description":"N is how many subject-days went into it.","format":"uint64","type":"integer"},"orgs":{"description":"Orgs is how many organisations contributed, each weighted exactly one vote\nwhatever its size. It is published so a reader can judge the band rather\nthan trust it.","format":"uint32","type":"integer"},"q10":{"description":"Q10 is the quiet end of the network's day: a tenth of contributing\norganisations sit at or below it.","format":"double","type":"number"},"q50":{"description":"Q50 is the network's median day.","format":"double","type":"number"},"q90":{"description":"Q90 is the busy end: a tenth of contributing organisations sit at or above\nit. It is the highest level published.","format":"double","type":"number"}},"type":"object"},"risk.riskCatalog":{"properties":{"gap":{"description":"Gap says why a lens could not be measured, when that is the case. Each\nreason names its own lens, because \"the surface is unreadable\" and \"the\nnetwork baseline is unreadable\" are different facts.","type":"string"},"model":{"description":"Model is the governed inventory: one entry per dimension of the model\nspace, each carrying the typology it serves and the published standard that\nasks for it. It is the same for every organisation, because it is the\nmodel's shape.","items":{"$ref":"#/components/schemas/risk.riskModelFeature"},"type":"array"},"network":{"description":"Network is the published cross-organisation baseline over the same window,\nso the surface above has something to be read AGAINST. It is the same for\nevery caller and it names nobody.\n\nIt carries no tenant and cannot be made to: the table it reads has no org\ncolumn, every figure is a quantile over at least kAnonOrgs organisations\nweighted one vote each, and a band that does not meet that floor is dropped\non the way out.","items":{"$ref":"#/components/schemas/risk.riskBand"},"type":"array"},"surface":{"description":"Surface is what this organisation's own event surface carries, per\ndimension, measured over the window. A dimension present in no bucket is\nblind here — the model reads its neutral value and a reviewer has to be able\nto see that.","items":{"$ref":"#/components/schemas/risk.riskOrgFeature"},"type":"array"},"tenant":{"description":"Tenant is whose surface was measured.","type":"string"}},"type":"object"},"risk.riskCause":{"properties":{"baseline":{"description":"Baseline is the number it was measured against — always this\norganisation's own history, never a fixed limit and never another\norganisation's.","format":"double","type":"number"},"citation":{"description":"Citation is where those words come from, so the claim is checkable rather\nthan asserted — which is what a chargeback network or a regulator asks for.","type":"string"},"feature":{"description":"Feature is the dimension that contributed.","type":"string"},"indicator":{"description":"Indicator is the supervisor's own words for the thing being looked for.","type":"string"},"observed":{"description":"Observed is the raw number the coordinate was computed from.","format":"double","type":"number"},"severity":{"description":"Severity is how much weight this dimension carries.","type":"string"},"share":{"description":"Share is this feature's part of the score, in [0,1]. Zero across every\ncause means no single feature accounts for the alert and the combination\ndoes; the causes are then ordered by how far each sits from unremarkable.","format":"double","type":"number"},"typology":{"description":"Typology is the laundering or abuse pattern this dimension detects.","type":"string"},"unit":{"description":"Unit is how to read Observed, which is what turns a coordinate into a\nsentence.","type":"string"},"without":{"description":"Without is the score the same event would have received with this\ncoordinate at its neutral value — the counterfactual itself.","format":"double","type":"number"}},"type":"object"},"risk.riskEvent":{"properties":{"at":{"description":"At is when it happened, RFC 3339. Empty means now. It must sit inside the\nthirty-day window the aggregates keep and no more than two minutes ahead of\nthis plane's clock; anything outside that is REFUSED rather than quietly\naccepted, because a future timestamp moves the aggregates' leading edge and\nleaves every later event for that subject reading as though it never\nhappened. History older than the window is folded in from your own event\nsurface, not through this endpoint.","type":"string"},"device":{"description":"Device is the device fingerprint, if any. It is the axis that surfaces\nseveral nominally unrelated subjects acting as one.","type":"string"},"id":{"description":"ID is the caller's own stable identifier for the event. It selects the\nbelow-the-line review sample by hash, so a counter would make the sample\nsteerable — use the id the event already has.","type":"string"},"kind":{"description":"Kind is whose behaviour this is: person, session or account. It namespaces\nthe subject, so a person and an account that share an identifier stay two\nsubjects.","type":"string"},"nano":{"description":"Nano is the value moved, in nano-USD. Omit it for an event that moves no\nmoney: the value features then read BLIND rather than being told the amount\nwas zero, and the difference is reported on the model state.","format":"int64","type":"integer"},"peer":{"description":"Peer is the counterparty, if any. It is an aggregation axis of its own —\n\"unfamiliar\" is a fact about a relationship and not about either party.","type":"string"},"subject":{"description":"Subject is the identifier on that kind.","type":"string"}},"type":"object"},"risk.riskLearnIn":{"properties":{"events":{"description":"Events are the things that happened, oldest first. An empty batch is\nrefused: learning nothing is not an operation.","items":{"$ref":"#/components/schemas/risk.riskEvent"},"type":"array"}},"type":"object"},"risk.riskLearnOut":{"properties":{"learned":{"description":"Learned is how many of the events the model actually learned from, and is\nalso what the call is metered at: one screen per event learned from. It is\nthe batch minus the events already in this organisation's record, so a\nretried batch reports — and is charged — zero.","format":"int64","type":"integer"}},"type":"object"},"risk.riskModelFeature":{"properties":{"blind":{"description":"Blind is how often this dimension took that neutral value for THIS\norganisation.","format":"int64","type":"integer"},"citation":{"description":"Citation is where those words come from, so the claim is checkable rather\nthan asserted.","type":"string"},"indicator":{"description":"Indicator is the supervisor's own words for the thing being looked for.","type":"string"},"name":{"description":"Name is the dimension.","type":"string"},"neutral":{"description":"Neutral is the value the coordinate takes when the data cannot support it.","format":"double","type":"number"},"severity":{"description":"Severity is how much weight an alert on it carries.","type":"string"},"typology":{"description":"Typology is the pattern this dimension detects.","type":"string"},"unit":{"description":"Unit is how to read the raw number, which is what turns a coordinate into a\nsentence an investigator can put in a file.","type":"string"},"window":{"description":"Window is the sliding aggregate it reads.","type":"string"}},"type":"object"},"risk.riskModelState":{"properties":{"aggregates":{"$ref":"#/components/schemas/risk.riskAggregates","description":"Aggregates reports the pressure on this organisation's own sliding\naggregates, and whether they have started forgetting subjects to stay inside\ntheir bound."},"blind":{"additionalProperties":{"format":"int64","type":"integer"},"description":"Blind counts, per feature, how often it took its neutral value for want of\ndata. A feature blind on most traffic is not contributing whatever the\ninventory claims for it.","type":"object"},"cut":{"description":"Cut is the threshold in force, derived from Stated as a quantile of the\nscores actually observed.","format":"double","type":"number"},"descends":{"description":"Descends is the published value the working model grew out of: the newest one\nwhose mass count it has reached or passed. Empty when nothing has been\npublished yet.\n\nIt is DERIVED from the count and never stored, so an instant rollback is right\nfor free — adopting an older value moves the count backward and this answers\nwith that older value, where a stored pointer would be a second fact to keep\nin step. Read with Learned it is also the DRIFT: this model is Descends plus\nhowever many events the two counts differ by.","type":"string"},"disposed":{"description":"Disposed is how many published values retention has taken. It is DERIVED from\nthe lowest surviving sequence, so it cannot drift from what it describes, and\nit is reported because a retention that binds is a fact an operator must be\nable to read rather than a silence.","format":"int64","type":"integer"},"learned":{"description":"Learned is how many events the model has learned from.","format":"int64","type":"integer"},"live":{"description":"Live is false while the model is in shadow — scoring, learning and\nrecording what it WOULD have alerted on, and changing no outcome. Shadow is\nthe default for a new tenant.","type":"boolean"},"policy":{"description":"Policy is the version of the decision regime this model is deciding under,\nfrom your organisation's own policy history (GET /v1/risk/policy). Every\nscore cites it, so it is the join between a past decision and the appetite\nthat produced its threshold. Zero means no regime has ever been stated and\nthe default posture — shadow — is in force.","format":"int64","type":"integer"},"realised":{"description":"Realised is the share that actually was. Reading it beside Stated is what\nmakes the appetite a measured commitment rather than an intention.","format":"double","type":"number"},"refused":{"additionalProperties":{"format":"int64","type":"integer"},"description":"Refused counts events the model would not score, by reason. None of them\nwas examined; a refusal is counted, never silent.","type":"object"},"sample":{"description":"Sample is the share of below-the-line events retained for review, which is\nhow the miss rate is measured rather than assumed.","format":"double","type":"number"},"saturated":{"description":"Saturated means no threshold can honour the stated appetite because too\nmuch of the stream scores in the top bucket, so the model is alerting on\nnothing — the one state that must never be mistaken for quiet.","type":"boolean"},"shape":{"description":"Shape is the model's identity, as `\u003cfamily\u003e:\u003cdigest\u003e`: the KIND of model, and\nthat family's own digest over the inventory in order and the detector's geometry\nparameters. It is what an auditor pins an alert to, because learned state is\nonly meaningful against the space that produced it — and the family leads it\nbecause two families' masses are not fitted differently, they are different\nkinds of number.","type":"string"},"stated":{"description":"Stated is the share of the stream this organisation said may be examined.","format":"double","type":"number"},"surface":{"$ref":"#/components/schemas/risk.riskSurface","description":"Surface reports what of the tenant's OWN event surface has been folded in."},"tenant":{"description":"Tenant is the qualified key the model is held under — the brand whose\nissuer vouched for the caller and the organisation it acts for. It is\nechoed so a reader can see the answer is its own and not a parameter it\npassed.","type":"string"},"values":{"description":"Values is your organisation's own published model values, newest first —\nevery state it deliberately named, each addressed by its own content and\nimmutable. This is what PUT /v1/risk/state/model names, so it is reported\nHERE rather than behind an address of its own: they are part of what a review\nof one model reads, and a list of names is a few hundred bytes.\n\nCompare each one's `shape` with the `shape` above: equal means adopting it\nrestores masses into the space this model already runs, and different means\nadopting it REPLANTS the model into the space that value describes — which is how\nthe shape a search found becomes the shape you are running.\n\nThe working model is NOT in it. Publication is a boundary somebody marked; the\nstate between two boundaries is in-process counters, and calling those a value\nwould be a claim about reproducibility that nothing could honour.","items":{"$ref":"#/components/schemas/risk.riskModelValue"},"type":"array"},"warm":{"description":"Warm is whether that is enough for the model to have an opinion at all.\nBelow it the model declines to score, which is an ordinary state and is not\na clean bill of health.","type":"boolean"}},"type":"object"},"risk.riskModelValue":{"properties":{"address":{"description":"Address names this value by its own content: the model's shape, the geometry\nseed, its position in the window, its threshold, its masses as IEEE-754 bits\nand the fold watermark behind them. Nothing else — no clock, no counter and\ndeliberately NOT the organisation, so an identical model has one name and a\nname is never an authority. Holding another organisation's address resolves\nnothing.","type":"string"},"at":{"description":"At is when it was published, RFC 3339, on the server clock. You do not supply\nit: a record whose date the audited party chose is not a record.","type":"string"},"learned":{"description":"Learned is how many events are behind the masses.","format":"int64","type":"integer"},"sequence":{"description":"Sequence is this value's place in YOUR organisation's own history, from 1 and\ncontiguous until retention disposes of the oldest.","format":"int64","type":"integer"},"shape":{"description":"Shape NAMES the model space the masses are only meaningful against, as\n`\u003cfamily\u003e:\u003cdigest\u003e` — the KIND of model, and that family's own digest over the\nfeature inventory in order and the detector's geometry parameters. Compare it\nwith the `shape` on your model state (GET /v1/risk/state): equal means adopting\nthis value restores masses into the space already running, and different means\nadopting it REPLANTS the model into the space this value describes. That is what\nmakes a searched shape installable.\n\nA DIFFERENT FAMILY IS NOT ADOPTABLE AT ALL, and that is the one difference the\nfamily term makes here: a different geometry in the same family is a replant, and\na different family is a refusal naming both — its masses do not describe your\nmodel in any space.","type":"string"},"warmed":{"description":"Warmed is how far your own event surface had been folded in when this value\nwas published, RFC 3339. It is part of the address because two models with\nidentical masses reached by different routes disagree about what is left to\nfold, and one of them will re-teach history the other will not.","type":"string"}},"type":"object"},"risk.riskOrgFeature":{"properties":{"blind":{"description":"Blind is true when the dimension is present in no bucket at all: this\norganisation's surface does not carry it, and saying so is the difference\nbetween no risk and no data.","type":"boolean"},"buckets":{"description":"Buckets is how many five-minute buckets of this organisation's surface were\nmeasured.","format":"int64","type":"integer"},"max":{"description":"Max is the largest value it reached in the window.","format":"double","type":"number"},"mean":{"description":"Mean is the dimension's average where it was present.","format":"double","type":"number"},"name":{"description":"Name is the dimension as this API publishes it.","type":"string"},"present":{"description":"Present is in how many of them the dimension carried a value at all.","format":"int64","type":"integer"},"source":{"description":"Source names the plane it is rolled up from, so a dimension that reads zero\neverywhere traces to a plane the organisation does not use rather than to a\ndefect.","type":"string"},"unit":{"description":"Unit is how to read the numbers below.","type":"string"}},"type":"object"},"risk.riskPolicyOut":{"properties":{"changes":{"description":"Changes is how many DISTINCT regimes may be adopted per Window. A restatement\nidentical to the regime in force mints no version and is not counted against\nit.","format":"int64","type":"integer"},"disposed":{"description":"Disposed is how many versions retention has taken. It is NOT a silence: a\nhistory bounded on disk must say what it no longer holds, because a decision\nciting a disposed version can no longer be reconstructed from this record.","format":"int64","type":"integer"},"history":{"description":"History is the retained versions, newest first.","items":{"$ref":"#/components/schemas/risk.riskPolicyVersion"},"type":"array"},"retained":{"description":"Retained is how many versions this organisation's history holds at most,\nderived from the byte budget its rows are a multiple of.","format":"int64","type":"integer"},"version":{"description":"Version is the version in force — the one every score currently cites. Zero\nmeans no regime has ever been stated and the default posture, shadow, is in\nforce.","format":"int64","type":"integer"},"window":{"description":"Window is the period Changes is measured over.","type":"string"}},"type":"object"},"risk.riskPolicyVersion":{"properties":{"at":{"description":"At is when it entered force, RFC 3339, from the server clock.","type":"string"},"by":{"description":"By is the identity that stated it, stamped server-side from the validated\nprincipal at the moment it entered force.","type":"string"},"live":{"description":"Live is whether the model was permitted to change an outcome under it.","type":"boolean"},"review":{"description":"Review is the share of the stream the regime states may be examined. The\nthreshold in force is derived from it, which is why a decision is only\ndefensible against the version that produced it.","format":"double","type":"number"},"sample":{"description":"Sample is the share of below-the-line events the regime retains for review.","format":"double","type":"number"},"version":{"description":"Version names this regime in this organisation's history.","format":"int64","type":"integer"}},"type":"object"},"risk.riskPublishOut":{"properties":{"minted":{"description":"Minted is false when your model was ALREADY published under this name and\nnothing was written. Publication is idempotent on the value itself, which is\nwhat a content address is for — publishing at every boundary costs nothing\nrather than being the cheapest way to fill a disk.","type":"boolean"},"tenant":{"description":"Tenant is whose history it entered.","type":"string"},"value":{"$ref":"#/components/schemas/risk.riskModelValue","description":"Value is the published value: its name and what it is, never its masses."}},"type":"object"},"risk.riskScoreIn":{"properties":{"event":{"$ref":"#/components/schemas/risk.riskEvent","description":"Event is the thing to judge. It is judged against the caller's OWN model\nand nothing is learned from it."}},"type":"object"},"risk.riskScoreOut":{"properties":{"alert":{"description":"Alert is whether this would become evidence. It is false in shadow however\nhigh the score.","type":"boolean"},"causes":{"description":"Causes is the per-feature attribution, ordered by contribution. Each is a\nCOUNTERFACTUAL on the model that produced the score — the coordinate moved\nto its neutral value and the event rescored — so the explanation is the\nsame arithmetic the score came from.","items":{"$ref":"#/components/schemas/risk.riskCause"},"type":"array"},"cut":{"description":"Cut is the threshold in force, derived from the stated appetite as a\nquantile of the scores actually observed rather than fixed at a number.","format":"double","type":"number"},"policy":{"description":"Policy is the version of your organisation's decision regime this verdict\nwas reached under, from its own policy history (GET /v1/risk/policy). Cut is\nderived from the appetite that version states, so it is the record that makes\nthis decision reconstructible after the appetite is restated. Zero means no\nregime has ever been stated and the default posture — shadow — was in force.","format":"int64","type":"integer"},"refusal":{"description":"Refusal names why the model declined, when it did.","type":"string"},"score":{"description":"Score is where the event sits in the tenant's own density: 0 where its\nrecent behaviour is densest, 1 where there is none of it.","format":"double","type":"number"},"scored":{"description":"Scored is false when the model declined, and Refusal says which refusal it\nwas: warming, unusable or unidentified. None of them is a clean bill of\nhealth, which is why the refusal is stated rather than rendered as a score\nof zero.","type":"boolean"},"shadow":{"description":"Shadow is whether the model is testing rather than deciding — scoring,\nlearning and recording what it WOULD have alerted on, and changing no\noutcome. It is the default for a model no one has reviewed yet.","type":"boolean"},"shape":{"description":"Shape is the model space this verdict was reached in, as `\u003cfamily\u003e:\u003cdigest\u003e`:\nthe KIND of model, and that family's own digest over your organisation's feature\ninventory in order and the detector's geometry parameters. It is what pins an\nadverse decision to a model — a score is only meaningful against the space that\nproduced it, and without this the only answer to \"which model decided this\" was\n\"the one that was running\", which is not an answer.\n\nThe family leads it because everything after it is one family's arithmetic. Two\nspaces are the same space only if they are the same family, so comparing this\nwith the `shape` on your model state or on a published value is a comparison\nthat holds ACROSS families and not only inside one.\n\nIt names the SPACE, not the learned state, and that is deliberate. The masses\nat the instant of a score are in-process counters somewhere between two\npublished values, so citing a published address here would claim that value\nproduced this score — true only for the score taken the instant after a\npublication. This, the policy version and the event's own time are what IS\ntrue, and the published history's clock (GET /v1/risk/state) brackets the\ndecision between two named values from there.","type":"string"},"values":{"description":"Values is every coordinate, including the ones that contributed nothing, so\na reviewer sees what the model read and not only what it concluded.","items":{"$ref":"#/components/schemas/risk.riskValue"},"type":"array"}},"type":"object"},"risk.riskSearchIn":{"properties":{"days":{"description":"Days is how much of the organisation's own history to replay, 1 to 400.\nZero takes thirty.","format":"int64","type":"integer"}},"type":"object"},"risk.riskSearchReport":{"properties":{"done":{"description":"Done is false while the run is still going; the trials below are then the\nones finished so far.","type":"boolean"},"ended":{"description":"Ended is when it finished, RFC 3339. Absent while it is still going.","type":"string"},"events":{"description":"Events is how much of this organisation's history was replayed.","format":"int64","type":"integer"},"fitted":{"$ref":"#/components/schemas/risk.riskModelValue","description":"Fitted is the winning shape FITTED over your own history and published as one of\nyour organisation's own model values. Name its address on PUT\n/v1/risk/state/model and the winning shape becomes the model you are running.\n\nIt is why this op answers something you can act on. A trial keeps counts and not\nthe model that produced them, so a report without this named a shape nobody could\ninstall — and the adoption path refused a shape change besides. Fitting the winner\nonce is a sixty-fifth pass over the same history; keeping all sixty-four fitted\nmodels resident instead would cost a measured 21 MiB per run for sixty-three\nshapes nobody adopts.\n\nTwo things about it are worth knowing before you adopt it. Its realised rate can\ndiffer from the winner's above, because the ranking measures every candidate under\none fixed reference geometry so the comparison is a comparison, while this is\nfitted under YOUR geometry — the one an outsider cannot predict. And it has\nlearned the window this search replayed and nothing older, so adopting it trades\nhistory for fit."},"gap":{"description":"Gap says why the winning shape could not be fitted into an adoptable value, when\nit could not. It is separate from Refusal because they are different facts: a\nrefusal means the ranking below proves nothing, a gap means the ranking stands and\nonly the value is missing.","type":"string"},"id":{"description":"ID is the run.","type":"string"},"refusal":{"description":"Refusal says why the run proves nothing, when it does. An empty history is\nREFUSED rather than reported as zero alerts: \"no alerts\" is exactly what a\nquiet model looks like, and choosing a shape on the strength of an empty\nreplay is the failure a sandbox exists to prevent.","type":"string"},"started":{"description":"Started is when the run was accepted, RFC 3339.","type":"string"},"trials":{"description":"Trials is every shape tried, best first.","items":{"$ref":"#/components/schemas/risk.riskTrial"},"type":"array"},"winner":{"$ref":"#/components/schemas/risk.riskTrial","description":"Winner is the best-fitting shape, absent when nothing fit."}},"type":"object"},"risk.riskSearchRun":{"properties":{"candidates":{"description":"Candidates is how many model shapes will be tried.","format":"int64","type":"integer"},"events":{"description":"Events is how much of the organisation's own history the run will replay.","format":"int64","type":"integer"},"id":{"description":"ID addresses the run. Read the result back with it.","type":"string"}},"type":"object"},"risk.riskSurface":{"properties":{"folded":{"description":"Folded is how many buckets of the tenant's own feature surface were folded\ninto the model when it became resident.","format":"int64","type":"integer"},"gap":{"description":"Gap says why the fold did not happen or did not complete, when that is the\ncase. An empty surface and an unreachable warehouse are different facts and\na model must not report them as the same one.","type":"string"},"refused":{"description":"Refused is how many buckets of this organisation's own surface the fold\ncould not fold, because a subject on them is longer than this plane's own\nfield bound. It is history the model does not have, said out loud.","format":"int64","type":"integer"},"replayed":{"description":"Replayed is how many of this organisation's own recorded observations\nrebuilt its sliding aggregates when the model became resident. It is what\nsays a rollout was a rebuild rather than a blindness: the aggregates are a\nprojection of a durable record, so a restart costs a replay and not a\ncontrol.","format":"int64","type":"integer"},"rolled":{"description":"Rolled is how many windows of this organisation's own source planes —\nproduct events, captured failures, metered inference — were rolled up into\nits feature surface before that fold. Zero with no gap means the surface was\nalready current, which is a different fact from the rollup never running.","format":"int64","type":"integer"},"window":{"description":"Window is the lookback the fold covered.","type":"string"}},"type":"object"},"risk.riskTopology":{"properties":{"blend":{"description":"Blend is how much of a closing window folds into the reference: 1 replaces\nit outright, less makes the reference expensive to move.","format":"double","type":"number"},"depth":{"description":"Depth is how deep each tree is. With Trees it sets how finely the space is\npartitioned, and therefore how much history it takes to fill.","format":"int64","type":"integer"},"family":{"description":"Family is the KIND of model this candidate is: `halfspace` is an ensemble of\nhalf-space trees whose masses are counters, and it is the family this search\ngrid ranks. The parameters below are that family's own — a family that does not\npartition space with trees has different ones — so read them against this.","type":"string"},"review":{"description":"Review is the appetite this shape was tried at.","format":"double","type":"number"},"trees":{"description":"Trees is how many half-space trees the ensemble holds.","format":"int64","type":"integer"},"window":{"description":"Window is how many events make one reference window.","format":"int64","type":"integer"}},"type":"object"},"risk.riskTrial":{"properties":{"alerted":{"description":"Alerted is how many of those it would have raised.","format":"int64","type":"integer"},"curve":{"description":"Curve is the realised alert rate over successive tenths of the history —\nthe learning curve, which says whether the shape settled or is still moving.","items":{"format":"double","type":"number"},"type":"array"},"fit":{"description":"Fit ranks the shape, smaller being better: the relative miss of the stated\nappetite, plus flat penalties for never warming and for saturating, plus the\nshare of coordinates that were blind.","format":"double","type":"number"},"learned":{"description":"Learned is how many events the shape learned from during the replay.","format":"int64","type":"integer"},"realised":{"description":"Realised is what that appetite actually produced. The distance between the\ntwo is what the search is searching over.","format":"double","type":"number"},"saturated":{"description":"Saturated is whether the appetite could not be honoured by any threshold,\nwhich is a shape that alerts on nothing and reads like a quiet one.","type":"boolean"},"scored":{"description":"Scored is how many it was able to score.","format":"int64","type":"integer"},"stated":{"description":"Stated is the appetite the shape was tried at.","format":"double","type":"number"},"topology":{"$ref":"#/components/schemas/risk.riskTopology","description":"Topology is the shape."},"warm":{"description":"Warm is whether the shape learned enough to have an opinion at all over\nthis organisation's whole history.","type":"boolean"}},"type":"object"},"risk.riskValue":{"properties":{"baseline":{"description":"Baseline is what Observed was measured against: this organisation's own\nhistory for this subject.","format":"double","type":"number"},"blind":{"description":"Blind marks a coordinate that could not be computed and took its neutral\nvalue. A model silently reading neutral for a dimension it never has data\nfor is indistinguishable from one reading a genuine absence of risk.","type":"boolean"},"feature":{"description":"Feature is the dimension.","type":"string"},"observed":{"description":"Observed is the raw number X was computed from, quoted so the coordinate\nreads back as a sentence rather than a bare ratio.","format":"double","type":"number"},"unit":{"description":"Unit is how to read Observed.","type":"string"},"x":{"description":"X is the coordinate in the model space, always dimensionless.","format":"double","type":"number"}},"type":"object"},"runner.Context":{"properties":{"actions_url":{"description":"ActionsURL is where act fetches an action repository from when a step\nnames one. A runner that receives nothing here composes an unusable URL\nand every job dies before its first step, so the runner supplies its own\nfallback rather than trusting this to be set.","type":"string"},"actor":{"description":"Actor is who caused the run.","type":"string"},"api_url":{"description":"APIURL is where the job reaches the forge's API.","type":"string"},"base_ref":{"description":"BaseRef is the target branch of a pull request, empty otherwise.","type":"string"},"event":{"contentEncoding":"base64","description":"Event is the webhook payload that triggered the run, as opaque JSON. It\nstays bytes because its shape belongs to the event and not to us: the\nrunner hands it to act, which evaluates github.event.* against it.","type":"string"},"event_name":{"description":"EventName is what triggered the run, e.g. \"push\".","type":"string"},"head_ref":{"description":"HeadRef is the source branch of a pull request, empty otherwise.","type":"string"},"job":{"description":"Job is which job of the workflow document this task is.","type":"string"},"ref":{"description":"Ref is the full ref the run is for, e.g. \"refs/heads/main\".","type":"string"},"ref_name":{"description":"RefName is that ref without its refs/heads/ or refs/tags/ prefix.","type":"string"},"ref_type":{"description":"RefType is \"branch\" or \"tag\".","type":"string"},"repository":{"description":"Repository is \"\u003cowner\u003e/\u003cname\u003e\".","type":"string"},"repository_owner":{"description":"RepositoryOwner is the owner half of it.","type":"string"},"retention_days":{"description":"RetentionDays is how long the run's artifacts are kept, as a number in a\nstring because that is what an expression reads.","type":"string"},"run_attempt":{"description":"RunAttempt is which attempt of that run this is, counting from 1.","type":"string"},"run_id":{"description":"RunID identifies the run this task belongs to.","type":"string"},"run_number":{"description":"RunNumber is the run's position in its repository, counting from 1.","type":"string"},"runtime_token":{"description":"RuntimeToken authorizes the job against the actions runtime: artifacts,\nthe cache. The runner passes it as ACTIONS_RUNTIME_TOKEN and masks it out\nof the log.","type":"string"},"server_url":{"description":"ServerURL is the forge's own origin, as a link in a log points at it.","type":"string"},"sha":{"description":"Sha is the commit being run, in full.","type":"string"},"token":{"description":"Token is the job's credential against the forge's own API — github.token\nin an expression.","type":"string"}},"type":"object"},"runner.DeclareIn":{"properties":{"capabilities":{"description":"Capabilities are the optional protocol behaviours this runner\nunderstands, e.g. \"cancelling\".","items":{"type":"string"},"type":"array"},"labels":{"description":"Labels replace what the forge holds, so a relabelled runner follows its\nconfiguration without re-registering.","items":{"type":"string"},"type":"array"},"version":{"description":"Version is the runner build now running.","type":"string"}},"type":"object"},"runner.DeclareOut":{"properties":{"capabilities":{"description":"Capabilities are what THIS FORGE understands, so a runner learns what the\nother side supports from the reply body rather than from a header.","items":{"type":"string"},"type":"array"},"runner":{"$ref":"#/components/schemas/runner.Identity","description":"Runner is the stored identity as the forge now holds it. Its Token is\nempty: the credential is minted once, by register."}},"type":"object"},"runner.Identity":{"properties":{"ephemeral":{"description":"Ephemeral means the runner takes ONE job and exits, so the forge must not\nexpect it back.","type":"boolean"},"id":{"description":"ID is the forge's own row id for this runner.","format":"int64","type":"integer"},"labels":{"description":"Labels are what a workflow's `runs-on:` selects this runner by.","items":{"type":"string"},"type":"array"},"name":{"description":"Name is what a person calls this runner in the forge's UI.","type":"string"},"token":{"description":"Token is the secret that authenticates that handle. It is in cleartext\nhere and nowhere else; the forge stores only a digest of it.","type":"string"},"uuid":{"description":"UUID is the handle the runner presents on every later op.","type":"string"},"version":{"description":"Version is the runner build the forge last heard from.","type":"string"}},"type":"object"},"runner.Line":{"properties":{"content":{"description":"Content is the line itself, without its terminator.","type":"string"},"time":{"description":"Time is when the line was written, in unix nanoseconds.","format":"int64","type":"integer"}},"type":"object"},"runner.LogIn":{"properties":{"index":{"description":"Index is the position of the first line in that log, so a resent batch\noverlaps rather than duplicates.","format":"int64","type":"integer"},"last":{"description":"Last seals the log and moves it to storage. Appending past a seal is an\nerror; resending one is acknowledged.","type":"boolean"},"lines":{"description":"Lines is the batch itself.","items":{"$ref":"#/components/schemas/runner.Line"},"type":"array"},"task":{"description":"Task is whose log this is.","format":"int64","type":"integer"}},"type":"object"},"runner.LogOut":{"properties":{"ack":{"description":"Ack is how far the log is durable — index plus lines accepted — and where\nthe runner resends from.","format":"int64","type":"integer"}},"type":"object"},"runner.Need":{"properties":{"job":{"description":"Job is the depended-on job's id in the workflow.","type":"string"},"outputs":{"description":"Outputs are the values it published.","items":{"$ref":"#/components/schemas/runner.Pair"},"type":"array"},"result":{"description":"Result is how it finished.","type":"string"}},"type":"object"},"runner.Pair":{"properties":{"name":{"description":"Name is what the value is filed under.","type":"string"},"value":{"description":"Value is the value itself, always a string on this wire.","type":"string"}},"type":"object"},"runner.RegisterIn":{"properties":{"capabilities":{"description":"Capabilities are the optional protocol behaviours this runner\nunderstands, e.g. \"cancelling\".","items":{"type":"string"},"type":"array"},"ephemeral":{"description":"Ephemeral declares that this runner takes ONE job and exits.","type":"boolean"},"labels":{"description":"Labels are what a workflow's `runs-on:` will select this runner by.","items":{"type":"string"},"type":"array"},"name":{"description":"Name is what to call this runner. Required.","type":"string"},"token":{"description":"Token is the REGISTRATION secret, a different secret from the runner\ntoken the reply carries. Required.","type":"string"},"version":{"description":"Version is the runner build asking to register.","type":"string"}},"type":"object"},"runner.RegisterOut":{"properties":{"runner":{"$ref":"#/components/schemas/runner.Identity","description":"Runner is the minted identity, carrying the token in cleartext once."}},"type":"object"},"runner.State":{"properties":{"id":{"description":"ID is the task this is about.","format":"int64","type":"integer"},"result":{"description":"Result is how it finished; empty means it has not.","type":"string"},"started":{"description":"Started is when it began, in unix nanoseconds; 0 is unset.","format":"int64","type":"integer"},"steps":{"description":"Steps is each step's own progress, in the order the workflow declares.","items":{"$ref":"#/components/schemas/runner.Step"},"type":"array"},"stopped":{"description":"Stopped is when it finished, in unix nanoseconds; 0 is unset.","format":"int64","type":"integer"}},"type":"object"},"runner.StateIn":{"properties":{"outputs":{"description":"Outputs are values the job has published since the last report.","items":{"$ref":"#/components/schemas/runner.Pair"},"type":"array"},"state":{"$ref":"#/components/schemas/runner.State","description":"State is the task's progress and that of each of its steps."}},"type":"object"},"runner.StateOut":{"properties":{"state":{"$ref":"#/components/schemas/runner.State","description":"State is the task's result AS THE FORGE HOLDS IT, which may differ from\nwhat was reported: that is how a runner learns it was cancelled."},"stored":{"description":"Stored names the outputs the forge has written down, so the runner stops\nresending them.","items":{"type":"string"},"type":"array"}},"type":"object"},"runner.Step":{"properties":{"id":{"description":"ID is the step's position in the job, counting from 0.","format":"int64","type":"integer"},"log_index":{"description":"LogIndex is the first line of the task log this step wrote.","format":"int64","type":"integer"},"log_length":{"description":"LogLength is how many lines it wrote from there.","format":"int64","type":"integer"},"result":{"description":"Result is how the step finished; empty means it has not.","type":"string"},"started":{"description":"Started is when it began, in unix nanoseconds; 0 is unset.","format":"int64","type":"integer"},"stopped":{"description":"Stopped is when it finished, in unix nanoseconds; 0 is unset.","format":"int64","type":"integer"}},"type":"object"},"runner.Task":{"properties":{"context":{"$ref":"#/components/schemas/runner.Context","description":"Context is what the job evaluates github.* against."},"id":{"description":"ID identifies this task on every later state and log report.","format":"int64","type":"integer"},"needs":{"description":"Needs is what the jobs this one depends on produced.","items":{"$ref":"#/components/schemas/runner.Need"},"type":"array"},"secrets":{"description":"Secrets are the values masked out of the log and exposed as secrets.*.","items":{"$ref":"#/components/schemas/runner.Pair"},"type":"array"},"vars":{"description":"Vars are the values exposed as vars.*.","items":{"$ref":"#/components/schemas/runner.Pair"},"type":"array"},"workflow":{"contentEncoding":"base64","description":"Workflow is the workflow document verbatim. The forge decides THAT a job\nruns; act, on the runner, decides what the document means.","type":"string"}},"type":"object"},"runner.TaskIn":{"properties":{"queue":{"description":"Queue is the queue version the runner last saw. When it equals the\nforge's, nothing has been queued since.","format":"int64","type":"integer"}},"type":"object"},"runner.TaskOut":{"properties":{"queue":{"description":"Queue is the forge's current queue version, to ask against next time.","format":"int64","type":"integer"},"task":{"$ref":"#/components/schemas/runner.Task","description":"Task is the assigned job, or nil for \"no work\"."}},"type":"object"},"s3.bucketIn":{"properties":{"name":{"description":"Name is the bucket's friendly name, matching\n^[a-z0-9]([a-z0-9-]{0,38}[a-z0-9])?$. It is validated AS GIVEN and never\nlower-cased for you: a client that creates \"Photos\" and then lists \"photos\"\nwould be reading a bucket it did not make, so mixed case is a clean 400.","type":"string"}},"type":"object"},"s3.bucketItem":{"properties":{"createdAt":{"description":"unix seconds","format":"int64","type":"integer"},"name":{"description":"friendly name","type":"string"}},"type":"object"},"s3.bucketList":{"properties":{"buckets":{"description":"Buckets are the caller org's buckets, friendly names, oldest first as the\nstore returns them.","items":{"$ref":"#/components/schemas/s3.bucketItem"},"type":"array"},"total":{"description":"Total is how many buckets this org has. It equals len(buckets): the listing\nis not paged, because an org's bucket count is small by construction.","format":"int64","type":"integer"}},"type":"object"},"s3.objectItem":{"properties":{"etag":{"description":"ETag is the store's entity tag for the bytes currently at this key, with the\nquotes the store wraps it in stripped. It is an opaque VERSION and not a\nchecksum to verify against: a single-part upload's tag happens to be the MD5\nof the content and a multipart upload's is not, and nothing here says which\nthis was. Compare two reads of one key to learn whether the object changed;\nabsent for a folder entry, and for an object the store reports none for.","type":"string"},"isDir":{"description":"true for a folder (common prefix)","type":"boolean"},"key":{"description":"key RELATIVE to the requested prefix","type":"string"},"lastModified":{"description":"unix seconds (0 for a folder)","format":"int64","type":"integer"},"size":{"description":"bytes (0 for a folder)","format":"int64","type":"integer"}},"type":"object"},"s3.objectList":{"properties":{"bucket":{"description":"Bucket is the bucket that was listed, friendly name.","type":"string"},"objects":{"description":"Objects are the entries at this level, keys RELATIVE to Prefix.","items":{"$ref":"#/components/schemas/s3.objectItem"},"type":"array"},"prefix":{"description":"Prefix is the sub-folder the listing was scoped to, cleaned. Empty for the\nbucket root.","type":"string"},"total":{"description":"Total is how many entries came back. The listing is BOUNDED, so a bucket\nwith more keys than the cap answers the cap and this says so — it is not a\ncount of what the bucket holds.","format":"int64","type":"integer"}},"type":"object"},"s3.partURL":{"properties":{"part":{"description":"Part is the part number.","format":"int64","type":"integer"},"url":{"description":"URL is the presigned address to PUT the part's bytes to, directly.","type":"string"}},"type":"object"},"s3.partURLs":{"properties":{"expiresIn":{"description":"Expiry is how many seconds the URLs stay valid.","format":"int64","type":"integer"},"urls":{"description":"URLs are one presigned PUT per part asked for.","items":{"$ref":"#/components/schemas/s3.partURL"},"type":"array"}},"type":"object"},"s3.presignResponse":{"properties":{"expiresIn":{"description":"seconds until the URL expires","format":"int64","type":"integer"},"key":{"description":"Key is the object key the URL was signed for, relative to the bucket root\nand path-cleaned — so it is what the store will actually read or write, which\nis not always the string the caller sent. The signature covers this one bucket\nand this one key: a URL minted here reaches nothing else.","type":"string"},"method":{"description":"\"PUT\" (upload) or \"GET\" (download)","type":"string"},"url":{"description":"presigned URL the browser follows directly","type":"string"}},"type":"object"},"s3.s3Health":{"properties":{"error":{"description":"Error is why the probe is degraded, in plain words. Absent when it is not.","type":"string"},"presign":{"description":"Presign is whether presigned upload and download URLs can be minted, which\nneeds a PUBLIC endpoint on top of the credentials. False does not make the\nsurface degraded — listing and creating still work.\n\nNOT omitempty. On the ready path the untyped probe wrote this key\nunconditionally, and omitting a false one would turn what a\nhealthy-but-presignless deployment reports from \"presign: false\" into\nsilence — two different facts. The degraded body now carries it too, which is\nthe one delta of typing this: the probe answers ONE shape under both of its\nstatuses, which is what makes a single declared Out honest.","type":"boolean"},"ready":{"description":"Ready is whether this deployment can serve object operations at all: true\nonly when admin credentials are configured.","type":"boolean"},"service":{"description":"Service names the subsystem this probe is for. Always \"s3\".","type":"string"},"status":{"description":"Status is \"ok\" when the store is reachable in principle, \"degraded\" when it\nis not. It is the field to read; the HTTP status carries the same fact for a\ncaller that only looks at the code.","type":"string"}},"type":"object"},"s3.storedPart":{"properties":{"etag":{"description":"ETag is the store's tag for its bytes, quotes stripped.","type":"string"},"part":{"description":"Part is the part number.","format":"int64","type":"integer"},"size":{"description":"Size is its length in bytes.","format":"int64","type":"integer"}},"type":"object"},"s3.storedParts":{"properties":{"key":{"description":"Key is the object key it is bound to.","type":"string"},"parts":{"description":"Parts are the parts stored, in order. A client resuming sends the others.","items":{"$ref":"#/components/schemas/s3.storedPart"},"type":"array"},"upload":{"description":"Upload is the upload's id.","type":"string"}},"type":"object"},"s3.uploadDone":{"properties":{"etag":{"description":"ETag is the assembled object's tag, quotes stripped.","type":"string"},"key":{"description":"Key is the object's key.","type":"string"},"parts":{"description":"Parts is how many parts it was assembled from.","format":"int64","type":"integer"},"size":{"description":"Size is the object's length in bytes: the sum of its parts.","format":"int64","type":"integer"}},"type":"object"},"s3.uploadGone":{"properties":{"upload":{"description":"Upload is the id of the upload abandoned; its stored parts are deleted.","type":"string"}},"type":"object"},"s3.uploadIn":{"properties":{"bucket":{"description":"Bucket is the bucket to upload into, from the path.","type":"string"},"key":{"description":"Key is the object key relative to the bucket root. It is path-cleaned, so a\n\"../\" cannot escape the bucket, and an empty or unclean key is 400.","type":"string"}},"type":"object"},"s3.uploadParts":{"properties":{"bucket":{"description":"Bucket is the bucket, from the path.","type":"string"},"key":{"description":"Key is the object key the upload was started on.","type":"string"},"parts":{"description":"Parts are the part numbers to mint URLs for, from 1. At most 64 a call.","items":{"format":"int64","type":"integer"},"type":"array"},"upload":{"description":"Upload is the upload's id, from the path.","type":"string"}},"type":"object"},"s3.uploadRef":{"properties":{"bucket":{"description":"Bucket is the bucket, from the path.","type":"string"},"key":{"description":"Key is the object key the upload was started on. In the query for a read\nor an abandon, in the body to complete.","type":"string"},"upload":{"description":"Upload is the upload's id, from the path.","type":"string"}},"type":"object"},"s3.uploadStart":{"properties":{"bucket":{"description":"Bucket is the bucket to upload into, from the path.","type":"string"},"key":{"description":"Key is the object key the upload will become, relative to the bucket\nroot. It is path-cleaned, so a \"../\" cannot escape the bucket.","type":"string"},"type":{"description":"Type is the object's media type, kept with it once it is assembled.","type":"string"}},"type":"object"},"s3.uploadStarted":{"properties":{"key":{"description":"Key is the object key the upload is bound to.","type":"string"},"partSize":{"description":"PartSize is the size every part but the last must be, in bytes. The\nnumber of parts is the file's size divided by it, rounded up.","format":"int64","type":"integer"},"upload":{"description":"Upload is the upload's id, which every later call names.","type":"string"}},"type":"object"},"sandbox.Blob":{"properties":{"data":{"contentEncoding":"base64","description":"Data is the file's bytes, verbatim, base64 on the wire. Empty for a directory\nand for an empty file alike; Dir is what tells those apart.","type":"string"},"dir":{"description":"Dir says which of the two answers this is: true and the path is a directory,\nso read Entries; false and it is a file, so read Data. Nothing else\ndistinguishes them — an empty file and an empty directory look alike here.","type":"boolean"},"entries":{"description":"Entries is a directory's contents as bare NAMES, not paths — one level, no\nrecursion, dotfiles included, \".\" and \"..\" excluded (`ls -1A`). Empty for a\nfile, and for an empty directory.","items":{"type":"string"},"type":"array"},"path":{"description":"Path is the RESOLVED absolute path that was read — the caller's relative path\njoined onto the sandbox's working directory (Leased.Workdir), so it names the\nsame file for a reader who does not know the class.","type":"string"}},"type":"object"},"sandbox.EndIn":{"properties":{"id":{"description":"ID is the sandbox whose lease ends, from an earlier lease.","type":"string"},"purge":{"description":"Purge deletes the project's DISK as well. It is opt-in because the disk holds\nthe only copy of the checkout: ending a lease is cheap and reversible,\ndeleting someone's uncommitted work is neither.","type":"boolean"}},"type":"object"},"sandbox.ExecResult":{"properties":{"exitCode":{"description":"ExitCode is the command's own exit status. A non-zero one is a SUCCESSFUL\ncall carrying a failed command — the HTTP status stays 200, because \"the\ncommand failed\" and \"the call failed\" are different facts and a caller has\nto be able to tell them apart.","format":"int64","type":"integer"},"stderr":{"description":"Stderr is everything it wrote to standard error. It is populated on a\nsuccessful run too — plenty of tools report progress there — so it is not a\nsignal that anything went wrong; ExitCode is.","type":"string"},"stdout":{"description":"Stdout is everything the command wrote to standard output, as text.","type":"string"}},"type":"object"},"sandbox.LeaseIn":{"properties":{"class":{"description":"Class is what KIND of computer to lease, and the set is closed:\n\n\texec     a throwaway one that keeps nothing. Seconds to minutes.\n\tdev      a coding one, with the project's own disk attached. Hours.\n\tdesktop  a dev one that also has a screen.\n\tandroid  a desktop with a phone running on that screen.\n\nEmpty leases an `exec`, which is the right answer for running a program and\nthe wrong one for working on a repository, because it keeps nothing.\n\nAn `android` needs a node that can virtualise a CPU, so it is the one class\na deployment may not be able to place. Where the fleet has none, the lease\nsucceeds and the pod stays Pending naming the device it is waiting for —\nwhich is the honest answer, because the alternative is an emulator running\non an interpreted CPU and never finishing its boot.","type":"string"},"cluster":{"description":"Cluster names one of the org's ATTACHED clusters to run the lease on —\nthe fleet-local name a BYO cluster was registered under. Empty runs where\nleases have always run, the home cluster. The named cluster must carry\nthe sandbox namespace and the gvisor runtime class; a name the org has\nnot attached is refused 404.","type":"string"},"disk":{"description":"Disk gives a sandbox with no Project a disk of its OWN, so what it writes\nsurvives a park: small — the size its working directory always had — billed\nas storage for as long as it exists, and deleted with the lease. Without it a\nproject-less sandbox keeps its files in the pod and loses them with it. A\nproject sandbox has the project's disk and ignores this.","type":"boolean"},"id":{"description":"ID names a sandbox to RESUME, and is the id an earlier lease answered with.\nEmpty asks for a new one. A caller that holds an id and omits it does not get\na second view of the same computer, it gets a second computer.","type":"string"},"project":{"description":"Project names the disk to attach, and is REQUIRED for every class but `exec`.\n\nOne live sandbox per project: the disk attaches to one computer at a time, so\na second lease over a project that already has one is refused by name rather\nthan handed a silently empty disk.","type":"string"},"runtime":{"description":"Runtime is the isolation boundary asked for: `gvisor` shares a filesystem\nand holds a project volume, `kata-fc` is a microVM that boots slower and\nreads files faster but has no shared filesystem at all. Empty asks for the\nfleet's default, which is the right answer unless you are measuring.\n\nIt is a REQUEST. The owner decides, and refuses a combination it cannot\nhonour — a volume under a runtime with no shared filesystem would write\ninto a tmpfs and lose the bytes at exit. Read Leased.Runtime for what the\nsandbox actually got.","type":"string"},"ttlSec":{"description":"TTLSec bounds the lease in seconds. Unset takes the class default. Nothing\nruns forever, because a sandbox is somebody else's code on our nodes.","format":"int64","type":"integer"}},"type":"object"},"sandbox.Leased":{"properties":{"class":{"description":"Class is what was actually leased, from the closed set LeaseIn.Class names:\nexec | dev | desktop | android. A request that named none leased an `exec`,\nso this is where a caller learns which kind of computer it is holding, and it\nis what Workdir below follows from.","type":"string"},"cluster":{"description":"Cluster is the attached cluster this sandbox runs on, when one was named.\nEmpty is the home cluster.","type":"string"},"id":{"description":"ID names this computer for every later call — run, read, write, stop and end\nall take it, and a LeaseIn carrying it resumes THIS sandbox instead of leasing\na second one. Minted here; a caller cannot choose it, and a resumed lease that\nhad expired comes back under a new one.","type":"string"},"runtime":{"description":"Runtime is the boundary this sandbox GOT, which need not be the one asked\nfor — carried for the same reason Workdir is, that it is a fact only the\nowner knows and a caller assuming it would be holding a second copy. Empty\nis the node's default runtime, and a real answer.","type":"string"},"status":{"description":"Status is where the pod stands, from the store's three: pending | running |\nerror. A lease that ANSWERS has already waited for the pod, so this reads\n`running` — a start that failed is a 503 and no sandbox at all. Read it\nanyway: exec refuses a sandbox that is not running, so anything else here is\nthe reason the next call will not work.","type":"string"},"workdir":{"description":"Workdir is the absolute directory this sandbox keeps files in, and what a\nrelative path in a later read, write or run resolves against — /work for dev,\ndesktop and android (the project volume's mount point), /mnt/data for exec\n(the artifact directory the code tool tells the model to write to). A path\nthat climbs above it is refused rather than rewritten.","type":"string"}},"type":"object"},"sandbox.PathIn":{"properties":{"id":{"description":"ID is the sandbox to read from, from an earlier lease.","type":"string"},"path":{"description":"Path is read relative to the sandbox's working directory unless it is\nabsolute, and a path that climbs out of it is refused rather than rewritten.\nEmpty names the working directory itself, which lists it.","type":"string"}},"type":"object"},"sandbox.Port":{"properties":{"host":{"description":"Host is the preview host that serves it, the same for as long as the\nsandbox lives, parked or running.","type":"string"},"port":{"description":"Port is the TCP port.","format":"int64","type":"integer"}},"type":"object"},"sandbox.Ports":{"properties":{"ports":{"description":"Ports are the listening ports, ascending. Never null.","items":{"$ref":"#/components/schemas/sandbox.Port"},"type":"array"}},"type":"object"},"sandbox.Ran":{"properties":{"exitCode":{"description":"ExitCode is the PROGRAM's own status — 0 succeeded, anything else is what it\nreturned, and a Command runs under `sh -c` so its shell's conventions apply.\nA command that never reached an exit does not arrive here at all: a timeout\nor a stop cancels the channel, and that is an error on the call rather than a\ncode of ours invented to fill this field.","format":"int64","type":"integer"},"stderr":{"description":"Stderr is standard error, kept apart from Stdout so a caller reading a\nprogram's OUTPUT is not reading its diagnostics as data. Same 1 MiB cap, same\nredaction. A program that failed usually says why here and nowhere else.","type":"string"},"stdout":{"description":"Stdout is what the program wrote to standard output, collected whole rather\nthan streamed — to watch it arrive instead, name a RunIn.Session and read that\nsession's feed. Capped at 1 MiB, past which it ends in \"[truncated at 1MiB]\".\nEvery string named in RunIn.Blind is replaced by \"[redacted]\" before it gets\nhere, and before it reaches the session.","type":"string"}},"type":"object"},"sandbox.RunIn":{"properties":{"argv":{"description":"Argv is the program and its arguments, already split — the form no shell can\nmisread. Give this or Command, not both.","items":{"type":"string"},"type":"array"},"blind":{"description":"Blind is the set of secrets this command must never publish.\n\nIt exists because output is redacted where it is PRODUCED or not at all. A\ncaller that scrubbed the returned result would still have streamed the\nunredacted bytes into the session as they were written — to a durable event\nstore, an SSE feed and a chat thread — because the narration leaves the\nsandbox by a different path from the result. Nothing downstream can take a\nsecret back out of a message that has already been delivered.\n\nThe sandbox holds these only for the life of the one command, applies them\nto every stream leaving it, and never logs or stores them.","items":{"type":"string"},"type":"array"},"command":{"description":"Command is a shell line, run by `sh -c`. Use it when a pipeline or a\nredirection is the point, and Argv when it is not.","type":"string"},"dir":{"description":"Dir runs the command somewhere other than the sandbox's working directory,\nwhich Leased.Workdir names.","type":"string"},"events":{"description":"Events says the command writes JSON lines to stdout, one event each, as an\nagent harness's --json does: each is appended to Session as one `event`, in\nthe shape the command wrote it, and stderr is narrated as output.","type":"boolean"},"id":{"description":"ID is the sandbox to run in, from an earlier lease.","type":"string"},"session":{"description":"Session is the live agent session this command narrates into: its output is\nappended there AS IT IS PRODUCED, so every surface watching that session\nwatches the command work instead of a blank pause. A long run is otherwise a\nsilence with a verdict at the end.\n\nIt names a SESSION and never a tenant. The org is the one the caller already\nproved, so a session belonging to somebody else is simply absent from the org\nthis call acts for and the append is refused there. Empty means nothing is\nwatching, and then nothing is sent.","type":"string"},"stdin":{"description":"Stdin is fed to the program on standard input. This is how bytes reach a file\nwithout being quoted into a shell line: `cat \u003e path` with the contents here\nwrites them exactly.","type":"string"},"timeoutSec":{"description":"TimeoutSec bounds this ONE command, so a wedged program holds the caller for\nits own timeout rather than for the whole lease.","format":"int64","type":"integer"}},"type":"object"},"sandbox.Sandbox":{"properties":{"actor":{"description":"Actor is the subject who LEASED this sandbox — the validated caller of the\nact that took the lease, never a value a request supplied. A sandbox is its\nlessee's: it holds their session, and a coding run's holds a write key to a\nrepository and the codebase's secrets. So the org gates which store a row is\nin, and this gates who in the org may act on it (holder.holds): the lessee,\nor an admin of the org, or a SuperAdmin. Empty is a lease taken by the org's\nown background work, which no person holds.","type":"string"},"class":{"description":"Class is what the sandbox is FOR, and it decides the image, the working\ndirectory and the isolation: \"exec\" for a code-interpreter call (workdir\n/mnt/data, no project, bounded per org), \"dev\" for a workspace bound to a\nproject (workdir /work, single-attach), \"desktop\" for one with a screen.","type":"string"},"cluster":{"description":"Cluster is the attached cluster this sandbox runs on — the fleet-local\nname the lease named — or empty for the home cluster. Immutable for the\nlife of the lease, like the pod it locates: every later call into the\nsandbox reads it to reach the right apiserver.","type":"string"},"connectedAt":{"description":"ConnectedAt is when somebody was last known to have this sandbox's project\nOPEN, Unix seconds. It is a fact with an EXPIRY rather than a flag: a\nwatcher restamps it every beat of its stream, and it goes stale on its own\nwhen the stream dies, so nothing has to be turned off by a process that may\nnot be there any more. The reaper reads it to choose WHICH idle allowance\napplies — see lifecycle.go.\n\nZero means nobody has said so, which puts the sandbox on the short clock.","format":"int64","type":"integer"},"createdAt":{"description":"CreatedAt is when the lease was taken, Unix seconds — by the lease that made\nthe sandbox, and again by each resume, which gives a parked sandbox a new pod\non a new lease. The ceiling on a sandbox's life runs from it.","format":"int64","type":"integer"},"error":{"description":"Error is why the sandbox could not come up, in plain words. Present only\nwith status \"error\", and it is the field to read rather than inferring a\ncause from the absence of a pod.","type":"string"},"expiresAt":{"description":"ExpiresAt is when the lease ends, Unix seconds. Past it the reaper may take\nthe sandbox at any time; it is a deadline, not a guarantee of survival until\nthen, since an idle sandbox goes sooner.","format":"int64","type":"integer"},"id":{"description":"ID is the sandbox's server-minted handle and what every operation addresses\nit by. The caller does not choose it.","type":"string"},"image":{"description":"Image is the container image this sandbox is actually running — the one the\nclass chose, or an override the policy admitted. It is what ran, not what\nwas asked for.","type":"string"},"kind":{"description":"Kind is the resource family this row belongs to. Always \"sandbox\" here; it\nexists because the store this shares is keyed across kinds.","type":"string"},"lastUsedAt":{"description":"LastUsedAt is when the sandbox last did work, Unix seconds. The reaper reads\nit: a sandbox idle past the idle window is reclaimed even inside its TTL,\nbecause an idle lease is capacity nobody is using.","format":"int64","type":"integer"},"org":{"description":"Org is the org that holds the lease — the validated caller's, never a value\na request supplied. It is also the store's key, so a sandbox is not merely\nfiltered out of another org's answers; it is unreachable from them.","type":"string"},"project":{"description":"Project is the project this sandbox is bound to. A dev or desktop sandbox\nhas one and is SINGLE-ATTACH under it, so asking twice resumes rather than\nleasing a second; an exec sandbox has none.","type":"string"},"runtime":{"description":"Runtime is the isolation boundary this sandbox GOT, which is not always the\none it asked for: a caller states a preference and runtimeFor answers with\nwhat the sandbox can actually have. Reported so a person comparing two\nruntimes is comparing the runtimes they got rather than the ones they typed\n— the difference between those two is the whole reason to record it.\n\nEmpty means the node's default runtime, which is a real answer and not a\nmissing one.\n\nThis is not a copy that can go stale. runtimeClassName is IMMUTABLE on a\npod, a sandbox's pod is created once and never recreated (restartPolicy\nNever, no pool), and its name is never reused — so for as long as the pod\nthis row names exists, it is running this runtime. The alternative, asking\nthe apiserver on every read, buys nothing and costs a round trip per row.","type":"string"},"status":{"description":"Status is where the sandbox is in its life: \"pending\" while the pod is\ncoming up, \"running\" once it can take work, \"error\" when it cannot, and\n\"parked\" when its pod is stopped and its disk kept, until a resume. Only a\nrunning sandbox takes an exec or mints an interactive ticket.","type":"string"},"volume":{"description":"Volume is the persistent volume attached to the sandbox, when it has one. A\nproject sandbox keeps its work across leases through the project's disk; a\nsandbox with no project has one only if its lease asked for a disk of its\nown, which keeps its files across a park and is deleted with the lease.\nWithout either, everything is lost with the pod.","type":"string"}},"type":"object"},"sandbox.StopIn":{"properties":{"id":{"description":"ID is the sandbox to interrupt, from an earlier lease. Every command running\nin it stops; the lease itself survives, so the checkout and the half-written\nfiles are still there to read. Use EndIn to give the computer back.","type":"string"}},"type":"object"},"sandbox.Stopped":{"properties":{"stopped":{"description":"Stopped counts the commands that were still running and were interrupted.\nZero says the sandbox was idle, not that the stop failed — see above.","format":"int64","type":"integer"}},"type":"object"},"sandbox.WriteIn":{"properties":{"data":{"contentEncoding":"base64","description":"Data is the file's bytes, and replaces whatever was there.","type":"string"},"id":{"description":"ID is the sandbox to write into, from an earlier lease.","type":"string"},"path":{"description":"Path is confined the same way PathIn.Path is. Missing parent directories are\ncreated.","type":"string"}},"type":"object"},"sandbox.Wrote":{"properties":{"bytes":{"description":"Bytes is how many bytes the file now holds. A write REPLACES the file, so this\nis its whole length and not an amount appended, and 0 is a legitimate answer:\na WriteIn with no Data truncates the file to nothing.","format":"int64","type":"integer"},"path":{"description":"Path is where the bytes actually landed: the caller's path resolved against\nthe sandbox's working directory (Leased.Workdir), which is what a later read\nor a shell line inside the sandbox has to name.","type":"string"}},"type":"object"},"sandbox.execRequest":{"properties":{"argv":{"description":"Argv is the command as an argument vector, which is the honest form: it\ncannot be word-split by accident. Send this OR Command, not both.","items":{"type":"string"},"type":"array"},"command":{"description":"Command is a shell line, for a caller that holds one. It is a convenience\nover Argv and is the only input that ever reaches a shell.","type":"string"},"dir":{"description":"Dir is the working directory to run in. Empty runs in the class's own\nworkdir — /mnt/data for exec, /work for dev.","type":"string"},"id":{"description":"ID is the sandbox to run in, from the path.","type":"string"},"stdin":{"description":"Stdin is fed to the command on its standard input.","type":"string"},"timeoutSec":{"description":"TimeoutSec bounds the run in seconds. Zero takes the default.","format":"int64","type":"integer"}},"type":"object"},"sandbox.previewGrant":{"properties":{"expiresIn":{"description":"ExpiresIn is how long the ticket in URL is good for, in seconds.","format":"int64","type":"integer"},"host":{"description":"Host is the preview's origin host, the same for every ticket for this port\nof this sandbox, before and after the sandbox is parked and resumed.","type":"string"},"port":{"description":"Port is the port the preview serves.","format":"int64","type":"integer"},"url":{"description":"URL opens the preview: its own origin, with a single-use ticket that sets\nthe preview's cookie and redirects to its root. Open it in a frame or a tab\nwithin ExpiresIn seconds, and mint another to reopen.","type":"string"}},"type":"object"},"sandbox.previewIn":{"properties":{"id":{"description":"ID is the sandbox, from the path.","type":"string"},"port":{"description":"Port is the TCP port inside the sandbox to open, 1 to 65535. Whatever\nlistens on it on localhost is what the address serves.","format":"int64","type":"integer"}},"type":"object"},"sandbox.sandboxIn":{"properties":{"class":{"description":"Class is what the sandbox is FOR: \"exec\" for a code-interpreter call,\n\"dev\" for a workspace bound to a project, \"desktop\" for one with a screen.\nIt decides the image, the working directory and the isolation.","type":"string"},"cluster":{"description":"Cluster names one of the org's attached clusters to run the sandbox on —\nthe fleet-local name it was registered under. Empty runs on the home\ncluster. The named cluster must carry the sandbox namespace and the\nvisor runtime class; a name the org has not attached is 404.","type":"string"},"image":{"description":"Image overrides the image the class would pick. Honoured only for a caller\nthe policy admits, and the sandbox that comes back names the image it GOT.","type":"string"},"project":{"description":"Project binds the sandbox to one of the org's projects. Required for a dev\nor desktop class, which are single-attach per project; an exec sandbox\ncarries none.","type":"string"},"runtime":{"description":"Runtime asks for an isolation: runc, visor, kata-clh or kata-fc. It is a\nREQUEST, not a guarantee — the sandbox that comes back carries the runtime\nit was actually given, which is the field to read.","type":"string"},"ttlSec":{"description":"TTLSec is how long the lease runs before the reaper may take it, in\nseconds. Zero takes the class's own default.","format":"int64","type":"integer"}},"type":"object"},"sandbox.sandboxList":{"properties":{"sandboxes":{"description":"Sandboxes are the sandboxes the caller holds that match the filter: the\nones they leased, or every one in the org for an admin of it. Never null.","items":{"$ref":"#/components/schemas/sandbox.Sandbox"},"type":"array"}},"type":"object"},"sandbox.ticketGrant":{"properties":{"expiresIn":{"description":"ExpiresIn is how long the ticket is good for, in seconds.","format":"int64","type":"integer"},"ticket":{"description":"Ticket is the grant itself. It is single-purpose and short-lived, and it\ntravels in a query string because a WebSocket handshake carries no\nAuthorization header a browser can set.","type":"string"},"url":{"description":"URL is the PATH to open, ticket included — not an absolute URL. Which host\nthis address wears in public is the edge's answer and not this process's, so\nan absolute URL would be a guess; the client already knows the host it is\ntalking to. It names the PAGE, which is what a caller embeds — the page\nfinds its own socket, and a caller that wants the raw socket adds `/ws`.","type":"string"}},"type":"object"},"sbom.SbomHealth":{"properties":{"datastore":{"description":"Datastore reports whether the shared datastore connection this subsystem reads\nand writes through is established. False means the data endpoints answer 503.","type":"boolean"},"service":{"description":"Service names the subsystem answering: always \"sbom\".","type":"string"},"status":{"description":"Status is the liveness verdict: always \"ok\" here, because the process answering\nat all IS the liveness fact.","type":"string"},"table":{"description":"Table is the fully-qualified datastore table the components live in.","type":"string"}},"type":"object"},"search.BackendStatus":{"properties":{"capped":{"description":"Capped is true when the leg answered from only PART of its corpus because it\nstopped at its scan cap — the code leg compares a query with at most 50000\nstored vectors — so a match past the cap was never seen. The status is still\nok: what it returned is right, it is just not the whole. Absent otherwise.","type":"boolean"},"error":{"description":"Error is the failure text from a leg whose status is degraded — the reason a\nconfigured backend could not answer. Absent otherwise.","type":"string"},"hits":{"description":"Hits is how many results this leg returned, counted BEFORE fusion, so it is\nnot the number that survived into Fusion.Hits — fusion merges what both\nlegs found and the caller's limit and offset then page it. 0 for a leg that\ndid not run.","format":"int64","type":"integer"},"name":{"description":"Name is which leg this reports: \"index\", the lexical store, \"vector\", the\nsemantic one, \"code\", the org's own repositories, or \"rerank\", the\nrelevance pass over the fused window. Match.Backend uses the same names.","type":"string"},"status":{"description":"Status is one of ok, degraded, disabled, skipped — four distinct operational\nfacts that are never collapsed. It ran and answered; it is configured and\nFAILED (Error says how, and only this one is a fault); this deployment never\nprovisioned it; or the request's mode excluded it.","type":"string"},"took_ms":{"description":"TookMS is how long this leg took, in milliseconds, timed around its own call\nand excluding fusion. 0 for a leg that was skipped or is disabled, since\nnothing was called.","format":"int64","type":"integer"}},"type":"object"},"search.Fusion":{"properties":{"backends":{"description":"Backends is the per-leg report. Always populated.","items":{"$ref":"#/components/schemas/search.BackendStatus"},"type":"array"},"hits":{"description":"Hits is the fused, ranked result set.","items":{"$ref":"#/components/schemas/search.Hit"},"type":"array"},"mode":{"description":"Mode is the mode actually used after `auto` resolution.","type":"string"},"status":{"description":"Status is the query's overall honesty signal:\n  ok          every consulted leg answered.\n  partial     at least one leg failed; Hits holds the survivors' results.\n  unavailable every consulted leg failed; Hits is empty AND that is stated.","type":"string"},"took_ms":{"description":"TookMS is the whole query's wall time in milliseconds — every leg it\nconsulted, plus fusion and paging. Each leg's own share is in\nBackends[].TookMS; the legs run in sequence, so this is at least their sum.","format":"int64","type":"integer"}},"type":"object"},"search.Hit":{"properties":{"corpus":{"description":"Corpus is which store the document lives in: \"kb\" for a document either\nknowledge leg returned, \"code\" for a span out of one of the org's own\nrepositories, \"files\" for a passage of one of the org's workspace files\n(ID is then the file's id and Title its citation). It is PROVENANCE — read it to say where a hit came from, not\nto branch on: the fused ranking is what decides order, and a caller that\nfilters by corpus wants the backend's own endpoint instead.","type":"string"},"doctype":{"description":"DocType is the knowledge doctype: kb.page, kb.memory or kb.source from the\nsemantic leg, and a lexical row's own doctype/type field otherwise. Absent\nwhen the row carried neither.","type":"string"},"id":{"description":"ID is the document's identity inside its corpus — the KB document name from\nthe semantic leg, or a lexical row's own name/id/_id (falling back to\n\"row-\u003cn\u003e\" when the row carries none). It is unique with DocType, not alone:\nthe pair is the key the two legs are fused on.","type":"string"},"matched":{"description":"Matched is one entry per leg that returned this document, with that leg's\nrank and native score. More than one entry means the legs AGREED, which is\nexactly why the hit outranks one a single leg found. Never empty on a\nreturned hit.","items":{"$ref":"#/components/schemas/search.Provenance"},"type":"array"},"passage":{"description":"Passage is the matching passage, for a hit from the files corpus: the span\nof the file's section that matched, about 2000 bytes. Absent for every\nother corpus, whose hits name a document rather than a span of one.","type":"string"},"project":{"description":"Project is the project scope the document was indexed under. Absent for a\ndocument saved with none; Request.Project filters the semantic leg on it.","type":"string"},"score":{"description":"Score is the FUSED score, not a relevance or a similarity: Reciprocal Rank\nFusion sums 1/(60+rank) over each leg that returned the document, so it is\nbounded by roughly 1/61 per leg (about 0.033 for a document two legs put\nfirst) and hits are ordered by it, descending. Being built from ranks, it is\ncomparable only WITHIN one response — never across queries, and never against\na backend's own score, which stays in Matched.","format":"double","type":"number"},"title":{"description":"Title is the document's display title — the indexed title from the semantic\nleg, the row's title (falling back to its name) from the lexical one. Absent\nwhen the document has none.","type":"string"},"url":{"description":"URL is where the document can be opened, carried from the indexed payload —\nthe link back to the app a connector ingested it from. Absent for anything\nwritten in the product, which has no external address.","type":"string"}},"type":"object"},"search.Provenance":{"properties":{"backend":{"description":"Backend is the leg that contributed this match: \"index\" (lexical), \"vector\"\n(semantic), \"code\" (the org's repositories) or \"rerank\" (the cross-encoder\npass, whose Score is the relevance it assigned). It is the same name that\nleg reports itself under in Fusion.Backends, so a hit can be traced to a\nstatus.","type":"string"},"rank":{"description":"Rank is this document's 1-based position in THAT leg's own result list,\nbefore fusion — 1 is the leg's best hit. It is the only input to the fused\nscore: RRF adds 1/(60+rank) per leg, which is why a document two legs ranked\nsecond beats one a single leg ranked first.","format":"int64","type":"integer"},"score":{"description":"Score is the leg's NATIVE score, on that leg's own scale, reported for\nexplanation and never used in ranking — the scales are incomparable (a cosine\nsimilarity against a term-match count), which is why fusion works on ranks.\nThe vector leg reports the cosine similarity of the document's best-matching\npassage; the lexical leg exposes no per-row score and reports 0, meaning\n\"unscored\", not \"scored zero\".","format":"double","type":"number"}},"type":"object"},"search.Request":{"properties":{"doctypes":{"description":"DocTypes restricts the semantic leg to a subset of indexed knowledge types.","items":{"type":"string"},"type":"array"},"index":{"description":"Index names the lexical index to query. Defaults to \"kb\".","type":"string"},"limit":{"description":"Limit bounds the FUSED result set (default 10, max 50).","format":"int64","type":"integer"},"mode":{"description":"Mode selects the legs: auto (default) | text | semantic | hybrid.","type":"string"},"offset":{"description":"Offset pages the fused result set.","format":"int64","type":"integer"},"project":{"description":"Project narrows to one project scope within the org.","type":"string"},"query":{"description":"Query is the natural-language or keyword query. Required.","type":"string"}},"type":"object"},"security.RuleView":{"properties":{"description":{"description":"what kind of secret this rule recognises","type":"string"},"id":{"description":"the rule identifier a finding cites","type":"string"},"name":{"description":"the rule's human name","type":"string"},"severity":{"description":"how serious a match is: critical, high, medium or low","type":"string"}},"type":"object"},"security.findingList":{"properties":{"data":{"description":"Data is the caller org's findings, newest first.","items":{"$ref":"#/components/schemas/security.findingView"},"type":"array"}},"type":"object"},"security.findingView":{"properties":{"createdAt":{"description":"CreatedAt is when the finding was recorded, in Unix milliseconds.","format":"int64","type":"integer"},"fingerprint":{"description":"Fingerprint is the SHA-256 of the raw secret. It is what makes the same\nsecret recognisable across scans and after rotation without the secret ever\nbeing written down.","type":"string"},"id":{"description":"ID addresses this finding.","type":"string"},"line":{"description":"Line is where in that file.","format":"int64","type":"integer"},"path":{"description":"Path is the file the secret was found in.","type":"string"},"preview":{"description":"Preview is the secret MASKED — first and last characters kept, the middle\nstarred — so a reviewer can recognise it without it being disclosed.","type":"string"},"ruleId":{"description":"RuleID is the detection rule that fired.","type":"string"},"ruleName":{"description":"RuleName is that rule's human name.","type":"string"},"scanId":{"description":"ScanID is the scan that produced it.","type":"string"},"severity":{"description":"Severity ranks the finding: critical, high, medium or low.","type":"string"}},"type":"object"},"security.ruleList":{"properties":{"data":{"description":"Data is every rule a scan can fire, each with the id, name and severity a\nfinding cites.","items":{"$ref":"#/components/schemas/security.RuleView"},"type":"array"}},"type":"object"},"security.ruleset":{"properties":{"rules":{"description":"Rules is how many detection rules the engine holds.","format":"int64","type":"integer"},"status":{"description":"Status is \"ok\" whenever the findings store opened.","type":"string"}},"type":"object"},"security.scan":{"properties":{"content":{"description":"Content is the source to scan. It is NEVER stored: what persists is the\nfinding, with a masked preview and a fingerprint.","type":"string"},"path":{"description":"Path is where the file lives, recorded on any finding so a result can be\nlocated in the tree it came from.","type":"string"}},"type":"object"},"security.scanDetail":{"properties":{"findings":{"description":"Findings is every finding on that scan, so the detail view is one round-trip.","items":{"$ref":"#/components/schemas/security.findingView"},"type":"array"},"scan":{"$ref":"#/components/schemas/security.scanView","description":"Scan is the summary."}},"type":"object"},"security.scanList":{"properties":{"data":{"description":"Data is the caller org's scans, newest first.","items":{"$ref":"#/components/schemas/security.scanView"},"type":"array"}},"type":"object"},"security.scanView":{"properties":{"createdAt":{"description":"CreatedAt is when the scan ran, in Unix milliseconds.","format":"int64","type":"integer"},"critical":{"description":"Critical is how many findings carry the highest severity.","format":"int64","type":"integer"},"files":{"description":"Files is how many files the scan read.","format":"int64","type":"integer"},"findings":{"description":"Findings is how many secrets fired across them.","format":"int64","type":"integer"},"high":{"description":"High is how many findings rank high.","format":"int64","type":"integer"},"id":{"description":"ID addresses this scan and every finding on it.","type":"string"},"low":{"description":"Low is how many findings rank low.","format":"int64","type":"integer"},"medium":{"description":"Medium is how many findings rank medium.","format":"int64","type":"integer"},"project":{"description":"Project is the sub-scope the scan was filed under.","type":"string"}},"type":"object"},"security.submitReq":{"properties":{"files":{"description":"Files is the batch to scan, at most 500 files and 8 MiB of content in total.","items":{"$ref":"#/components/schemas/security.scan"},"type":"array"},"project":{"description":"Project names the sub-scope the scan is filed under. It must be a slug; omit\nit and the caller's project header is used instead.","type":"string"}},"required":["files"],"type":"object"},"seo.seoAuditIn":{"properties":{"url":{"description":"URL is the page, absolute and http or https.","type":"string"}},"type":"object"},"seo.seoAuditOut":{"properties":{"checks":{"additionalProperties":{"type":"boolean"},"description":"Checks is every named finding, each a yes or no — \"is_https\", \"no_h1_tag\",\n\"high_loading_time\", around fifty of them. It is an OPEN set the upstream adds\nto, so it is published as an object of booleans rather than as fifty declared\nfields that would be wrong the next time they name a fifty-first.","type":"object"},"cost":{"description":"Cost is what this call cost, in USD, as an exact decimal string.","type":"string"},"description":{"description":"Description is its meta description.","type":"string"},"score":{"description":"Score is the upstream's on-page score, 0 to 100.","format":"double","type":"number"},"status":{"description":"Status is the HTTP status the page answered with.","format":"int64","type":"integer"},"title":{"description":"Title is the page's title.","type":"string"},"url":{"description":"URL is the address actually read, after redirects.","type":"string"},"words":{"description":"Words is how many words of readable text the page carries.","format":"int64","type":"integer"}},"type":"object"},"seo.seoBacklinkIn":{"properties":{"target":{"description":"Target is a domain, a subdomain or a single page URL. A domain summarises the\nwhole site; a URL summarises that page.","type":"string"}},"type":"object"},"seo.seoBacklinkOut":{"properties":{"backlinks":{"description":"Backlinks is how many links point at it.","format":"int64","type":"integer"},"broken":{"description":"Broken is how many of those links point at something that no longer answers.","format":"int64","type":"integer"},"cost":{"description":"Cost is what this call cost, in USD, as an exact decimal string.","type":"string"},"domains":{"description":"Domains is how many distinct sites those links come from — the number that\nmatters, since a thousand links from one site is one site.","format":"int64","type":"integer"},"firstSeen":{"description":"FirstSeen is when the upstream first saw a link to this target, RFC 3339.","type":"string"},"pages":{"description":"Pages is how many distinct pages link in.","format":"int64","type":"integer"},"rank":{"description":"Rank is the upstream's authority score for the target, 0 to 1000.","format":"int64","type":"integer"},"spam":{"description":"Spam is the share of the profile judged spam, 0 to 100.","format":"int64","type":"integer"},"target":{"description":"Target is the target as the upstream resolved it.","type":"string"}},"type":"object"},"seo.seoCharge":{"properties":{"op":{"description":"Op is the operation id — seoKeyword, seoRank — so a line here and a tool in a\nmodel's list are the same name.","type":"string"},"request":{"description":"Request is the flat charge for making the call, in USD, as an exact decimal\nstring.","type":"string"},"result":{"description":"Result is the charge for each row returned, in USD, as an exact decimal\nstring. Zero for the ops priced per request.","type":"string"}},"type":"object"},"seo.seoCompetitorIn":{"properties":{"keywords":{"description":"Keywords are the phrases. At least one; blanks are dropped.","items":{"type":"string"},"type":"array"},"language":{"description":"Language is the ISO code. Defaults to \"en\".","type":"string"},"limit":{"description":"Limit is how many domains to return, 1 to 1000. Defaults to 100.","format":"int64","type":"integer"},"location":{"description":"Location is the market, as the upstream's numeric code. Defaults to 2840.","format":"int64","type":"integer"}},"type":"object"},"seo.seoCompetitorOut":{"properties":{"competitors":{"description":"Competitors is one row per domain, strongest first.","items":{"$ref":"#/components/schemas/seo.seoDomain"},"type":"array"},"cost":{"description":"Cost is what this call cost, in USD, as an exact decimal string.","type":"string"},"total":{"description":"Total is how many domains the upstream holds for these phrases.","format":"int64","type":"integer"}},"type":"object"},"seo.seoDomain":{"properties":{"domain":{"description":"Domain is the competitor.","type":"string"},"keywords":{"description":"Keywords is how many of the phrases it places for.","format":"int64","type":"integer"},"position":{"description":"Position is its average rank across the phrases.","format":"double","type":"number"},"traffic":{"description":"Traffic is the estimated monthly visits those placements earn.","format":"double","type":"number"},"visibility":{"description":"Visibility is its share of the possible attention across those phrases.","format":"double","type":"number"}},"type":"object"},"seo.seoIdeaIn":{"properties":{"keywords":{"description":"Keywords are the seeds. At least one; blanks are dropped.","items":{"type":"string"},"type":"array"},"language":{"description":"Language is the ISO code. Defaults to \"en\".","type":"string"},"limit":{"description":"Limit is how many phrases to return, 1 to 1000. Defaults to 100. It is what\nthis call is priced on, because the upstream charges per row.","format":"int64","type":"integer"},"location":{"description":"Location is the market, as the upstream's numeric code. Defaults to 2840.","format":"int64","type":"integer"}},"type":"object"},"seo.seoIdeaOut":{"properties":{"cost":{"description":"Cost is what this call cost, in USD, as an exact decimal string.","type":"string"},"keywords":{"description":"Keywords is the phrases found, each measured.","items":{"$ref":"#/components/schemas/seo.seoMetric"},"type":"array"},"total":{"description":"Total is how many the upstream holds, which is usually more than Limit\nreturned — it is what raising the limit would reach.","format":"int64","type":"integer"}},"type":"object"},"seo.seoKeywordIn":{"properties":{"keywords":{"description":"Keywords are the phrases. At least one; blanks are dropped.","items":{"type":"string"},"type":"array"},"language":{"description":"Language is the ISO code. Defaults to \"en\".","type":"string"},"location":{"description":"Location is the market, as the upstream's numeric code. Defaults to 2840,\nthe United States.","format":"int64","type":"integer"}},"type":"object"},"seo.seoKeywordOut":{"properties":{"cost":{"description":"Cost is what this call cost, in USD, as an exact decimal string. It is the\nupstream's own number and it is what was debited.","type":"string"},"keywords":{"description":"Keywords is one measurement per phrase, in the order the upstream answered.","items":{"$ref":"#/components/schemas/seo.seoMetric"},"type":"array"}},"type":"object"},"seo.seoMetric":{"properties":{"competition":{"description":"Competition is how contested the advertising is, from 0 to 1. The upstream\nreports it as an index out of a hundred on one endpoint and as this fraction\non another; it is the fraction here in both cases.","format":"double","type":"number"},"cpc":{"description":"CPC is the average cost of one advertising click, in USD. It is a reported\nstatistic about somebody else's auction, not an amount this API moves.","format":"double","type":"number"},"difficulty":{"description":"Difficulty is how hard the first page is to reach organically, 0 to 100.\nPresent on seoIdea, which measures it; absent on seoKeyword, which does not.","format":"int64","type":"integer"},"keyword":{"description":"Keyword is the phrase.","type":"string"},"level":{"description":"Level is the same fact as a word: low, medium or high.","type":"string"},"volume":{"description":"Volume is the average monthly searches.","format":"int64","type":"integer"}},"type":"object"},"seo.seoRankIn":{"properties":{"domain":{"description":"Domain is the site, with or without a subdomain — \"hanzo.ai\", \"docs.hanzo.ai\".","type":"string"},"language":{"description":"Language is the ISO code. Defaults to \"en\".","type":"string"},"limit":{"description":"Limit is how many placements to return, 1 to 1000. Defaults to 100.","format":"int64","type":"integer"},"location":{"description":"Location is the market, as the upstream's numeric code. Defaults to 2840.","format":"int64","type":"integer"}},"type":"object"},"seo.seoRankOut":{"properties":{"cost":{"description":"Cost is what this call cost, in USD, as an exact decimal string.","type":"string"},"rankings":{"description":"Rankings is one row per phrase the domain places for.","items":{"$ref":"#/components/schemas/seo.seoRanking"},"type":"array"},"total":{"description":"Total is how many placements the upstream holds for this domain.","format":"int64","type":"integer"}},"type":"object"},"seo.seoRanking":{"properties":{"keyword":{"description":"Keyword is the phrase searched.","type":"string"},"position":{"description":"Position is the absolute rank on the results page, counting every element —\nso it is what a person scrolling actually passes, not the organic-only rank.","format":"int64","type":"integer"},"title":{"description":"Title is that result's headline.","type":"string"},"traffic":{"description":"Traffic is the estimated monthly visits this placement earns.","format":"double","type":"number"},"url":{"description":"URL is the page of the target that placed.","type":"string"},"volume":{"description":"Volume is the phrase's average monthly searches.","format":"int64","type":"integer"}},"type":"object"},"seo.seoRateOut":{"properties":{"rates":{"description":"Rates is one row per op on this surface.","items":{"$ref":"#/components/schemas/seo.seoCharge"},"type":"array"}},"type":"object"},"settings.View":{"properties":{"config":{"description":"Config is the product's non-secret configuration, an opaque JSON object the\nserver stores and returns verbatim. `{}` when nothing has been saved."},"createdAt":{"description":"CreatedAt is when this configuration was first written, RFC 3339 UTC.","type":"string"},"product":{"description":"Product is the catalog slug this configuration belongs to.","type":"string"},"secretKeys":{"description":"SecretKeys names the secret fields that ARE set. Their VALUES live only in KMS\nand are never returned here — the console renders a mask.","items":{"type":"string"},"type":"array"},"updatedAt":{"description":"UpdatedAt is when this configuration was last written, RFC 3339 UTC. Empty\nwhen nothing has been saved.","type":"string"}},"type":"object"},"settings.settingsReq":{"properties":{"config":{"additionalProperties":{},"description":"Config is the product's non-secret configuration, stored verbatim. Bounded at\n64 KiB once serialized. Omit it to store an empty object.","type":"object"},"product":{"description":"Product is the catalog slug, from the PATH. zip binds the path last, so the\nURL names the product being written whatever a body field claims.","type":"string"},"secrets":{"additionalProperties":{"type":"string"},"description":"Secrets are the secret fields, by name. Each VALUE is sealed into KMS and\nnever reaches this deployment's database; a value that is empty or equal to\nthe mask the read path returns means \"unchanged\" and is skipped, so a console\nround-trip cannot blank a stored secret. A key must match\n^[a-z0-9][a-z0-9._-]{0,62}$, a value is bounded at 8 KiB, and an org may hold\nat most 64 secret fields per product.","type":"object"}},"type":"object"},"share.enableResp":{"properties":{"accountToken":{"description":"AccountToken is the caller's tunnel-account credential: their org's, or in a\nheld org their own. Treat it as a secret: it is what the CLI enables an\nenvironment with.","type":"string"},"controller":{"description":"Controller is the public controller endpoint the CLI enables against.","type":"string"},"namespace":{"description":"Namespace is the public frontend a share is published into, when the\ndeployment names one.","type":"string"},"urlTemplate":{"description":"URLTemplate is the shape a share token expands to, so the CLI can print the\nresulting URL without asking again.","type":"string"}},"type":"object"},"share.rotated":{"properties":{"ended":{"description":"Ended is how many environments the rotated accounts had enabled. Each is\nended with its shares, so a machine that ran a tunnel on an account enables\nagain with the new credential.","format":"int64","type":"integer"},"pending":{"description":"Pending says what this call could not rotate, and is empty when it rotated\neverything. In a held org an admin rotates their own account first and the\norg's own after it, so the org's failing to rotate is said here rather than\nkeeping them from their own; calling again tries it again.","type":"string"}},"type":"object"},"share.shareView":{"properties":{"backend":{"description":"Backend is the local endpoint the share proxies to.","type":"string"},"backendMode":{"description":"BackendMode is how the tunnel serves the backend, e.g. proxy or web.","type":"string"},"createdAt":{"description":"CreatedAt is when the share was opened, unix seconds.","format":"int64","type":"integer"},"token":{"description":"Token is the share's own identifier, the leaf of its public URL.","type":"string"},"url":{"description":"URL is the share's public address, rendered from the deployment's URL template.","type":"string"}},"type":"object"},"share.sharesOut":{"properties":{"shares":{"description":"Shares is the org's active shares — empty rather than absent when there are\nnone, or when the controller cannot be reached.","items":{"$ref":"#/components/schemas/share.shareView"},"type":"array"}},"type":"object"},"social.orgApp":{"properties":{"clientId":{"description":"ClientID is the public app id, in the clear. The screen masks it.","type":"string"},"provider":{"description":"Provider is the network: x, facebook, instagram, linkedin, tiktok,\nyoutube or threads.","type":"string"},"secretSet":{"description":"SecretSet is whether a secret is sealed for this app. The secret itself\nis not in this response.","type":"boolean"}},"type":"object"},"social.orgAppWrite":{"properties":{"clientId":{"description":"ClientID is the full app id, never a mask. Empty clears the app.","type":"string"},"clientSecret":{"description":"ClientSecret is the secret. Absent leaves the sealed value. An empty\nstring clears it.","type":"string"},"provider":{"description":"Provider is the network to write.","type":"string"}},"type":"object"},"social.orgApps":{"properties":{"apps":{"description":"Apps is the org's sealed developer apps.","items":{"$ref":"#/components/schemas/social.orgApp"},"type":"array"},"data":{"description":"Data is Apps again, so a client that reads either envelope sees the list.","items":{"$ref":"#/components/schemas/social.orgApp"},"type":"array"}},"type":"object"},"social.orgAppsWrite":{"properties":{"apps":{"description":"Apps are the networks the caller is changing. The rest stay as they are.","items":{"$ref":"#/components/schemas/social.orgAppWrite"},"type":"array"}},"type":"object"},"social.socialAccount":{"properties":{"createdAt":{"description":"CreatedAt is when the account was connected, as a unix timestamp in seconds.","format":"int64","type":"integer"},"externalId":{"description":"ExternalID is the platform id the sealed token is stored under. Empty for\nan account recorded by hand, before a consent named one. A publish uses\nit to choose that token rather than another account on the same network.","type":"string"},"handle":{"description":"Handle is the account's public name on the network, as the customer knows\nit. Trimmed and bounded at 1024 characters.\n\nExample: \"@acme\"","type":"string"},"id":{"description":"ID is the account's identifier, minted on connect and the id every later\ncall addresses it by.\n\nExample: \"acct_7f3c1a\"","type":"string"},"provider":{"description":"Provider is the network this account is on: x, facebook, instagram,\nlinkedin, tiktok, youtube or threads.\n\nExample: \"x\"","type":"string"},"status":{"description":"Status is the connection lifecycle: connected, disconnected or error. Only\na connected account is a publish target.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the account row last changed, as a unix timestamp in\nseconds. The listing is ordered by it, newest first.","format":"int64","type":"integer"}},"type":"object"},"social.socialAccountBody":{"properties":{"handle":{"description":"Handle is the account's public name on the network, as the customer knows it\n(`@acme`). Trimmed and bounded at 1024 characters.\n\nExample: \"@acme\"","type":"string"},"provider":{"description":"Provider is the network this account is on: x, facebook, instagram, linkedin,\ntiktok, youtube or threads. Omitted means x. Anything else is refused rather\nthan coerced, because a stored account on a network that does not exist can\nnever be published through.\n\nExample: \"x\"","type":"string"},"status":{"description":"Status is the connection lifecycle: connected, disconnected or error.\nOmitted means connected. Only a connected account is a publish target.","type":"string"}},"type":"object"},"social.socialAccountWrite":{"properties":{"handle":{"description":"Handle is the account's public name on the network. Omitting it BLANKS the\nstored handle: this is a replacement, not a merge.\n\nExample: \"@acme\"","type":"string"},"provider":{"description":"Provider is the network this account is on: x, facebook, instagram, linkedin,\ntiktok, youtube or threads. Omitted means x.\n\nExample: \"x\"","type":"string"},"status":{"description":"Status is the connection lifecycle: connected, disconnected or error.\nOmitting it RESETS the account to connected.","type":"string"}},"type":"object"},"social.socialAccounts":{"properties":{"data":{"description":"Data is the accounts, most-recently-updated first, bounded by the limit.","items":{"$ref":"#/components/schemas/social.socialAccount"},"type":"array"}},"type":"object"},"social.socialPost":{"properties":{"accountId":{"description":"AccountID / ExternalID / Error are server-managed publish results, set only by\nthe publish path (never by a client update): the account a post was published\nthrough, the provider's returned external post id (for reconciliation), and the\nlast failure reason. Empty until a publish attempt lands.\nAccountID is the connected account the post went out through. Absent until\na publish succeeds.","type":"string"},"channel":{"description":"Channel is the network this post targets: x, facebook, instagram, linkedin,\ntiktok, youtube or threads. It is the channel whose CONNECTED accounts a\npublish fans out to.\n\nExample: \"x\"","type":"string"},"content":{"description":"Content is the post's text, bounded at 8192 characters.\n\nExample: \"Shipping today.\"","type":"string"},"createdAt":{"description":"CreatedAt is when the post was created, as a unix timestamp in seconds.","format":"int64","type":"integer"},"error":{"description":"Error is why the last publish attempt failed, verbatim and bounded. Absent\nwhen no attempt has failed; cleared by a later success.","type":"string"},"externalId":{"description":"ExternalID is the id the network returned for the published post, which is\nwhat reconciles this row against the post on the network. Absent until a\npublish succeeds.","type":"string"},"id":{"description":"ID is the post's identifier, minted on create and the id every later call\naddresses it by.\n\nExample: \"post_91ab20\"","type":"string"},"media":{"description":"Media is the post's attached media as a list of URLs (images today; the\ncomposer's URL field now, an S3 picker later, populate it). Stored as a JSON\narray in the media TEXT column and ALWAYS serialized as an array (never null),\nso a client can rely on `media` being present. Bounded at the write layer\n(normMedia in social.go): each URL clipped to maxField, the list to maxMedia.","items":{"type":"string"},"type":"array"},"scheduleAt":{"description":"ScheduleAt is when the post is due, as a unix timestamp in SECONDS. 0 means\nunscheduled. It is meaningful only while the status is scheduled — a\nscheduled post whose time has arrived is published by the scheduler.","format":"int64","type":"integer"},"status":{"description":"Status is the post's lifecycle state: draft, scheduled, published or failed.\nA fifth, transient publishing state exists while a publish attempt holds the\nclaim; it is never settable from a request and a caller sees it only if it\nreads a post mid-attempt.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the post row last changed, as a unix timestamp in seconds.\nThe listing is ordered by it, newest first.","format":"int64","type":"integer"}},"type":"object"},"social.socialPostBody":{"properties":{"channel":{"description":"Channel is the network to publish to: x, facebook, instagram, linkedin,\ntiktok, youtube or threads. Omitted means x.\n\nExample: \"x\"","type":"string"},"content":{"description":"Content is the post's text. Required — an empty body is a 400 — and bounded\nat 8192 characters, comfortably above every network's own limit.\n\nExample: \"Shipping today.\"","type":"string"},"media":{"description":"Media is the post's attached media as URLs, at most 10, each bounded at 1024\ncharacters. Blank entries are dropped. Omitting it CLEARS any stored media.","items":{"type":"string"},"type":"array"},"scheduleAt":{"description":"ScheduleAt is when to publish, as a unix timestamp in SECONDS. 0 means\nunscheduled. A negative value is clamped to 0. It only matters for a post\nwhose status is scheduled.","format":"int64","type":"integer"},"status":{"description":"Status is the post's lifecycle state: draft, scheduled, published or failed.\nOmitted means draft. The transient publishing claim is never settable here —\naccepting it from a request would let a caller wedge or replay the guard that\nstops two publishers double-posting the same row.","type":"string"}},"type":"object"},"social.socialPostWrite":{"properties":{"channel":{"description":"Channel is the network to publish to: x, facebook, instagram, linkedin,\ntiktok, youtube or threads. Omitted means x.\n\nExample: \"x\"","type":"string"},"content":{"description":"Content is the post's text. Required on every update, and bounded at 8192\ncharacters.\n\nExample: \"Shipping today.\"","type":"string"},"media":{"description":"Media is the post's attached media as URLs, at most 10. Omitting it CLEARS\nany stored media: this is a replacement, not a merge.","items":{"type":"string"},"type":"array"},"scheduleAt":{"description":"ScheduleAt is when to publish, as a unix timestamp in SECONDS. 0 means\nunscheduled. Moving it into the past here does NOT publish the post — that is\nthe scheduler's to notice, or the publish operation's.","format":"int64","type":"integer"},"status":{"description":"Status is the post's lifecycle state: draft, scheduled, published or failed.\nOmitting it RESETS the post to draft.","type":"string"}},"type":"object"},"social.socialPosts":{"properties":{"data":{"description":"Data is the posts, most-recently-updated first, bounded by the limit.","items":{"$ref":"#/components/schemas/social.socialPost"},"type":"array"}},"type":"object"},"social.socialProvider":{"properties":{"credentialsConfigured":{"description":"CredentialsConfigured is whether this deployment holds every OAuth\napplication credential the network needs. It is a statement about the\nDEPLOYMENT, not about the caller: a connected account also needs its own\naccess token before a post can go out.","type":"boolean"},"missingCredentials":{"description":"MissingCredentials names the environment variables still unset for this\nnetwork, so the answer is an installation instruction rather than a refusal.\nAbsent when the credentials are complete. Only the NAMES appear here; a\ncredential value is never reported.","items":{"type":"string"},"type":"array"},"provider":{"description":"Provider is the network: x, facebook, instagram, linkedin, tiktok, youtube\nor threads.\n\nExample: \"x\"","type":"string"}},"type":"object"},"social.socialProviders":{"properties":{"data":{"description":"Data is one row per supported network, in the product's fixed order: x,\nfacebook, instagram, linkedin, tiktok, youtube, threads.","items":{"$ref":"#/components/schemas/social.socialProvider"},"type":"array"}},"type":"object"},"social.socialSummary":{"properties":{"accounts":{"description":"Accounts is how many accounts the org has connected, in any status.","format":"int64","type":"integer"},"posts":{"description":"Posts is how many posts the org has, in any state.","format":"int64","type":"integer"},"published":{"description":"Published is how many of them have published.","format":"int64","type":"integer"},"scheduled":{"description":"Scheduled is how many of them are waiting for their scheduled time.","format":"int64","type":"integer"}},"type":"object"},"space.driveIn":{"properties":{"name":{"description":"Name is the drive's name, matching the same shape a space name does. It\nbecomes the FIRST SEGMENT of every key the drive holds, which is why it may\ncarry no \"/\".","type":"string"},"space":{"description":"Space is the space to create the drive in, from the path. It carries NO\n`url:\"-\"`, unlike the field below it, and the difference is the whole reason\nboth tags are written out: zip's binder skips a field tagged \"-\" for EVERY\nURL source, path params included, so a path-borne value that carried it\nwould arrive empty and the create would refuse a perfectly good address.","type":"string"}},"type":"object"},"space.driveItem":{"properties":{"name":{"description":"Name is the drive's name — the first segment of every key it holds.","type":"string"}},"type":"object"},"space.driveList":{"properties":{"drives":{"description":"Drives are the drives at the space's root.","items":{"$ref":"#/components/schemas/space.driveItem"},"type":"array"},"space":{"description":"Space is the space that was listed.","type":"string"},"total":{"description":"Total is how many drives came back. The listing is BOUNDED, so it is what\ncame back and not a count of what the space holds.","format":"int64","type":"integer"}},"type":"object"},"space.fileItem":{"properties":{"etag":{"description":"ETag is the store's entity tag for the bytes currently at this name, with the\nquotes the store wraps it in stripped. It is an opaque VERSION and not a\nchecksum to verify against: a single-part upload's tag happens to be the MD5\nof the content and a multipart upload's is not, and nothing here says which\nthis was. Compare two reads of one file to learn whether it changed; absent\nfor a folder, and for a file the store reports none for.","type":"string"},"isFolder":{"description":"Folder is true for a folder entry, which is emergent from \"/\" in the names\nbeneath it rather than a thing that was created.","type":"boolean"},"modifiedAt":{"description":"ModifiedAt is when the file was last written, in unix seconds, and 0 for a\nfolder.","format":"int64","type":"integer"},"name":{"description":"Name is the entry's name RELATIVE to the folder that was listed.","type":"string"},"size":{"description":"Size is the file's size in bytes, and 0 for a folder.","format":"int64","type":"integer"}},"type":"object"},"space.fileList":{"properties":{"drive":{"description":"Drive is the drive that was listed.","type":"string"},"files":{"description":"Files are the entries at this level, names RELATIVE to Folder.","items":{"$ref":"#/components/schemas/space.fileItem"},"type":"array"},"folder":{"description":"Folder is the sub-folder the listing was scoped to, cleaned. Empty for the\ndrive's own root.","type":"string"},"space":{"description":"Space is the space that was listed.","type":"string"},"total":{"description":"Total is how many entries came back. The listing is BOUNDED, so a drive with\nmore files than the cap answers the cap and this says so — it is not a count\nof what the drive holds.","format":"int64","type":"integer"}},"type":"object"},"space.spaceHealth":{"properties":{"error":{"description":"Error is why the probe is degraded, in plain words. Absent when it is not.","type":"string"},"presign":{"description":"Presign is whether upload and download URLs can be minted, which needs a\nPUBLIC endpoint on top of the credentials. False does not make the surface\ndegraded — listing spaces, drives and folders still works, only the bytes\ncannot be reached.","type":"boolean"},"ready":{"description":"Ready is whether this deployment can serve drive and file operations at all:\ntrue only when object-store credentials are configured.","type":"boolean"},"service":{"description":"Service names the subsystem this probe is for. Always \"space\".","type":"string"},"status":{"description":"Status is \"ok\" when the store is reachable in principle, \"degraded\" when it\nis not. It is the field to read; the HTTP status carries the same fact for a\ncaller that only looks at the code.","type":"string"}},"type":"object"},"space.spaceIn":{"properties":{"name":{"description":"Name is the space's name, matching ^[a-z0-9]([a-z0-9-]{0,38}[a-z0-9])?$ — the\nshape a drive name takes too, so a caller learns one rule. It is validated AS\nGIVEN and never lower-cased for you: a client that creates \"Photos\" and then\nlists \"photos\" would be reading a space it did not make, so mixed case is a\nclean 400.","type":"string"}},"type":"object"},"space.spaceItem":{"properties":{"createdAt":{"description":"CreatedAt is when the space was made, in unix seconds.","format":"int64","type":"integer"},"name":{"description":"Name is the space's name, as the org created it.","type":"string"}},"type":"object"},"space.spaceList":{"properties":{"spaces":{"description":"Spaces are the caller org's spaces, oldest first as the store returns them.","items":{"$ref":"#/components/schemas/space.spaceItem"},"type":"array"},"total":{"description":"Total is how many spaces this org has. It equals len(spaces): the listing is\nnot paged, because one bucket per (org, space) keeps an org's count small by\nconstruction, which is the whole reason a drive is a prefix and not a bucket.","format":"int64","type":"integer"}},"type":"object"},"standing.Obligation":{"properties":{"amountCents":{"description":"AmountCents is what it costs each period.","format":"int64","type":"integer"},"asOf":{"description":"AsOf is when that amount was last checked against its source, RFC 3339 date.","type":"string"},"code":{"description":"Code names the obligation so a caller can branch without reading prose.","type":"string"},"every":{"description":"Every is how often it falls due — \"yearly\" for every obligation known here.","type":"string"},"label":{"description":"Label is what the payer sees.","type":"string"},"minimum":{"description":"Minimum marks a floor rather than a fixed price — a franchise tax that\nscales with shares or assets is quoted at its minimum, and an entity past\nthe threshold owes more. Saying so is the difference between a quote and a\nnumber someone later disputes.","type":"boolean"},"passThrough":{"description":"PassThrough marks money we collect and remit to the state rather than keep.","type":"boolean"},"source":{"description":"Source names the authority that publishes a pass-through amount, so the\nfigure can be checked without first working out who would know.","type":"string"},"stale":{"description":"Stale reports that AsOf is older than the review window. It tells; it does\nnot block.","type":"boolean"}},"type":"object"},"standing.Upkeep":{"properties":{"atLeast":{"description":"AtLeast reports that some obligation is a minimum, so YearlyCents is a floor\nrather than a final figure.","type":"boolean"},"currency":{"description":"Currency is the ISO code every amount here is denominated in.","type":"string"},"jurisdiction":{"description":"Jurisdiction is the state whose obligations these are.","type":"string"},"obligations":{"description":"Obligations are the recurring charges, in the order a reader should see them.","items":{"$ref":"#/components/schemas/standing.Obligation"},"type":"array"},"structure":{"description":"Structure is the entity this prices.","type":"string"},"yearlyCents":{"description":"YearlyCents is what the entity owes every year, all obligations summed.","format":"int64","type":"integer"}},"type":"object"},"standing.upkeepIn":{"properties":{"agentOfRecord":{"description":"AgentOfRecord includes our agent fee, which most entities owe someone.","type":"boolean"},"jurisdiction":{"description":"Jurisdiction is the state the entity stands in.","type":"string"},"structure":{"description":"Structure is the entity kind: c-corp, llc or dao-llc.","type":"string"}},"type":"object"},"studio.Brand":{"properties":{"created":{"type":"string"},"creator":{"type":"string"},"id":{"type":"string"},"logos":{"items":{"type":"string"},"type":"array"},"name":{"type":"string"},"org":{"type":"string"},"shared":{"type":"boolean"},"tokens":{"additionalProperties":{},"type":"object"},"updated":{"type":"string"}},"type":"object"},"studio.BrandPage":{"properties":{"data":{"items":{"$ref":"#/components/schemas/studio.Brand"},"type":"array"},"next":{"type":"string"}},"type":"object"},"studio.BrandPatch":{"properties":{"id":{"type":"string"},"logos":{"items":{"type":"string"},"type":"array"},"name":{"type":"string"},"shared":{"type":"boolean"},"tokens":{"additionalProperties":{},"type":"object"}},"type":"object"},"studio.BrandWrite":{"properties":{"logos":{"items":{"type":"string"},"type":"array"},"name":{"type":"string"},"shared":{"type":"boolean"},"tokens":{"additionalProperties":{},"type":"object"}},"type":"object"},"studio.Document":{"properties":{"brand":{"type":"string"},"created":{"type":"string"},"creator":{"type":"string"},"id":{"type":"string"},"ir":{"$ref":"#/components/schemas/studio.IR"},"kind":{"type":"string"},"org":{"type":"string"},"shared":{"type":"boolean"},"title":{"type":"string"},"updated":{"type":"string"}},"type":"object"},"studio.DocumentPage":{"properties":{"data":{"items":{"$ref":"#/components/schemas/studio.Document"},"type":"array"},"next":{"type":"string"}},"type":"object"},"studio.DocumentPatch":{"properties":{"brand":{"type":"string"},"id":{"type":"string"},"ir":{"$ref":"#/components/schemas/studio.IR"},"shared":{"type":"boolean"},"title":{"type":"string"}},"type":"object"},"studio.DocumentWrite":{"properties":{"brand":{"type":"string"},"ir":{"$ref":"#/components/schemas/studio.IR"},"kind":{"description":"Kind is doc or deck.","type":"string"},"shared":{"type":"boolean"},"title":{"type":"string"}},"type":"object"},"studio.Estimate":{"properties":{"cents":{"format":"int64","type":"integer"},"steps":{"items":{"$ref":"#/components/schemas/studio.StepPrice"},"type":"array"}},"type":"object"},"studio.Flow":{"properties":{"created":{"type":"string"},"creator":{"type":"string"},"description":{"type":"string"},"graph":{"$ref":"#/components/schemas/studio.Graph"},"id":{"type":"string"},"inputs":{"additionalProperties":{},"type":"object"},"kind":{"type":"string"},"name":{"type":"string"},"org":{"type":"string"},"shared":{"type":"boolean"},"updated":{"type":"string"}},"type":"object"},"studio.FlowPage":{"properties":{"data":{"items":{"$ref":"#/components/schemas/studio.Flow"},"type":"array"},"next":{"type":"string"}},"type":"object"},"studio.FlowPatch":{"properties":{"description":{"type":"string"},"graph":{"$ref":"#/components/schemas/studio.Graph"},"id":{"type":"string"},"inputs":{"additionalProperties":{},"type":"object"},"kind":{"type":"string"},"name":{"type":"string"},"shared":{"type":"boolean"}},"type":"object"},"studio.FlowWrite":{"properties":{"description":{"type":"string"},"graph":{"$ref":"#/components/schemas/studio.Graph"},"inputs":{"additionalProperties":{},"type":"object"},"kind":{"type":"string"},"name":{"type":"string"},"shared":{"type":"boolean"}},"type":"object"},"studio.Gpu":{"properties":{"id":{"type":"string"},"machine":{"type":"string"},"name":{"description":"Name is the device, as its worker reports it.","type":"string"},"owner":{"description":"Owner is org (linked by your org with hanzo link) or platform.","type":"string"},"seen":{"description":"Seen is its worker's last heartbeat.","type":"string"},"status":{"description":"Status is idle, busy or offline.","type":"string"},"vram_mb":{"format":"int64","type":"integer"}},"type":"object"},"studio.GpuList":{"properties":{"data":{"items":{"$ref":"#/components/schemas/studio.Gpu"},"type":"array"}},"type":"object"},"studio.Graph":{"properties":{"steps":{"description":"Steps are the graph's steps, 1 to 64 of them.","items":{"$ref":"#/components/schemas/studio.Spec"},"type":"array"}},"type":"object"},"studio.IR":{"properties":{"blocks":{"items":{"additionalProperties":{},"type":"object"},"type":"array"},"slides":{"items":{"additionalProperties":{},"type":"object"},"type":"array"}},"type":"object"},"studio.Item":{"properties":{"bytes":{"format":"int64","type":"integer"},"created":{"type":"string"},"download":{"type":"string"},"expires":{"type":"string"},"height":{"format":"int64","type":"integer"},"id":{"type":"string"},"kind":{"type":"string"},"mime":{"type":"string"},"mine":{"type":"boolean"},"name":{"type":"string"},"origin":{"type":"string"},"owner":{"type":"string"},"pages":{"format":"int64","type":"integer"},"preview":{"type":"string"},"ref":{"type":"string"},"seconds":{"format":"double","type":"number"},"shared":{"type":"boolean"},"source":{"type":"string"},"url":{"description":"URL opens the file inline; Download saves it; Preview is its still.","type":"string"},"width":{"format":"int64","type":"integer"}},"type":"object"},"studio.Message":{"properties":{"assets":{"items":{"type":"string"},"type":"array"},"created":{"type":"string"},"id":{"type":"string"},"role":{"type":"string"},"runs":{"description":"Runs are the runs this message started.","items":{"type":"string"},"type":"array"},"text":{"type":"string"}},"type":"object"},"studio.Problem":{"properties":{"code":{"type":"string"},"detail":{"type":"string"},"status":{"format":"int64","type":"integer"},"title":{"type":"string"},"type":{"type":"string"}},"type":"object"},"studio.Run":{"properties":{"brand":{"type":"string"},"charged_cents":{"description":"ChargedCents is what the finished steps cost; final once the run ends.","format":"int64","type":"integer"},"created":{"type":"string"},"creator":{"type":"string"},"error":{"$ref":"#/components/schemas/studio.Problem"},"estimate_cents":{"description":"EstimateCents is what was reserved when the run started.","format":"int64","type":"integer"},"finished":{"type":"string"},"flow":{"type":"string"},"graph":{"$ref":"#/components/schemas/studio.Graph"},"id":{"type":"string"},"input":{"additionalProperties":{},"description":"Input is what the run was given, as its inputs schema reads it.","type":"object"},"kind":{"type":"string"},"org":{"type":"string"},"outputs":{"description":"Outputs are the Library items the run made, the final steps' first.","items":{"$ref":"#/components/schemas/studio.Item"},"type":"array"},"parent":{"type":"string"},"root":{"description":"Root is the first version's id; equal to id on version 1.","type":"string"},"shared":{"type":"boolean"},"started":{"type":"string"},"status":{"type":"string"},"steps":{"items":{"$ref":"#/components/schemas/studio.Step"},"type":"array"},"template":{"type":"string"},"text":{"description":"Text is the last chat step's text, when the run's product is words.","type":"string"},"title":{"type":"string"},"version":{"format":"int64","type":"integer"}},"type":"object"},"studio.RunCreate":{"properties":{"brand":{"description":"Brand is a brand id; its tokens are brand.* in the graph.","type":"string"},"flow":{"description":"Flow is a flow id.","type":"string"},"graph":{"$ref":"#/components/schemas/studio.Graph"},"input":{"additionalProperties":{},"description":"Input are the values the inputs schema asks for.","type":"object"},"parent":{"description":"Parent makes this run the next version of that run.","type":"string"},"shared":{"type":"boolean"},"template":{"description":"Template is a template id.","type":"string"},"title":{"type":"string"}},"type":"object"},"studio.RunPage":{"properties":{"data":{"items":{"$ref":"#/components/schemas/studio.Run"},"type":"array"},"next":{"type":"string"}},"type":"object"},"studio.RunPatch":{"properties":{"id":{"type":"string"},"shared":{"type":"boolean"},"title":{"type":"string"}},"type":"object"},"studio.Spec":{"properties":{"each":{"description":"Each fans the step out: a {{path}} naming an array, run once per item (at\nmost 64), its outputs the items' outputs in order.","type":"string"},"id":{"description":"ID names the step within its graph: a lowercase letter, then up to 31\nlowercase letters, digits or underscores.","type":"string"},"op":{"description":"Op is what the step does: chat, image.generate, image.edit, voice.speak,\nmusic.generate, video.generate, model.generate, studio.render, render.html,\nrender.document, render.slides, render.composition or video.edit.","type":"string"},"title":{"description":"Title is what a person sees for the step.","type":"string"},"with":{"additionalProperties":{},"description":"With are the op's parameters. Values may reference other steps.","type":"object"}},"type":"object"},"studio.Step":{"properties":{"attempt":{"description":"Attempt is how many times the step has started.","format":"int64","type":"integer"},"cost_cents":{"format":"int64","type":"integer"},"error":{"$ref":"#/components/schemas/studio.Problem"},"executor":{"description":"Executor is where the step runs: gateway, studio.render, render or flow.run.","type":"string"},"finished":{"type":"string"},"id":{"type":"string"},"items":{"description":"Items is how many items a step with each fanned out to.","format":"int64","type":"integer"},"message":{"description":"Message is what the step is doing now, for a person.","type":"string"},"op":{"type":"string"},"outputs":{"description":"Outputs are the Library item ids the step made.","items":{"type":"string"},"type":"array"},"progress":{"format":"double","type":"number"},"started":{"type":"string"},"status":{"description":"Status is pending, queued, running, succeeded, failed, canceled or skipped.","type":"string"},"text":{"type":"string"},"title":{"type":"string"}},"type":"object"},"studio.StepPrice":{"properties":{"cents":{"format":"int64","type":"integer"},"id":{"type":"string"},"op":{"type":"string"}},"type":"object"},"studio.Template":{"properties":{"created":{"type":"string"},"creator":{"type":"string"},"description":{"type":"string"},"graph":{"$ref":"#/components/schemas/studio.Graph"},"id":{"description":"ID is a catalog slug (image, poster) or an org template's id.","type":"string"},"inputs":{"additionalProperties":{},"type":"object"},"kind":{"type":"string"},"org":{"type":"string"},"preview":{"description":"Preview is an asset id or https URL of a still that shows what it makes.","type":"string"},"shared":{"type":"boolean"},"title":{"type":"string"},"updated":{"type":"string"}},"type":"object"},"studio.TemplatePage":{"properties":{"data":{"items":{"$ref":"#/components/schemas/studio.Template"},"type":"array"},"next":{"type":"string"}},"type":"object"},"studio.TemplatePatch":{"properties":{"description":{"type":"string"},"graph":{"$ref":"#/components/schemas/studio.Graph"},"id":{"type":"string"},"inputs":{"additionalProperties":{},"type":"object"},"preview":{"type":"string"},"shared":{"type":"boolean"},"title":{"type":"string"}},"type":"object"},"studio.TemplateWrite":{"properties":{"description":{"type":"string"},"graph":{"$ref":"#/components/schemas/studio.Graph"},"inputs":{"additionalProperties":{},"type":"object"},"kind":{"type":"string"},"preview":{"type":"string"},"shared":{"type":"boolean"},"title":{"type":"string"}},"type":"object"},"studio.Thread":{"properties":{"created":{"type":"string"},"creator":{"type":"string"},"id":{"type":"string"},"messages":{"items":{"$ref":"#/components/schemas/studio.Message"},"type":"array"},"org":{"type":"string"},"title":{"type":"string"},"updated":{"type":"string"}},"type":"object"},"studio.ThreadCard":{"properties":{"id":{"type":"string"},"title":{"type":"string"},"updated":{"type":"string"}},"type":"object"},"studio.ThreadPage":{"properties":{"data":{"items":{"$ref":"#/components/schemas/studio.ThreadCard"},"type":"array"},"next":{"type":"string"}},"type":"object"},"sync.endpointReq":{"properties":{"connector":{"description":"Connector names the stored credential to reach this endpoint with.","type":"string"},"locator":{"description":"Locator addresses the resource. For a git source it is the https clone URL on\nthe provider's own host, with no embedded credentials; for a native target it\nis the repository name.","type":"string"},"provider":{"description":"Provider is the platform: github or gitlab for a source; a target defaults to\nthe native Hanzo Git plane.","type":"string"}},"type":"object"},"sync.endpointView":{"properties":{"connector":{"description":"Connector names a connected account from the org's connector registry, when the\nendpoint reaches its provider through one. Absent means the locator stands on\nits own; the pair below is always sufficient either way.","type":"string"},"locator":{"description":"Locator addresses the thing INSIDE that provider, in the provider's own terms —\nan https clone URL for a hosted forge, a bare repository name for hanzo-git. It\nnever carries a credential.","type":"string"},"provider":{"description":"Provider is the concrete integration: \"github\", \"gitlab\" or \"hanzo-git\".","type":"string"}},"type":"object"},"sync.nativeView":{"properties":{"advancedAt":{"description":"AdvancedAt is when an import or a push last moved one of its refs, RFC3339\nin UTC. Absent until one has.","type":"string"},"branch":{"description":"Branch is the forge's default branch, which an import sets to the\nupstream's once that branch has landed.","type":"string"},"clone":{"description":"Clone is the https address to clone it from.","type":"string"},"sizeBytes":{"description":"SizeBytes is the repository's size on the forge, in bytes.","format":"int64","type":"integer"},"ssh":{"description":"SSH is the ssh address to clone it from, when the forge serves one.","type":"string"},"status":{"description":"Status is one of \"synced\" (the forge holds it and no ref is in conflict),\n\"conflict\" (an upstream ref diverged and the forge kept its own history),\n\"pending\" (the forge does not hold it yet) or \"paused\" (the link's\ndirection is off).","type":"string"},"url":{"description":"URL is the repository's page on the forge.","type":"string"}},"type":"object"},"sync.patchSyncIn":{"properties":{"actor":{"description":"Actor is the loop-guard identity the sync writes as. Omitted, the stored actor\nstands.","type":"string"},"direction":{"description":"Direction is both, pull, push or off. Omitted, the stored direction stands.","type":"string"},"id":{"description":"ID is the sync to update, from the path.","type":"string"},"kind":{"description":"Kind names a different kind of sync, and is refused, for the same reason.","type":"string"},"source":{"$ref":"#/components/schemas/sync.endpointReq","description":"Source, Target and Kind are DECLARED HERE IN ORDER TO BE REFUSED.\n\nThey are immutable by design — re-pointing a sync is a delete and a create, so\na link can never silently start syncing somewhere else — but an UNDECLARED\nfield is dropped by the binder before the handler sees it, so a request asking\nto repoint answered 200, changed nothing, and said nothing. The operator then\nbelieves a moved repository has been repointed and it has not.\n\nLive: a sync still naming github.com/hanzoai/cloud after the repository moved\nto hanzo-inc/cloud failed every reconcile with \"Repository not found\", and the\nPATCH that appeared to fix it did nothing at all. Declaring the fields is what\nlets the documented immutability actually answer.\nSource names a new upstream, and is refused. Delete this sync and create the\none you want."},"target":{"$ref":"#/components/schemas/sync.endpointReq","description":"Target names a new native repository, and is refused, for the same reason."},"trigger":{"description":"Trigger is webhook, poll or manual. Omitted, the stored trigger stands.","type":"string"}},"type":"object"},"sync.syncList":{"properties":{"data":{"description":"Data is the org's syncs, each with its endpoints, policy and last-synced time.","items":{"$ref":"#/components/schemas/sync.syncView"},"type":"array"}},"type":"object"},"sync.syncQueued":{"properties":{"id":{"description":"ID is the sync the reconcile was queued for.","type":"string"},"queued":{"description":"Queued is true when the reconcile was accepted; it has not run yet.","type":"boolean"}},"type":"object"},"sync.syncReq":{"properties":{"actor":{"description":"Actor is the identity the sync writes as, used as the loop guard so its own\nwrites do not re-trigger it. Defaults to the deployment's GIT_SYNC_ACTOR.","type":"string"},"direction":{"description":"Direction is both (the default), pull, push or off.","type":"string"},"kind":{"description":"Kind is what is being synced. Only \"git\" today, which is also the default.","type":"string"},"run":{"description":"Run reconciles once immediately after the upsert, in the background.","type":"boolean"},"source":{"$ref":"#/components/schemas/sync.endpointReq","description":"Source is the upstream end. Required."},"target":{"$ref":"#/components/schemas/sync.endpointReq","description":"Target is the downstream end. Optional for git: a native repository named\nafter the source is derived when it is omitted."},"trigger":{"description":"Trigger is what starts a reconcile: webhook (the default), poll or manual.","type":"string"}},"type":"object"},"sync.syncView":{"properties":{"actor":{"description":"Actor is the identity a reconcile writes AS. It is the loop guard: a change\nthis identity made is one we already have, so it is not synced back.","type":"string"},"createdAt":{"description":"CreatedAt is when the link was first declared, RFC3339 in UTC.","type":"string"},"direction":{"description":"Direction is which way work flows: \"both\", \"pull\" (target ← source), \"push\"\n(source → target), or \"off\" — which keeps the link declared and moves nothing.","type":"string"},"id":{"description":"ID is the link's handle, derived from its source and target — which is what\nmakes re-declaring the same pair an update rather than a duplicate.","type":"string"},"kind":{"description":"Kind is what is being synced. \"git\" today; the field exists so a storage or\ndatabase link is a value here rather than a second route family.","type":"string"},"native":{"$ref":"#/components/schemas/sync.nativeView","description":"Native is the repo link's copy on the forge: where it lives and how it\nstands. Absent for an account link, and absent when the forge could not be\nread — an unread forge is not reported as a healthy one."},"scope":{"description":"Scope is \"repo\" for a link to one repository, or \"account\" for a link to a\nwhole GitHub account, which declares a repo link for every repository the\naccount holds — the ones created later included.","type":"string"},"source":{"$ref":"#/components/schemas/sync.endpointView","description":"Source is the side read FROM on a pull."},"target":{"$ref":"#/components/schemas/sync.endpointView","description":"Target is the side written TO on a push."},"trigger":{"description":"Trigger is what starts a reconcile: \"webhook\" (the provider tells us),\n\"poll\" (we ask on a schedule), or \"manual\" (only an explicit call).","type":"string"},"updatedAt":{"description":"UpdatedAt is bumped by every reconcile, so it reads as the LAST-SYNCED time\nrather than the last edit. Absent until the first one runs.","type":"string"}},"type":"object"},"tagConfig":{"properties":{"audience":{"type":"string"},"consent":{"$ref":"#/components/schemas/Decision"},"tags":{"items":{"$ref":"#/components/schemas/browserTagOut"},"type":"array"}},"type":"object"},"task.Reply":{"properties":{"channel":{"description":"Channel is the room inside that workspace, and it is what decides whether\nthere is an address at all. Empty is the ordinary case: a caller of\n/v1/agent/coding holds a session id and reads the stream instead.","type":"string"},"provider":{"description":"Provider is the transport the conversation is on — slack, discord,\ntelegram, teams — and it is what decides who can carry the text at all. An\naddress without it names a room in no particular workspace.","type":"string"},"thread":{"description":"Thread narrows the address to one thread inside the channel — on Slack the\nparent message's ts, the same value a reply carries as thread_ts. Empty\nputs the text at the top level of the channel.","type":"string"},"turn":{"description":"Turn is the turn that renders a run started here: the session whose one\nmessage the run's progress and its outcome are shown in. A run with a Turn\nposts nothing of its own — one question, one message. The dispatcher writes\nit (apps/agents/replyto.go); a model never does.","type":"string"},"user":{"description":"User is the platform's id for the person the conversation is with — whose\nrun it is. A run's buttons name them to anyone else who presses one; it is\nnever what decides who may (that is the chat identity).","type":"string"}},"type":"object"},"task.boardView":{"properties":{"createdAt":{"description":"CreatedAt is when the board was created, in unix seconds. 0 on a forge board\nfor the same reason Description is absent.","format":"int64","type":"integer"},"description":{"description":"Description is whatever an index board was created with. Absent on a forge\nboard: this projection takes the repository's name and nothing else about the\nrepository.","type":"string"},"id":{"description":"ID is the board's opaque handle, and it is NOT how you address it — Key is.\nIts shape says which source answered: a forge board's is the repository's\nfull name (\"hanzoai/cloud\"), an index board's a minted \"prj_\" id.","type":"string"},"key":{"description":"Key addresses the board everywhere else — /v1/task/projects/\u003ckey\u003e/issues —\nand prefixes every issue identifier on it. An index board's key is 2-8\nuppercase alphanumerics starting with a letter (\"ENG\", \"OPS2\") and is matched\ncase-insensitively; a forge board's is the repository name as the forge\nspells it.","type":"string"},"name":{"description":"Name is the board's display name. For a forge board it is the repository\nname, so it equals Key; an index board carries its own.","type":"string"},"org":{"description":"Org is the IAM org the board belongs to, taken from the validated principal\nand never from the request. Every board a caller can see is in it.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the board record last changed, in unix seconds — the BOARD,\nnot the work on it, so filing an issue does not move it. 0 on a forge board.","format":"int64","type":"integer"}},"type":"object"},"task.comment":{"properties":{"author":{"description":"Author is who wrote it: their name, else their forge login.","type":"string"},"body":{"description":"Body is what was written, as markdown.","type":"string"},"createdAt":{"description":"CreatedAt is when it was written, RFC 3339.","type":"string"},"id":{"description":"ID is the forge's id for the comment.","format":"int64","type":"integer"}},"type":"object"},"task.commentList":{"properties":{"data":{"description":"Data is the conversation. Empty is an empty array, never null.","items":{"$ref":"#/components/schemas/task.comment"},"type":"array"},"home":{"description":"Home is the GitHub repository (owner/name) the issue lives on when its board\nmirrors one; its conversation is read there, and Data is then empty.","type":"string"}},"type":"object"},"task.issueEdit":{"properties":{"assignee":{"description":"Assignee hands the work to somebody — a person or an agent, by the name\nthey are known by on the forge. \"\" TAKES IT OFF whoever holds it, which is\nwhy this is a pointer: absent leaves the holder alone.\n\nIt is the other half of `claim`, which that handler already named: a claim\ntakes work for the CALLER and refuses to name anyone else, because giving\nwork away is a different act with different authority. This is that act,\nand until it existed a board could only be worked by whoever clicked\nfirst — an agent could never be given anything.\n\n`me` is you, by the GitHub account IAM links to you (or your forge login).\n`agent` hands the issue to the coding agent: it is labelled `agent`, and a\ncoding run starts on its repository with the issue as the task, narrating\nin the thread the hand-off was asked in; its pull request closes the issue.\nLabelling an issue `agent` on GitHub does the same.","type":"string"},"comment":{"description":"Comment is posted on the issue, after every other change — what a person in\nthe issue's thread wants said on it.","type":"string"},"description":{"description":"Description rewrites the body.","type":"string"},"key":{"description":"Key is the board — the repository name, from the path.","type":"string"},"num":{"description":"Num is the issue number on that repository, from the path.","format":"int64","type":"integer"},"priority":{"description":"Priority re-prioritises it.","type":"string"},"reply":{"$ref":"#/components/schemas/task.Reply","description":"Reply is the conversation the edit was asked for in, written by a chat turn\nand never chosen (see newIssue). An issue bound to no thread is bound to\nthis one, and a run the edit starts narrates here."},"status":{"description":"Status moves the card to another column.","type":"string"},"title":{"description":"Title renames the work item.","type":"string"}},"type":"object"},"task.issueHit":{"properties":{"assignee":{"description":"Assignee is who holds the work. EMPTY MEANS UNHELD, which is what makes the\nissue claimable: claiming one already held by someone else is refused with\n409 rather than quietly taken.","type":"string"},"kind":{"description":"Kind is what the row IS: issue, pr or epic.","type":"string"},"number":{"description":"Number is the issue's number on that board, from 1 and monotonic there.\nUnique per board, never across the org — so it addresses an issue only\ntogether with Project.","format":"int64","type":"integer"},"priority":{"description":"Priority is urgent, high, medium, low or none. Never empty — an unset\npriority is the value \"none\".","type":"string"},"project":{"description":"Project is the board key the issue is on. It and Number are the issue's\naddress in every other route on this surface, which is why a hit carries it.","type":"string"},"repo":{"description":"Repo is the git repository the issue is bound to, empty when it is not\nrepo-bound.","type":"string"},"room":{"description":"Room is the collaboration room the issue belongs to, spelled\n\"\u003cspace\u003e_\u003croom\u003e\" — empty when it is not room-bound, which is most of\nthem. It is here so an org-wide search says which channel each item came\nfrom without a second read.","type":"string"},"source":{"description":"Source is which surface opened it: team, git, crm, helpdesk, cms or agent.\n\"git\" is how the mirrored forge and GitHub rows are spelled.","type":"string"},"status":{"description":"Status is the board column: backlog, todo, in_progress, done or canceled.\nClaiming moves backlog and todo to in_progress and leaves the other three\nwhere they are.","type":"string"},"title":{"description":"Title is the issue's one-line summary — what the q filter matched, along with\nthe description.","type":"string"},"url":{"description":"URL is the row's external anchor — its extRef — which is a link only when the\nfeeder sent one. A mirrored GitHub issue carries \"github:owner/repo#123\" and\nan agent's PR row carries the pushed branch. Empty for a row opened here.","type":"string"}},"type":"object"},"task.issueHits":{"properties":{"count":{"description":"Count is how many rows Issues carries — the size of THIS answer after the\ncap, not how many issues matched. A count equal to the limit means there are\nprobably more; there is no total and no cursor.","format":"int64","type":"integer"},"issues":{"description":"Issues are the matching rows grouped by status and oldest-first within a\ngroup, capped by the search's limit (50 by default, 200 at most). The cap is\napplied to that order, so a broad search returns the head of it rather than a\nsample.","items":{"$ref":"#/components/schemas/task.issueHit"},"type":"array"}},"type":"object"},"task.issueView":{"properties":{"assignee":{"description":"Assignee is who holds the work — an IAM username, or the login of the FIRST\nassignee when a forge issue has several. Absent when nobody holds it, which\nis exactly the state a claim needs.","type":"string"},"createdAt":{"description":"CreatedAt is when the item was opened, in unix seconds. 0 when the source\ngave no parseable timestamp.","format":"int64","type":"integer"},"description":{"description":"Description is the body, markdown as its author wrote it. Absent when empty.","type":"string"},"dueAt":{"description":"DueAt is when the work is due, in unix seconds; absent means no due date. A\nforge row takes it from its MILESTONE's due date, since a forge issue has no\ndeadline of its own. Never before StartAt, and never past 2200-01-01.","format":"int64","type":"integer"},"extRef":{"description":"ExtRef anchors the item to something outside the task — a mirrored issue\n(\"github:owner/repo#123\"), a pushed PR branch, or a record on another plane.\nIt is the idempotency key the mirror upsert matches on. Absent when the item\nhas no external origin.","type":"string"},"id":{"description":"ID is the work item's opaque handle, and it is NOT how you address it —\nProjectKey plus Number is. Its shape says which source answered: a forge\nissue's is the forge's own numeric id in decimal, an index row's a minted\n\"issue_\" id.","type":"string"},"identifier":{"description":"Identifier is the human handle, \"\u003ckey\u003e#\u003cnumber\u003e\" — the board and the number\non it, joined. ONE spelling whichever source answered, because a list where\nforge rows read cli#1 and index rows read OPS-3 is two products in one list.","type":"string"},"kind":{"description":"Kind is what the item IS: issue, pr or epic. Set once at create and never\nchanged, so a row does not migrate between surfaces. Deliberately not \"task\"\n— that word is the async plane (contract.go).","type":"string"},"labels":{"description":"Labels are the item's remaining tags, with the status and priority labels\nlifted OUT — a column that stayed here would render twice, once as the card's\ncolumn and once as a chip on the card. Always present; empty is [].","items":{"type":"string"},"type":"array"},"number":{"description":"Number is the item's number ON ITS BOARD, from 1 and monotonic there — the\nforge's own issue number for a forge row, allocated inside the create\ntransaction for an index row so it cannot race. Unique per board, never\nacross the org.","format":"int64","type":"integer"},"priority":{"description":"Priority is urgent, high, medium, low or none. Also a label on a forge row.\nNever empty: \"none\" when nothing names one, so callers compare a value rather\nthan test for absence.","type":"string"},"projectKey":{"description":"ProjectKey is the board this item is on: the repository name for a forge\nissue, the index board's key otherwise. With Number it is the item's address\nin every other route.","type":"string"},"repo":{"description":"Repo is the git repository the item is bound to, so a repository's Issues and\nPRs tabs are filters over this one table. Absent when the item is not\nrepo-bound.","type":"string"},"source":{"description":"Source is which surface OPENED it: team, git, crm, helpdesk, cms or agent.\nAlso set once. It is the ORIGIN, not the subject — source=helpdesk is an\nengineering issue opened from a support escalation, not a support ticket.","type":"string"},"startAt":{"description":"StartAt is when the work starts, in unix seconds; absent means unscheduled.\nA forge row takes it from when the issue was opened, but only once the issue\nhas a due date — an interval needs both ends.","format":"int64","type":"integer"},"status":{"description":"Status is the board column: backlog, todo, in_progress, done or canceled, and\nnothing else. On a forge row it is read off a LABEL, so relabelling in the\nforge web UI moves the card here and vice versa — and a CLOSED forge issue\nreads done whatever its labels say. Never empty: \"backlog\" when nothing names\na column.","type":"string"},"title":{"description":"Title is the item's one-line summary.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it last changed, in unix seconds.","format":"int64","type":"integer"},"url":{"description":"URL is where a person reads the item: its page on the forge or on GitHub.\nAbsent for an index row, which has no page of its own.","type":"string"}},"type":"object"},"task.newIssue":{"properties":{"description":{"description":"Description becomes the issue body.","type":"string"},"key":{"description":"Key is the board — the repository name, from the path. `owner/name`, or\n`github.com/owner/name`, names a repository on GitHub that no board on the\nforge stands for.","type":"string"},"priority":{"description":"Priority is one of none, urgent, high, medium or low.","type":"string"},"reply":{"$ref":"#/components/schemas/task.Reply","description":"Reply is the conversation the issue was asked for in. A chat turn writes\nits own thread here, over anything else (apps/agents replyto.go); it is not\na value to choose. The issue is bound to it, and what happens to the issue\nnext — comments, closing, who holds it, a pull request that closes it — is\nsaid there."},"status":{"description":"Status is the board column to open into: backlog, todo, in_progress, done\nor canceled. Empty opens into backlog.","type":"string"},"title":{"description":"Title is the one line the card is read by on the board. Blank or whitespace\nis refused — an untitled card cannot be told apart from any other.","type":"string"}},"type":"object"},"task.roomWork":{"properties":{"open":{"description":"Open is how many items are still work: everything whose status does not\nend it. It is the number a channel header shows.","format":"int64","type":"integer"},"room":{"description":"Room is the room these counts are for, echoed back as it was resolved.","type":"string"},"status":{"additionalProperties":{"format":"int64","type":"integer"},"description":"Status is the count per board column, carrying EVERY column this surface\nknows — an empty column reads 0 rather than being absent, so a caller can\nrender the board without inventing the vocabulary. The keys are the same\nclosed set every other operation here validates against.","type":"object"},"total":{"description":"Total is every item bound to this room, settled ones included, so Total\nminus Open is what the room has finished.","format":"int64","type":"integer"},"updated":{"description":"Updated is when anything in this room's work last moved, in unix seconds.\nABSENT when the room has no work at all: zero would read as the epoch, and\na room nobody has filed anything in has no last activity rather than an\ninfinitely old one. Total is 0 in exactly that case.","format":"int64","type":"integer"}},"type":"object"},"tax.Address":{"properties":{"city":{"description":"City is the city or town.","type":"string"},"country":{"description":"Country is ISO 3166-1 alpha-2; \"US\" when absent.","type":"string"},"line1":{"description":"Line1 is the number, street, and apartment or suite. No periods or \"#\":\nIRIS rejects them in an address line.","type":"string"},"line2":{"description":"Line2 continues the street address, when there is more of it.","type":"string"},"state":{"description":"State is the two-letter state or territory code.","type":"string"},"zip":{"description":"ZIP is five or nine digits.","type":"string"}},"type":"object"},"tax.Amount":{"properties":{"box":{"description":"Box is the box number, e.g. \"1a\".","type":"string"},"cents":{"description":"Cents is the amount in cents.","format":"int64","type":"integer"},"label":{"description":"Label is the box's caption on the form.","type":"string"}},"type":"object"},"tax.Box":{"properties":{"box":{"type":"string"},"kind":{"type":"string"},"label":{"type":"string"}},"type":"object"},"tax.Certification":{"properties":{"by":{"description":"By is who signed it: the IAM user legal recorded completing the signature.","type":"string"},"document":{"description":"Document is the /v1/legal document that carries the signature.","type":"string"},"signed":{"description":"Signed is when legal reported the document signed, unix seconds.","format":"int64","type":"integer"},"signer":{"description":"Signer is the IAM user the signature was opened for — the admin who asked.\nOnly that user's completion certifies: a completion anyone else recorded is\nnot their signature, and a fresh request is opened in its place.","type":"string"},"status":{"description":"Status is none, pending (a signature is open) or certified.","type":"string"},"version":{"description":"Version is the profile version the signature covers. Changing any W-9 fact\nmakes a new version, and the certification no longer covers it.","format":"int64","type":"integer"}},"type":"object"},"tax.Consent":{"properties":{"at":{"description":"At is when the consent was given or withdrawn, unix seconds.","format":"int64","type":"integer"},"by":{"description":"By is the IAM user who gave or withdrew it.","type":"string"},"electronic":{"description":"Electronic is true while the consent stands. Withdrawing it sends every\nstatement furnished afterwards on paper.","type":"boolean"}},"type":"object"},"tax.Deadline":{"properties":{"file":{"description":"File is the date the return is due to the IRS, electronically (IRIS).","type":"string"},"furnish":{"description":"Furnish is the date Copy B is due to the recipient.","type":"string"}},"type":"object"},"tax.Filing":{"properties":{"createdAt":{"description":"CreatedAt is when it was exported, unix seconds.","format":"int64","type":"integer"},"due":{"description":"Due is when the return is due to the IRS.","type":"string"},"forms":{"description":"Forms are the form ids the filing carries.","items":{"type":"string"},"type":"array"},"id":{"description":"ID is the filing's id, \"iris_\"-prefixed.","type":"string"},"kind":{"description":"Kind is 1099-NEC or 1099-MISC — one per filing, as IRIS takes them.","type":"string"},"layout":{"description":"Layout says what the files are.","type":"string"},"missingTin":{"description":"MissingTIN are forms filed with no recipient TIN.","items":{"type":"string"},"type":"array"},"parts":{"description":"Parts are its files.","items":{"$ref":"#/components/schemas/tax.Part"},"type":"array"},"receiptId":{"description":"ReceiptID is the Receipt ID IRIS returned, once the payer recorded one.","type":"string"},"status":{"description":"Status is exported, submitted, accepted, accepted_with_errors or rejected.\nOnly the payer's own record moves it past exported: nothing here submits.","type":"string"},"steps":{"description":"Steps are what remains for the payer to do, in order.","items":{"type":"string"},"type":"array"},"tcc":{"description":"TCC is the payer's IRIS Transmitter Control Code, once it recorded a submission.","type":"string"},"updatedAt":{"description":"UpdatedAt is when its status last moved, unix seconds.","format":"int64","type":"integer"},"year":{"description":"Year is the tax year.","format":"int64","type":"integer"}},"type":"object"},"tax.Form":{"properties":{"account":{"description":"Account is the account number the form prints — the original form's id,\nwhich a correction keeps, so the IRS can tie the two.","type":"string"},"backup":{"$ref":"#/components/schemas/tax.Withholding","description":"Backup is the backup withholding the form carries."},"boxes":{"description":"Boxes are the figures, box 4 (federal income tax withheld) included.","items":{"$ref":"#/components/schemas/tax.Amount"},"type":"array"},"certified":{"description":"Certified is whether the payee's W-9 was certified when the form was prepared.","type":"boolean"},"corrected":{"description":"Corrected is true for a form that corrects one already furnished.","type":"boolean"},"createdAt":{"description":"CreatedAt is when the form was prepared, unix seconds.","format":"int64","type":"integer"},"delivery":{"description":"Delivery is electronic (Copy B in the payee's inbox) or paper, once furnished.","type":"string"},"due":{"$ref":"#/components/schemas/tax.Deadline","description":"Due is when Copy B is due to the payee and the return to the IRS."},"furnishedAt":{"description":"FurnishedAt is when Copy B was delivered in the inbox, or marked owed on paper.","format":"int64","type":"integer"},"id":{"description":"ID is the form's id, \"f1099_\"-prefixed.","type":"string"},"kind":{"description":"Kind is 1099-NEC or 1099-MISC.","type":"string"},"mailedAt":{"description":"MailedAt is when the payer recorded mailing a paper Copy B.","format":"int64","type":"integer"},"notes":{"description":"Notes are what still needs a person, in words.","items":{"type":"string"},"type":"array"},"payer":{"$ref":"#/components/schemas/tax.Party","description":"Payer is the filer."},"payments":{"description":"Payments are the rail payment ids summed into the boxes.","items":{"type":"string"},"type":"array"},"reason":{"description":"Reason is why a corrected form was made.","type":"string"},"recipient":{"$ref":"#/components/schemas/tax.Party","description":"Recipient is the payee."},"status":{"description":"Status is draft, reviewed, furnished, owed or void.","type":"string"},"supersededBy":{"description":"SupersededBy is the form that corrects this one, once there is one.","type":"string"},"supersedes":{"description":"Supersedes is the form this one corrects.","type":"string"},"updatedAt":{"description":"UpdatedAt is when its status last moved, unix seconds.","format":"int64","type":"integer"},"w9":{"description":"W9 is where the payer's W-9 request stood when the form was prepared.","type":"string"},"year":{"description":"Year is the calendar year the payments were made.","format":"int64","type":"integer"}},"type":"object"},"tax.Ledger":{"properties":{"payees":{"description":"Payees is every org the caller paid, by org id.","items":{"$ref":"#/components/schemas/tax.PayeeYear"},"type":"array"},"source":{"description":"Source names where the year's numbers were read.","type":"string"},"thresholdCents":{"description":"ThresholdCents is the §6041(a) threshold for the year.","format":"int64","type":"integer"},"year":{"description":"Year is the tax year.","format":"int64","type":"integer"}},"type":"object"},"tax.Line":{"properties":{"amountCents":{"description":"AmountCents is its fair market value in U.S. dollars on the date paid, in\ncents — for a U.S. dollar payment, what was paid.","format":"int64","type":"integer"},"id":{"description":"ID is the economic event's id.","type":"string"},"memo":{"description":"Memo is what was bought, in the rail's words.","type":"string"},"paid":{"description":"Paid is when, unix seconds.","format":"int64","type":"integer"},"proof":{"description":"Proof is the rail's own reference for the payment.","type":"string"},"rail":{"description":"Rail is how it moved: x402, ledger, chain, ach, wire, card, network or other.","type":"string"},"verdict":{"$ref":"#/components/schemas/tax.Verdict","description":"Verdict is whether it is reportable, where, and the rules that decided it."}},"type":"object"},"tax.Match":{"properties":{"at":{"description":"At is when the payer recorded it, unix seconds.","format":"int64","type":"integer"},"by":{"description":"By is the admin who recorded it.","type":"string"},"result":{"description":"Result is what IRS TIN Matching answered: matched or mismatched.","type":"string"}},"type":"object"},"tax.Part":{"properties":{"csv":{"description":"CSV is the file itself. It carries full TINs, and is answered only to an org\nadmin of the payer, on the audit trail.","type":"string"},"digest":{"description":"Digest is the SHA-256 of its bytes, hex, so a re-read proves it is the same file.","type":"string"},"name":{"description":"Name is the file name, e.g. \"1099-NEC-2026-original-1.csv\".","type":"string"},"records":{"description":"Records is how many forms it holds, at most 250.","format":"int64","type":"integer"},"type":{"description":"Type is original or correction: the portal takes them apart.","type":"string"}},"type":"object"},"tax.Party":{"properties":{"address":{"$ref":"#/components/schemas/tax.Address","description":"Address is where the form says they are."},"businessName":{"description":"BusinessName is W-9 line 2, when there is one.","type":"string"},"name":{"description":"Name is W-9 line 1.","type":"string"},"org":{"description":"Org is the Hanzo org.","type":"string"},"phone":{"description":"Phone is the payer's telephone number; a recipient has none on the form.","type":"string"},"tin":{"description":"TIN is masked here always. The recipient's is truncated on Copy B as Pub 1099\nallows; the payer's prints in full on the form itself, where the law requires it.","type":"string"},"tinType":{"description":"TINType is ssn or ein; empty when no TIN is held.","type":"string"}},"type":"object"},"tax.PayeeYear":{"properties":{"category":{"description":"Category is what the payer states it bought from this payee; services when\nit has stated nothing.","type":"string"},"lines":{"description":"Lines are the payments, oldest first.","items":{"$ref":"#/components/schemas/tax.Line"},"type":"array"},"payee":{"description":"Payee is the org paid.","type":"string"},"totals":{"description":"Totals are the reportable sums by box.","items":{"$ref":"#/components/schemas/tax.Total"},"type":"array"},"w9":{"description":"W9 is where the payer's W-9 request to this payee stands: none, requested,\ngranted, declined or revoked.","type":"string"}},"type":"object"},"tax.Prepared":{"properties":{"forms":{"description":"Forms are the drafts made or refreshed.","items":{"$ref":"#/components/schemas/tax.Form"},"type":"array"},"skipped":{"description":"Skipped says, per payee and form, why nothing was prepared — a form already\nfurnished is never re-prepared, only corrected.","items":{"type":"string"},"type":"array"},"year":{"description":"Year is the tax year.","format":"int64","type":"integer"}},"type":"object"},"tax.Profile":{"properties":{"address":{"$ref":"#/components/schemas/tax.Address","description":"Address is lines 5 and 6."},"businessName":{"description":"BusinessName is line 2: the business or disregarded entity name.","type":"string"},"certification":{"$ref":"#/components/schemas/tax.Certification","description":"Certification is where the Part II signature stands."},"classification":{"description":"Classification is line 3a.","type":"string"},"consent":{"$ref":"#/components/schemas/tax.Consent","description":"Consent is the electronic-delivery consent. Only the org itself reads it: how\na payee takes delivery is not a payer's to know."},"disclosure":{"description":"Disclosure is the electronic-delivery disclosure the consent is given against.","type":"string"},"exemptPayee":{"description":"ExemptPayee is line 4's exempt payee code, 1–13.","type":"string"},"expires":{"description":"Expires is when a certified W-8 stops being valid, unix seconds: the last\nday of the third calendar year after the year it was signed. A W-9 does not\nexpire.","format":"int64","type":"integer"},"fatca":{"description":"FATCA is line 4's FATCA exemption code, A–M.","type":"string"},"foreignOwners":{"description":"ForeignOwners is line 3b: a flow-through entity with foreign partners,\nowners or beneficiaries.","type":"boolean"},"foreignTin":{"description":"ForeignTIN is a W-8's foreign tax identifying number, masked. The full\nnumber is answered only with the full TIN read.","type":"string"},"form":{"description":"Form is w9, w8ben or w8bene.","type":"string"},"name":{"description":"Name is line 1: the name on the income tax return, or of the foreign\nindividual or organization that is the beneficial owner.","type":"string"},"phone":{"description":"Phone is the number a 1099 this org files as PAYER prints for it.","type":"string"},"tin":{"description":"TIN is Part I, masked to its last four digits. The full number is answered\nonly by GET /v1/tax/w9/{id}/tin, to a payer this org granted it to.","type":"string"},"tinType":{"description":"TINType is which Part I box: ssn (an SSN or ITIN) or ein.","type":"string"},"updatedAt":{"description":"UpdatedAt is when the profile last changed, unix seconds.","format":"int64","type":"integer"},"valid":{"description":"Valid is whether the form establishes what it certifies today — for a W-8,\ncertified for its current version and not expired; for a W-9, a TIN on file.","type":"boolean"},"version":{"description":"Version counts the W-9's revisions; a certification covers exactly one.","format":"int64","type":"integer"},"w8":{"$ref":"#/components/schemas/tax.W8","description":"W8 is what a W-8BEN or W-8BEN-E certifies beyond name and address."}},"type":"object"},"tax.Rule":{"properties":{"code":{"description":"Code is the rule's stable name, for a caller that branches on it.","type":"string"},"reason":{"description":"Reason is the rule, stated.","type":"string"}},"type":"object"},"tax.Statement":{"properties":{"account":{"description":"Account is the account number the form prints.","type":"string"},"backup":{"$ref":"#/components/schemas/tax.Withholding","description":"Backup is the backup withholding the payer applied."},"boxes":{"description":"Boxes are the figures.","items":{"$ref":"#/components/schemas/tax.Amount"},"type":"array"},"corrected":{"description":"Corrected is true for a statement that corrects an earlier one.","type":"boolean"},"furnishedAt":{"description":"FurnishedAt is when it was delivered, unix seconds.","format":"int64","type":"integer"},"id":{"description":"ID is the form id the payer issued it under.","type":"string"},"kind":{"description":"Kind is 1099-NEC or 1099-MISC.","type":"string"},"payer":{"$ref":"#/components/schemas/tax.Party","description":"Payer is the org that furnished it."},"recipient":{"$ref":"#/components/schemas/tax.Party","description":"Recipient is this org, as the form names it, TIN truncated."},"supersededBy":{"description":"SupersededBy is the later statement that corrects this one.","type":"string"},"supersedes":{"description":"Supersedes is the earlier statement this corrects.","type":"string"},"year":{"description":"Year is the calendar year of the payments.","format":"int64","type":"integer"}},"type":"object"},"tax.Total":{"properties":{"amountCents":{"description":"AmountCents is the reportable payments in this box, summed exactly and then\nrounded to cents.","format":"int64","type":"integer"},"box":{"$ref":"#/components/schemas/tax.Box","description":"Box is the form and box."},"payments":{"description":"Payments are the ids that sum into it.","items":{"type":"string"},"type":"array"},"reportable":{"description":"Reportable is true when the total is at or above the threshold.","type":"boolean"},"rule":{"$ref":"#/components/schemas/tax.Rule","description":"Rule states the comparison and its source."},"thresholdCents":{"description":"ThresholdCents is the year's threshold for this box.","format":"int64","type":"integer"}},"type":"object"},"tax.Treaty":{"properties":{"article":{"description":"Article is the treaty article and paragraph claimed, e.g. \"12(2)\".","type":"string"},"conditions":{"description":"Conditions is the explanation the form asks for: the conditions of the\narticle the beneficial owner meets.","type":"string"},"country":{"description":"Country is the treaty country the beneficial owner is resident in.","type":"string"},"income":{"description":"Income is the type of income the claim covers: services, rents, royalties\nor other.","type":"string"},"lob":{"description":"LOB is W-8BEN-E line 14b: the treaty's limitation on benefits provision the\nentity meets. Required on a W-8BEN-E treaty claim; a W-8BEN has no line 14b.","type":"string"},"rateBps":{"description":"RateBps is the claimed withholding rate in basis points: 0 is exempt,\n1000 is 10%.","format":"int64","type":"integer"}},"type":"object"},"tax.Verdict":{"properties":{"box":{"$ref":"#/components/schemas/tax.Box","description":"Box is where it is reported, when it is."},"reportable":{"type":"boolean"},"rules":{"description":"Rules are every rule that applied, in the order applied — the last one is\nthe verdict's reason.","items":{"$ref":"#/components/schemas/tax.Rule"},"type":"array"}},"type":"object"},"tax.W8":{"properties":{"birth":{"description":"Birth is W-8BEN line 8, the individual's date of birth, YYYY-MM-DD.","type":"string"},"capacity":{"description":"Capacity is the capacity in which the signer signs for the beneficial owner\n— \"Director\", \"Authorized officer\". Required on a W-8BEN-E; on a W-8BEN, empty\nwhen the beneficial owner signs.","type":"string"},"chapter3":{"description":"Chapter3 is W-8BEN-E line 4. A W-8BEN's beneficial owner is an individual\nand states none.","type":"string"},"chapter4":{"description":"Chapter4 is W-8BEN-E line 5, the FATCA status.","type":"string"},"country":{"description":"Country is line 2: the country of citizenship (W-8BEN) or of incorporation\nor organization (W-8BEN-E), ISO 3166-1 alpha-2.","type":"string"},"giin":{"description":"GIIN is W-8BEN-E line 9a, when the chapter 4 status carries one.","type":"string"},"noForeignTin":{"description":"NoForeignTIN is W-8BEN line 6b / W-8BEN-E line 9b's alternative: the\njurisdiction of residence does not require or issue a foreign TIN.","type":"boolean"},"treaty":{"$ref":"#/components/schemas/tax.Treaty","description":"Treaty is the claim of treaty benefits (W-8BEN Part II lines 9-10, W-8BEN-E\nPart III lines 14-15), when one is made."}},"type":"object"},"tax.W9":{"properties":{"category":{"description":"Category is what the payer states it pays this payee for. Only the payer\nsees it.","type":"string"},"decidedAt":{"description":"DecidedAt is when the payee last granted, declined or revoked.","format":"int64","type":"integer"},"id":{"description":"ID addresses the relationship on both sides.","type":"string"},"match":{"$ref":"#/components/schemas/tax.Match","description":"Match is the IRS TIN Matching result the payer recorded, when it recorded one."},"payee":{"description":"Payee is the org whose W-9 it is.","type":"string"},"payer":{"description":"Payer is the org that asked.","type":"string"},"profile":{"$ref":"#/components/schemas/tax.Profile","description":"Profile is the payee's W-9, TIN masked — present only for the payer, only\nwhile the grant is live."},"requestedAt":{"description":"RequestedAt is when the payer asked, unix seconds.","format":"int64","type":"integer"},"role":{"description":"Role is the caller's side of it: payer or payee.","type":"string"},"status":{"description":"Status is requested, granted, declined or revoked.","type":"string"}},"type":"object"},"tax.Withholding":{"properties":{"dueCents":{"description":"DueCents is what 24% of the reported boxes comes to — what should have been\nwithheld. Nothing on Hanzo's rails withholds, so box 4 reports zero, and the\npayer is liable for the amount it did not withhold (IRC §3403).","format":"int64","type":"integer"},"rate":{"description":"Rate is the backup withholding rate, in percent: 24.","format":"int64","type":"integer"},"reason":{"description":"Reason says why, and which rule — or, when nothing is required, what the payer\nshould still know.","type":"string"},"required":{"description":"Required is true when the payer holds no TIN for the payee — the IRC\n§3406(a)(1)(A) trigger these forms can know. An uncertified W-9 is not one for\nthese payments, and says so in Reason without requiring anything.","type":"boolean"}},"type":"object"},"tax.correctIn":{"properties":{"boxes":{"description":"Boxes are the corrected amounts, by box. Omitted, the boxes are derived\nagain from the payments and the payee's W-9 is read again — which is also how a\nwrong name or TIN is corrected. Zero in every box withdraws the return.","items":{"$ref":"#/components/schemas/tax.Amount"},"type":"array"},"id":{"description":"ID is the furnished form to correct, from the path.","type":"string"},"reason":{"description":"Reason says what was wrong. Required; it goes on the record.","type":"string"}},"type":"object"},"tax.exportIn":{"properties":{"kind":{"description":"Kind is 1099-NEC or 1099-MISC.","type":"string"},"year":{"description":"Year is the tax year.","format":"int64","type":"integer"}},"type":"object"},"tax.filingList":{"properties":{"data":{"description":"Data are the filings, oldest first, without their files.","items":{"$ref":"#/components/schemas/tax.Filing"},"type":"array"}},"type":"object"},"tax.formList":{"properties":{"data":{"description":"Data are the forms, oldest first.","items":{"$ref":"#/components/schemas/tax.Form"},"type":"array"}},"type":"object"},"tax.matchIn":{"properties":{"id":{"description":"ID is the relationship, from the path.","type":"string"},"result":{"description":"Result is what IRS TIN Matching answered for this payee's name and TIN:\nmatched or mismatched.","type":"string"}},"type":"object"},"tax.prepareIn":{"properties":{"year":{"description":"Year is the calendar year the payments were made in.","format":"int64","type":"integer"}},"type":"object"},"tax.profileIn":{"properties":{"address":{"$ref":"#/components/schemas/tax.Address","description":"Address is W-9 lines 5 and 6, or a W-8's line 3 permanent residence address\noutside the United States (state and zip where the country uses them).\nRequired: a statement owed on paper is mailed there."},"businessName":{"description":"BusinessName is line 2, when it differs from line 1.","type":"string"},"classification":{"description":"Classification is W-9 line 3a: individual, c_corp, s_corp, partnership,\ntrust_estate, llc_c, llc_s or llc_p. Required on a W-9; absent on a W-8.","type":"string"},"electronicConsent":{"description":"ElectronicConsent gives (true) or withdraws (false) consent to receive 1099s\nin the Hanzo inbox, against the disclosure every profile answers with.\nOmitted, the stored consent stands.","type":"boolean"},"exemptPayee":{"description":"ExemptPayee is the exempt payee code, 1–13. Entities only.","type":"string"},"fatca":{"description":"FATCA is the FATCA exemption code, A–M. Entities only.","type":"string"},"foreignOwners":{"description":"ForeignOwners is line 3b; only a partnership, trust/estate or llc_p may set it.","type":"boolean"},"foreignTin":{"description":"ForeignTIN is a W-8's foreign tax identifying number (W-8BEN line 6a,\nW-8BEN-E line 9b), as the jurisdiction of residence issues it. Omitted\nafterwards, the stored number is kept; the empty string with\nw8.noForeignTin clears it.","type":"string"},"form":{"description":"Form is w9 (a U.S. person), w8ben (a foreign individual) or w8bene (a\nforeign entity). w9 when omitted.","type":"string"},"name":{"description":"Name is line 1: the name on the income tax return, or the foreign\nindividual's or organization's name. Required.","type":"string"},"phone":{"description":"Phone is printed on the 1099s this org files as payer.","type":"string"},"tin":{"description":"TIN is W-9 Part I, or a W-8's U.S. TIN (W-8BEN line 5, W-8BEN-E line 8),\ndigits with or without hyphens. Required on a W-9's first write; on a W-8,\nonly for a treaty claim with no foreign TIN. Omitted afterwards, the stored\nnumber is kept, so an address change never re-sends it.","type":"string"},"tinType":{"description":"TINType is ssn (an SSN or ITIN) or ein. An entity other than an individual\nstates an EIN.","type":"string"},"w8":{"$ref":"#/components/schemas/tax.W8","description":"W8 is the rest of a W-8: the country of citizenship or incorporation, the\nchapter 3 and chapter 4 statuses of an entity, a date of birth, the treaty\nclaim, and the signer's capacity. Required on a W-8; absent on a W-9."}},"type":"object"},"tax.receiptIn":{"properties":{"id":{"description":"ID is the filing, from the path.","type":"string"},"receiptId":{"description":"ReceiptID is the Receipt ID IRIS returned for the submission.","type":"string"},"status":{"description":"Status is submitted (IRIS returned a Receipt ID), accepted,\naccepted_with_errors or rejected (IRIS's acknowledgment).","type":"string"},"tcc":{"description":"TCC is the IRIS Transmitter Control Code the payer submitted under: five\nuppercase letters and digits.","type":"string"}},"type":"object"},"tax.statementList":{"properties":{"data":{"description":"Data are the statements, oldest first.","items":{"$ref":"#/components/schemas/tax.Statement"},"type":"array"}},"type":"object"},"tax.tinOut":{"properties":{"foreignTin":{"description":"ForeignTIN is a W-8 payee's foreign tax identifying number as issued, which\nForm 1042-S carries for a foreign recipient.","type":"string"},"tin":{"description":"TIN is the payee's full U.S. taxpayer identification number, hyphenated as\nthe IRS writes it; empty when a W-8 carries none.","type":"string"},"tinType":{"description":"TINType is ssn or ein.","type":"string"}},"type":"object"},"tax.w9List":{"properties":{"asPayee":{"description":"AsPayee are the requests for the caller's own W-9.","items":{"$ref":"#/components/schemas/tax.W9"},"type":"array"},"asPayer":{"description":"AsPayer are the W-9s the caller asked for.","items":{"$ref":"#/components/schemas/tax.W9"},"type":"array"}},"type":"object"},"tax.w9Request":{"properties":{"category":{"description":"Category is what the caller pays it for: services, attorney, rents,\nroyalties, other or merchandise. Services when omitted.","type":"string"},"payee":{"description":"Payee is the org id of the company asked. The caller must have paid it on\nHanzo's rails.","type":"string"}},"type":"object"},"taxonomy.Category":{"properties":{"brands":{"description":"Brands are the brands whose console shows this category. Absent means every\nbrand.","items":{"type":"string"},"type":"array"},"id":{"description":"ID is the stable slug this category is addressed by, e.g. \"observe\".","type":"string"},"label":{"description":"Label is the display name, e.g. \"Observe\".","type":"string"},"order":{"description":"Order is where the category sits among its siblings, ascending.","format":"int64","type":"integer"},"owner":{"description":"Owner is the org this category belongs to: the platform's own org for a\ncategory every tenant sees, or your org for one you added. It tells a console\nwhich rows it may offer to edit.","type":"string"},"summary":{"description":"Summary is the one line describing what the category groups, shown as the\nheader copy on its landing page.","type":"string"},"taxa":{"description":"Taxa are the products filed under this category, in display order.","items":{"$ref":"#/components/schemas/taxonomy.Taxon"},"type":"array"}},"type":"object"},"taxonomy.Taxon":{"properties":{"brands":{"description":"Brands are the brands whose console shows this taxon. Absent means every\nbrand its category admits.","items":{"type":"string"},"type":"array"},"category":{"description":"Category is the id of the category this taxon is filed under.","type":"string"},"description":{"description":"Description is the one line shown beneath the name in the catalogue and nav.","type":"string"},"href":{"description":"Href is the absolute URL an external product launches, for the taxa that\ngenuinely live at their own domain. Empty for an in-console product.","type":"string"},"icon":{"description":"Icon names the icon the surface renders, e.g. \"Database\". It is a NAME, not\nan image: which icon set draws it is the rendering surface's business.","type":"string"},"id":{"description":"ID is the stable slug this taxon is addressed by, e.g. \"vector\".","type":"string"},"name":{"description":"Name is the display name, e.g. \"Vector\".","type":"string"},"order":{"description":"Order is where the taxon sits within its category, ascending.","format":"int64","type":"integer"},"owner":{"description":"Owner is the org this product belongs to: the platform's own org for one\nevery tenant sees, or your org for one you added. Where two rows share an id,\nyours is the one served.","type":"string"},"published":{"description":"Published is whether the taxon is shown. An unpublished taxon is served only\nto an editor, so a product can be staged before anyone sees it.","type":"boolean"},"route":{"description":"Route is the in-console path this taxon opens, e.g. \"/vector\". Set for a\nproduct the console renders itself; empty for an external one.","type":"string"},"tags":{"description":"Tags are free-form labels for search and grouping across categories.","items":{"type":"string"},"type":"array"}},"type":"object"},"taxonomy.Taxonomy":{"properties":{"categories":{"description":"Categories are the groupings, in display order, each with its own taxa.","items":{"$ref":"#/components/schemas/taxonomy.Category"},"type":"array"}},"type":"object"},"taxonomy.categoryIn":{"properties":{"brands":{"description":"Brands are the brands whose console shows it. Omit for every brand.","items":{"type":"string"},"type":"array"},"id":{"description":"ID is the category slug to write, from the path.","type":"string"},"label":{"description":"Label is the display name. Required.","type":"string"},"order":{"description":"Order is where the category sits among its siblings, ascending.","format":"int64","type":"integer"},"summary":{"description":"Summary is the one line describing what the category groups.","type":"string"}},"type":"object"},"taxonomy.deleted":{"properties":{"deleted":{"description":"Deleted is the id that no longer exists.","type":"string"}},"type":"object"},"taxonomy.taxonIn":{"properties":{"brands":{"description":"Brands are the brands whose console shows it. Omit for every brand its\ncategory admits.","items":{"type":"string"},"type":"array"},"category":{"description":"Category is the id of an EXISTING category to file it under. Required.","type":"string"},"description":{"description":"Description is the one line shown beneath the name.","type":"string"},"href":{"description":"Href is the absolute URL an external product launches. Give this or route,\nnever both.","type":"string"},"icon":{"description":"Icon names the icon the surface renders, e.g. \"Database\".","type":"string"},"id":{"description":"ID is the taxon slug to write, from the path.","type":"string"},"name":{"description":"Name is the display name. Required.","type":"string"},"order":{"description":"Order is where it sits within its category, ascending.","format":"int64","type":"integer"},"published":{"description":"Published is whether it is shown. Omitted means published — a taxon someone\ntook the trouble to write is meant to be seen, and hiding one is the\ndeliberate act.","type":"boolean"},"route":{"description":"Route is the in-console path it opens, e.g. \"/vector\". Give this or href,\nnever both.","type":"string"},"tags":{"description":"Tags are free-form labels for search and grouping across categories.","items":{"type":"string"},"type":"array"}},"type":"object"},"team.ProviderInfo":{"properties":{"displayName":{"description":"DisplayName is the human label for the sign-in button; this deployment\nsends \"Hanzo\". Omitted from the body when empty.","type":"string"},"name":{"description":"Name is the provider id, and it is the value that goes back in the URL to\nstart a login: GET /v1/team/account/auth/{provider}. This deployment\nsurfaces exactly one, \"openid\" — the hanzo.id provider.","type":"string"}},"type":"object"},"team.collabPayload":{"properties":{"content":{"additionalProperties":{"type":"string"},"description":"Content maps a document field to its ProseMirror markup JSON.","type":"object"},"source":{"description":"Source is the blob ref a getContent reads the snapshot from. Absent means\nthere is no snapshot to read, which answers empty content.","type":"string"},"updates":{"additionalProperties":{"type":"string"},"description":"Updates carries, per field, a base64 Y.js state update encoding the SAME\nmarkup — the front computes it (markupToYDoc → encodeStateAsUpdate) so a\ncreateContent seeds the live-editing lane's update log, not just the\nsnapshot blob. Without it a dialog-created description is invisible in the\ncollaborative editor, which replays the ydoc log, never the snapshot.","type":"object"}},"type":"object"},"team.collabRequest":{"properties":{"documentId":{"description":"DocumentID addresses the document field, as\n\"\u003cspaceUuid\u003e|\u003cobjectClass\u003e|\u003cobjectId\u003e|\u003cobjectAttr\u003e\" — the\ncollaborator-client encodeDocumentId shape, from the path.","type":"string"},"method":{"description":"Method is the verb: createContent, updateContent or getContent.","type":"string"},"payload":{"$ref":"#/components/schemas/team.collabPayload","description":"Payload is the verb's argument."}},"type":"object"},"team.collabResult":{"properties":{"content":{"additionalProperties":{"type":"string"},"description":"Content maps each document field to its value for the verb: the new blob\nref after a createContent, the stored markup after a getContent.","type":"object"},"error":{"description":"Error carries a SEMANTIC refusal, which this RPC reports under 200 because\nthe client throws on result.error — auth and tenancy failures are HTTP\nstatuses instead.","type":"string"}},"type":"object"},"team.cookieAck":{"properties":{"result":{"description":"Result is true when the cookie was written or cleared.","type":"boolean"}},"type":"object"},"team.listed":{"properties":{"members":{"description":"Members counts the room, and never names anybody in it.","format":"int64","type":"integer"},"name":{"description":"Name is what a person sees, without the sigil a client draws.","type":"string"},"org":{"description":"Org owns the room. It is also what a caller filters by to browse one org.","type":"string"},"room":{"description":"Room addresses it in the owning store — what a join is called with.","type":"string"},"space":{"description":"Space is where the room lives inside that org.","type":"string"},"topic":{"description":"Topic is the room's one-line subject, empty when it has none.","type":"string"},"updated":{"description":"Updated is when this row was last written, unix seconds.","format":"int64","type":"integer"}},"type":"object"},"team.planInfo":{"properties":{"active":{"description":"Active is whether that plan's entitlement is live.","type":"boolean"},"guestLimit":{"description":"GuestLimit is the plan's team.guests cap, when the plan carries one.","format":"int64","type":"integer"},"guests":{"description":"Guests is how many of those seats are guests.","format":"int64","type":"integer"},"plan":{"description":"Plan is the licensed plan id, empty when it cannot be resolved here — an\nhonest dash on the page, never a fabricated tier.","type":"string"},"seats":{"description":"Seats is the org's distinct active human members.","format":"int64","type":"integer"},"upgradeUrl":{"description":"UpgradeURL is where the page sends a caller who wants a bigger plan.","type":"string"}},"type":"object"},"team.publicRooms":{"properties":{"rooms":{"description":"Rooms is every published room the query matched, newest-written first.","items":{"$ref":"#/components/schemas/team.listed"},"type":"array"}},"type":"object"},"team.statsOut":{"properties":{"admin":{"description":"Admin is the upstream service's server-panel flag, always false here.","type":"boolean"},"metrics":{"description":"Metrics is the upstream transactor's metrics block. This server does not\npopulate it, so it is always the empty object — the front reads the key,\nnot its contents.","type":"object"},"statistics":{"$ref":"#/components/schemas/team.statsSessions","description":"Statistics carries the live sessions."}},"type":"object"},"team.statsSessions":{"properties":{"activeSessions":{"additionalProperties":{"items":{"$ref":"#/components/schemas/team.statsUser"},"type":"array"},"description":"ActiveSessions maps a space uuid to its connected sessions. It carries\nonly the token's OWN space, and is empty for a token that names none.","type":"object"}},"type":"object"},"team.statsUser":{"properties":{"userId":{"description":"UserID is the account the session is authenticated as.","type":"string"}},"type":"object"},"team.teamCommentWrite":{"properties":{"files":{"description":"Files attaches blobs already uploaded to the space.","items":{"$ref":"#/components/schemas/team.teamFileIn"},"type":"array"},"id":{"description":"ID is the document, from the path.","type":"string"},"space":{"description":"Space is the space uuid holding it. Body-only.","type":"string"},"text":{"description":"Text is the comment, with the same `\u003c@account-uuid\u003e` mentions a message\ntakes.","type":"string"}},"type":"object"},"team.teamDirect":{"properties":{"created":{"description":"Created is true when this call opened the conversation (201) and false\nwhen it already existed (200).","type":"boolean"},"room":{"$ref":"#/components/schemas/team.teamRoom","description":"Room is the direct message, as the room listing answers it."}},"type":"object"},"team.teamDirectOpen":{"properties":{"members":{"description":"Members are the account uuids to talk to — people or agents of the space.\nThe caller is always in the conversation and need not name themselves; an\nempty list is the caller's own notes-to-self conversation.","items":{"type":"string"},"type":"array"},"space":{"description":"Space is the space uuid. Optional for a caller in exactly one space.","type":"string"}},"type":"object"},"team.teamDoc":{"properties":{"author":{"description":"Author is the account uuid that created it.","type":"string"},"collaborator":{"description":"Collaborator is the documentId to open the body with on the\n/v1/team/collaborator Y.js socket:\n\"\u003cspace\u003e|document:class:Document|\u003cid\u003e|content\".","type":"string"},"comments":{"description":"Comments is how many comments it has.","format":"int64","type":"integer"},"createdOn":{"description":"CreatedOn is when it was created, unix milliseconds.","format":"int64","type":"integer"},"id":{"description":"ID is the document's own id.","type":"string"},"modifiedOn":{"description":"ModifiedOn is when its title or place last changed, unix milliseconds.\nEdits to the body happen on the collaborator socket and do not move it.","format":"int64","type":"integer"},"parent":{"description":"Parent is the document this one is nested under. Empty for a document at\nthe top of its teamspace.","type":"string"},"rank":{"description":"Rank orders siblings: compare as plain strings, ascending.","type":"string"},"space":{"description":"Space is the space uuid holding it.","type":"string"},"teamspace":{"description":"Teamspace is the teamspace it belongs to.","type":"string"},"title":{"description":"Title is the document's title.","type":"string"}},"type":"object"},"team.teamDocEdit":{"properties":{"id":{"description":"ID is the document, from the path.","type":"string"},"parent":{"description":"Parent moves the document under another one; \"\" moves it to the top of\nits teamspace. It goes after its new siblings.","type":"string"},"space":{"description":"Space is the space uuid holding it. Body-only.","type":"string"},"teamspace":{"description":"Teamspace moves the document — with everything nested under it — to\nanother teamspace, at the top unless Parent names a document there.","type":"string"},"title":{"description":"Title renames the document. Empty reads \"Untitled\".","type":"string"}},"type":"object"},"team.teamDocNew":{"properties":{"parent":{"description":"Parent nests the new document under another one.","type":"string"},"space":{"description":"Space is the space uuid. Optional for a caller in exactly one space.","type":"string"},"teamspace":{"description":"Teamspace is where the document goes. Optional: a document nested under a\nparent goes in the parent's teamspace, and a space with exactly one\nteamspace the caller can write needs no name — with none, the first\ndocument opens a public \"General\" teamspace for the whole space.","type":"string"},"title":{"description":"Title is the document's title. Empty reads \"Untitled\", as in the Team\nclient.","type":"string"}},"type":"object"},"team.teamDocs":{"properties":{"docs":{"description":"Docs are the documents, grouped by teamspace, then parent, then the\norder the Team client shows siblings in.","items":{"$ref":"#/components/schemas/team.teamDoc"},"type":"array"},"teamspaces":{"description":"Teamspaces are the teamspaces the caller may see, by name — the groups a\nclient draws the tree under.","items":{"$ref":"#/components/schemas/team.teamTeamspace"},"type":"array"}},"type":"object"},"team.teamFile":{"properties":{"file":{"description":"File is the blob id, readable at GET /v1/team/files/{space}/{name}?file={file}.","type":"string"},"id":{"description":"ID is the attachment document's own id.","type":"string"},"name":{"description":"Name is the file's name as the person uploaded it.","type":"string"},"size":{"description":"Size is the file's length in bytes, as the uploader stated it.","format":"int64","type":"integer"},"type":{"description":"Type is the media type the uploader declared. The download route serves\nwhat the BYTES are, not this; it is a hint for drawing an icon.","type":"string"}},"type":"object"},"team.teamFileIn":{"properties":{"file":{"description":"File is the blob id — the uuid the file was uploaded under with\nPOST /v1/team/files/{space}. A blob of another space cannot be named: the\ndownload is keyed by this message's space, so a foreign id resolves to\nnothing.","type":"string"},"name":{"description":"Name is the file's name as a person should see it.","type":"string"},"size":{"description":"Size is the file's length in bytes.","format":"int64","type":"integer"},"type":{"description":"Type is the file's media type, e.g. \"image/png\".","type":"string"}},"type":"object"},"team.teamInbox":{"properties":{"items":{"description":"Items are the notifications, newest first, at most 200.","items":{"$ref":"#/components/schemas/team.teamInboxItem"},"type":"array"},"unread":{"description":"Unread is how many of the caller's live (unarchived) notifications are\nunread — the number a badge shows, counted over all of them rather than\nthe page.","format":"int64","type":"integer"}},"type":"object"},"team.teamInboxAll":{"properties":{"space":{"description":"Space is the space uuid. Optional for a caller in exactly one space.","type":"string"}},"type":"object"},"team.teamInboxAt":{"properties":{"id":{"description":"ID is the notification, from the path.","type":"string"},"space":{"description":"Space is the space uuid it was filed in. Body-only.","type":"string"}},"type":"object"},"team.teamInboxCleared":{"properties":{"read":{"description":"Read is how many notifications this call marked read.","format":"int64","type":"integer"}},"type":"object"},"team.teamInboxItem":{"properties":{"archived":{"description":"Archived reports that the caller archived it.","type":"boolean"},"createdOn":{"description":"CreatedOn is when it was filed, unix milliseconds.","format":"int64","type":"integer"},"doc":{"description":"Doc is the document it is about, when it is about a document.","type":"string"},"id":{"description":"ID is the notification's own id — what read and archive address.","type":"string"},"message":{"$ref":"#/components/schemas/team.teamMessage","description":"Message is the message that caused it, as the message ops answer it.\nAbsent when that message has since been deleted, or is in a room the\ncaller can no longer see."},"read":{"description":"Read reports that the caller has seen it.","type":"boolean"},"reason":{"description":"Reason is why it was filed: \"mention\", \"dm\" (a direct message), \"reply\" (in\na thread the caller is in), \"comment\" (on something the caller follows),\n\"assigned\", or \"other\".","type":"string"},"room":{"description":"Room is the room it is about, when it is about a room.","type":"string"},"space":{"description":"Space is the space uuid it was filed in.","type":"string"},"thread":{"description":"Thread is the message whose thread it is about, for a reply.","type":"string"}},"type":"object"},"team.teamMember":{"properties":{"active":{"description":"Active is false for an agent the org has retired: it stays in the roster so\nits past messages keep an author, and it no longer answers.","type":"boolean"},"avatar":{"description":"Avatar is the blob id of an uploaded picture, readable at\nGET /v1/team/files/{space}/avatar?file={avatar}. Empty when the person has\nnone and the client draws initials.","type":"string"},"bot":{"description":"Bot reports that this member is one of the org's agents rather than a\nperson. An agent answers when it is @-mentioned or messaged directly.","type":"boolean"},"id":{"description":"ID is the account uuid — the value every message's author, every room's\nmembers list and every `\u003c@id\u003e` mention token names.","type":"string"},"name":{"description":"Name is what to call them: the name IAM holds for a person, the agent's\nown name for an agent. Falls back to the id when neither has one.","type":"string"},"personRef":{"description":"PersonRef is the member's Person document id, the reference a mention\nstores.","type":"string"},"presence":{"description":"Presence is \"online\" while the member holds a live connection to this\nspace (a Team client or an event stream), \"offline\" otherwise.","type":"string"},"role":{"description":"Role is the member's role in the space — owner, admin, member or guest.\nAgents read \"member\".","type":"string"}},"type":"object"},"team.teamMembers":{"properties":{"degraded":{"description":"Degraded names a roster source that did not answer — \"agents\" — so an\nempty agent list reads as an outage rather than as an org with no agents.\nAbsent when every source answered.","items":{"type":"string"},"type":"array"},"members":{"description":"Members are the space's people and the org's agents, people first, each\ngroup by name.","items":{"$ref":"#/components/schemas/team.teamMember"},"type":"array"}},"type":"object"},"team.teamMessage":{"properties":{"author":{"description":"Author is the team account uuid that wrote it. It is an ACCOUNT and not a\ndisplay name: what to call somebody is the roster's answer\n(GET /v1/team/members), and copying it onto every message is how the two\ncome to disagree. An agent's messages carry the account derived from its\nid, so the same field answers for both.","type":"string"},"createdOn":{"description":"CreatedOn is unix MILLIseconds, which is what the platform stamps.","format":"int64","type":"integer"},"doc":{"description":"Doc is the document this message is a comment on. Empty for a message in a\nroom.","type":"string"},"editedOn":{"description":"EditedOn is when the author last edited the message, unix milliseconds.\nAbsent for a message never edited.","format":"int64","type":"integer"},"files":{"description":"Files are the files attached to the message.","items":{"$ref":"#/components/schemas/team.teamFile"},"type":"array"},"id":{"description":"ID is the message document's own id.","type":"string"},"lastReply":{"description":"LastReply is when the thread was last answered, unix milliseconds. Absent\nfor a message with no replies.","format":"int64","type":"integer"},"mentions":{"description":"Mentions are the account uuids the message @-mentions — exactly the\npeople notify.go told they were mentioned.","items":{"type":"string"},"type":"array"},"reactions":{"description":"Reactions are the emoji people reacted with, one entry per emoji, in the\norder each emoji was first used.","items":{"$ref":"#/components/schemas/team.teamReaction"},"type":"array"},"replies":{"description":"Replies is how many replies the message's thread holds.","format":"int64","type":"integer"},"room":{"description":"Room is the room it was said in — the same id the room listing answers\nwith, so a caller holding a message can name its room without a second read.\nA reply names the room its thread is in; a comment on a document has none.","type":"string"},"text":{"description":"Text is the message as PLAIN TEXT. The document stores markup; this is the\nsame `plainText` reduction the agent responder reads a prompt with, so a\ncaller never has to parse the client's markup to know what was said. A\nmention reads as \"@Name\" here and is listed by id in Mentions.","type":"string"},"thread":{"description":"Thread is the message this one replies to. Empty for a message that starts\na conversation rather than answering one.","type":"string"}},"type":"object"},"team.teamMessageEdit":{"properties":{"id":{"description":"ID is the message, from the path.","type":"string"},"space":{"description":"Space names the space holding it. Body-only.","type":"string"},"text":{"description":"Text is the message's new text, with the same `\u003c@account-uuid\u003e` mentions\na new message takes. Somebody newly mentioned is notified; somebody already\nmentioned is not notified twice.","type":"string"}},"type":"object"},"team.teamMessageWrite":{"properties":{"files":{"description":"Files attaches blobs already uploaded to the space. A message may be\nfiles alone, with no text.","items":{"$ref":"#/components/schemas/team.teamFileIn"},"type":"array"},"id":{"description":"ID is the room to say it in, from the path.","type":"string"},"space":{"description":"Space names the space holding the room. Body-only: a query string may not\nredirect a write.","type":"string"},"text":{"description":"Text is what to say, as plain text. It is wrapped in the client's markup on\nthe way in, so a caller writes words rather than HTML. `\u003c@account-uuid\u003e`\nmentions a member of the space: it is stored as the platform's mention, so\nthey are notified, and an agent mentioned this way answers.","type":"string"}},"type":"object"},"team.teamMessages":{"properties":{"messages":{"description":"Messages are the conversation's, oldest first, at most `messageMax` of\nthem.","items":{"$ref":"#/components/schemas/team.teamMessage"},"type":"array"}},"type":"object"},"team.teamReaction":{"properties":{"accounts":{"description":"Accounts are the account uuids that reacted with it, earliest first.","items":{"type":"string"},"type":"array"},"count":{"description":"Count is how many people reacted with it.","format":"int64","type":"integer"},"emoji":{"description":"Emoji is the reaction itself, as the person picked it.","type":"string"}},"type":"object"},"team.teamReactionWrite":{"properties":{"emoji":{"description":"Emoji is the reaction, from the path (percent-encoded on the wire).","type":"string"},"id":{"description":"ID is the message, from the path.","type":"string"},"space":{"description":"Space names the space holding the message. Body-only.","type":"string"}},"type":"object"},"team.teamReplyWrite":{"properties":{"files":{"description":"Files attaches blobs already uploaded to the space.","items":{"$ref":"#/components/schemas/team.teamFileIn"},"type":"array"},"id":{"description":"ID is the message being answered, from the path.","type":"string"},"space":{"description":"Space names the space holding it. Body-only.","type":"string"},"text":{"description":"Text is the reply, with the same `\u003c@account-uuid\u003e` mentions a message\ntakes.","type":"string"}},"type":"object"},"team.teamRoom":{"properties":{"archived":{"description":"Archived reports that the room has been closed. It is the platform's own\nSpace attribute — the same one the Team client writes — and NOT a field of\nthe work facet, so there is exactly one answer to \"is this room open\".","type":"boolean"},"bindings":{"description":"Bindings are what this room is ABOUT, each a \"\u003ckind\u003e:\u003cref\u003e\" string —\n\"project:acme/web\", \"repo:hanzoai/cloud\", \"issue:1010\". One list rather\nthan one field per kind, because the next thing a room can be about should\nnot be a schema change; and a bound value is opaque here on purpose, since\nthe app that owns a project is the app that can resolve one. HIP-0523 §2:\na binding is a REFERENCE, never a copy — a room holding an issue's title or\nstatus would be the parallel work-item store HIP-1160 §1 forbids.","items":{"type":"string"},"type":"array"},"direct":{"description":"Direct reports that this is a room between people rather than a named\nroom. It is derived from the document's class, so it cannot disagree\nwith what the client will render.","type":"boolean"},"id":{"description":"ID is the room document's own id, and the value the bind op addresses.\nIt is unique within a space, not across the org.","type":"string"},"kind":{"description":"Kind is what sort of room this is: \"channel\" (open to everyone in the\nspace), \"private\" (open to its members) or \"dm\" (a conversation between\nthe people in it). It is derived from the class and the private flag, so it\ncannot disagree with Direct and Private beside it.","type":"string"},"life":{"description":"Life is the room's lifecycle INTENT — \"standing\" or \"bound\" (HIP-0523 §2).\nAbsent on the document it reads \"standing\": a room nobody classified is one\nthat persists.","type":"string"},"members":{"description":"Members are the account uuids in the room, agents included: an agent\nprojects as a space member under a uuid derived from its id, so a\ncaller comparing this against GET /v1/bot/members learns which rooms an\nagent is in.","items":{"type":"string"},"type":"array"},"name":{"description":"Name is what a person sees in a sidebar. A direct message carries none, so\nthis is empty for one — the members are its name.","type":"string"},"private":{"description":"Private reports that the room is restricted to its members.","type":"boolean"},"space":{"description":"Space is the space uuid holding this room. It is part of the\nroom's address: two spaces of one org may each hold a room with\nthe same name, and only the pair identifies one.","type":"string"},"topic":{"description":"Topic is the room's own one-line subject, as the Team client sets it.","type":"string"}},"type":"object"},"team.teamRoomBind":{"properties":{"bindings":{"description":"Bindings REPLACES what the room is about, wholly. It is a replace and\nnot a merge because a caller that cannot remove a binding would have no way\nto correct a wrong one, and an empty list sent explicitly is how a room\nis unbound. Absent (null) leaves the existing list alone.","items":{"type":"string"},"type":"array"},"id":{"description":"ID is the room to bind, from the path. The URL is the authority; a body\ncarrying another id cannot redirect the write.","type":"string"},"life":{"description":"Life sets the lifecycle intent: \"standing\" or \"bound\". Any other\nvalue is refused rather than stored, so a reader never has to interpret a\nthird one. Empty leaves the current intent unchanged.","type":"string"},"space":{"description":"Space names the space holding the room. It is required, because\na room id is unique only within one and searching every space for a\nmatching id would make the write's target depend on iteration order.","type":"string"}},"type":"object"},"team.teamRoomEdit":{"properties":{"archived":{"description":"Archived closes the room (true) or reopens it (false). An archived room\nkeeps its history and takes no new messages.","type":"boolean"},"id":{"description":"ID is the room, from the path.","type":"string"},"name":{"description":"Name renames a channel. A direct message has no name.","type":"string"},"space":{"description":"Space is the space uuid holding it. Body-only.","type":"string"},"topic":{"description":"Topic sets the channel's one-line subject; \"\" clears it.","type":"string"}},"type":"object"},"team.teamRoomJoin":{"properties":{"id":{"description":"ID is the room, from the path.","type":"string"},"members":{"description":"Members are the account uuids to add — people or agents of the space.\nNaming only yourself joins a public channel.","items":{"type":"string"},"type":"array"},"space":{"description":"Space is the space uuid holding it. Body-only.","type":"string"}},"type":"object"},"team.teamRoomMembers":{"properties":{"members":{"description":"Members are the room's people and agents, as the roster describes them.\nAn account the space no longer knows is listed by id, with no role.","items":{"$ref":"#/components/schemas/team.teamMember"},"type":"array"}},"type":"object"},"team.teamRoomNew":{"properties":{"bindings":{"description":"Bindings are what the room is about, each \"\u003ckind\u003e:\u003cref\u003e\".","items":{"type":"string"},"type":"array"},"life":{"description":"Life is the lifecycle intent, \"standing\" or \"bound\"; empty reads standing.","type":"string"},"members":{"description":"Members are the account uuids in the room. A public room may open empty —\nanyone in the org can find it — and a private one that names nobody is\nrefused rather than created unreachable.","items":{"type":"string"},"type":"array"},"name":{"description":"Name is what a person sees in a sidebar — \"bugfix-1010\", not \"#bugfix-1010\".\nThe sigil is how a client DRAWS a room, and storing it would put it in the\nname twice the first time a client added its own.","type":"string"},"private":{"description":"Private restricts the room to its members. Public is the default because a\nroom nobody can find is the more surprising of the two.","type":"boolean"},"space":{"description":"Space is where the room is opened. Optional: an org with one space has no\nchoice to make, so it does not have to state one. An org with several must,\nbecause picking for it would make the room's home depend on iteration order.","type":"string"},"topic":{"description":"Topic is the room's one-line subject.","type":"string"}},"type":"object"},"team.teamRooms":{"properties":{"rooms":{"description":"Rooms is every room of every space the caller's org owns, each\nwith the work facet it carries.","items":{"$ref":"#/components/schemas/team.teamRoom"},"type":"array"}},"type":"object"},"team.teamTeamspace":{"properties":{"archived":{"description":"Archived reports that the teamspace is closed: its documents still read,\nand none can be created, moved into it, renamed or commented on.","type":"boolean"},"id":{"description":"ID is the teamspace document's id, the value teamDoc.teamspace names.","type":"string"},"name":{"description":"Name is what a person sees in a sidebar.","type":"string"},"private":{"description":"Private reports that the teamspace is open to its members only.","type":"boolean"}},"type":"object"},"tel.Call":{"properties":{"agent":{"description":"Agent names the Hanzo assistant handling the call. Set means the call was\nanswered by that assistant rather than connected to a person.","type":"string"},"from":{"description":"From is the calling number in E.164. It must be one this org holds: a carrier\nrefuses an origination from a number nobody proved they own.","type":"string"},"id":{"description":"ID is the carrier's handle for the call — what a hangup or a lookup names.","type":"string"},"org":{"description":"Org is the tenant the call was placed for or received by.","type":"string"},"status":{"description":"Status is where the call is: \"queued\", \"ringing\", \"answered\", \"completed\" or\n\"failed\". Only the last two are terminal.","type":"string"},"to":{"description":"To is the called number in E.164.","type":"string"}},"type":"object"},"tel.Number":{"properties":{"capable":{"description":"Capable is what the number can carry: any of \"voice\", \"sms\", \"mms\", \"fax\". A\nnumber missing \"sms\" cannot send one no matter what this platform does.","items":{"type":"string"},"type":"array"},"country":{"description":"Country is the ISO 3166-1 alpha-2 code the number is issued under. Numbering is\nnational, so this is what makes a search answerable at all.","type":"string"},"currency":{"description":"Currency is the ISO 4217 code Monthly is denominated in. Without it the number\nbeside it means nothing, so the two are always read together.","type":"string"},"e164":{"description":"E164 is the number in E.164: a leading + and digits only, no spaces or dashes.\nThat is what a carrier accepts and what a search result must be bought by.","type":"string"},"id":{"description":"ID is the carrier's handle for the number, and the id every route here\naddresses it by. It is not the number itself — see E164.","type":"string"},"monthly":{"description":"Monthly is the recurring rental in the MINOR unit of Currency (cents for USD),\nexactly as the carrier quoted it. It is a price, not a charge: nothing is billed\nby this field.","format":"int64","type":"integer"},"org":{"description":"Org is the tenant holding the number. A search result carries none — nobody\nholds it yet — which is how an available number is told from a held one.","type":"string"},"type":{"description":"Type is what kind of number it is: \"local\", \"national\", \"tollfree\" or \"mobile\".\nIt decides both price and what a carrier will let it originate.","type":"string"}},"type":"object"},"tel.SMS":{"properties":{"from":{"description":"From is the sending number in E.164, and must be one this org holds.","type":"string"},"id":{"description":"ID is the carrier's handle for the message.","type":"string"},"org":{"description":"Org is the tenant the message was sent for or received by.","type":"string"},"status":{"description":"Status is where the message is: \"queued\", \"sent\", \"delivered\" or \"failed\".\n\"sent\" means the carrier took it; \"delivered\" means the handset got it, and\nnot every carrier or destination reports that.","type":"string"},"text":{"description":"Text is the message body. Empty is legal when the message carried only media.","type":"string"},"to":{"description":"To is the receiving number in E.164.","type":"string"}},"type":"object"},"tel.buyInput":{"properties":{"e164":{"description":"E164 is the number to buy, in E.164 (a leading + and digits), exactly as the\nsearch returned it. This is the number itself, not the id from a search result.","type":"string"}},"type":"object"},"tel.callInput":{"properties":{"agent":{"description":"Agent hands the answered call to a Hanzo assistant by name instead of\nconnecting it to a person. Empty places an ordinary call.","type":"string"},"from":{"description":"From is the number to call FROM, in E.164. It must be one this org holds.","type":"string"},"record":{"description":"Record is a per-call flag rather than a product. Where a recording lands and\nhow long it is kept is the org's retention policy, not this call's.","type":"boolean"},"to":{"description":"To is the number to call, in E.164.","type":"string"},"webhook":{"description":"Webhook is a URL the carrier posts this call's events to as it progresses.\nEmpty means the call's outcome is only visible by reading it back.","type":"string"}},"type":"object"},"tel.callList":{"properties":{"data":{"description":"Data is this org's own calls, newest first — what this platform placed or\nreceived on its behalf, which is our record rather than the carrier's.","items":{"$ref":"#/components/schemas/tel.Call"},"type":"array"}},"type":"object"},"tel.messageInput":{"properties":{"from":{"description":"From is the number to send FROM, in E.164. It must be one this org holds and it\nmust be sms-capable.","type":"string"},"media":{"description":"Media are URLs to attach. A message with any is an MMS to the carrier — the\ndistinction is the carrier's to make, not something the caller declares.","items":{"type":"string"},"type":"array"},"text":{"description":"Text is the message body. It may be empty when Media carries the message.","type":"string"},"to":{"description":"To is the number to send to, in E.164.","type":"string"}},"type":"object"},"tel.messageList":{"properties":{"data":{"description":"Data is this org's own messages, newest first — from our store rather than the\ncarrier's, so it is the set an audit or a bill has to agree with.","items":{"$ref":"#/components/schemas/tel.SMS"},"type":"array"}},"type":"object"},"tel.numberList":{"properties":{"data":{"description":"Data is the numbers, and which numbers depends on the route: a search answers\nwhat the carrier has available, a list answers what this org already holds.","items":{"$ref":"#/components/schemas/tel.Number"},"type":"array"}},"type":"object"},"tel.summary":{"properties":{"calls":{"description":"Calls is how many calls this org has placed or received, over its whole\nhistory — a running total, not a window.","format":"int64","type":"integer"},"messages":{"description":"Messages is the same running total for messages.","format":"int64","type":"integer"},"numbers":{"description":"Numbers is how many numbers this org holds right now.","format":"int64","type":"integer"}},"type":"object"},"template.StarterKit":{"properties":{"category":{"description":"groups the kit in the gallery browser (\"Portfolio\", \"SaaS\")","type":"string"},"demo":{"description":"live demo (\u003cslug\u003e.hanzo.app), when deployed","type":"string"},"description":{"description":"the browse-card blurb","type":"string"},"features":{"description":"the highlights the card lists, at most 32","items":{"type":"string"},"type":"array"},"framework":{"description":"the stack the kit is built on (\"Next.js 14.2 + TS\")","type":"string"},"org":{"description":"owner of a PRIVATE template; empty in the public catalog","type":"string"},"preview":{"description":"the still image the browse card renders","type":"string"},"rating":{"description":"Rating is public-gallery curation, on the same terms as Tier: catalog-only,\nnever accepted from a request, absent on a customer's own kit.","format":"double","type":"number"},"slug":{"description":"the kit's identity — lowercase alphanumeric with dashes, max 40","type":"string"},"source":{"description":"the repository the kit is forked from","type":"string"},"tier":{"description":"Tier is public-gallery curation, carried verbatim from the embedded catalog.\nNo request can set it — neither write body has the field and neither builds a\nkit carrying one — so it is absent on every customer-published kit.","format":"int64","type":"integer"},"title":{"description":"display name","type":"string"},"useCase":{"description":"what the kit is for, in a phrase","type":"string"},"variants":{"description":"the shapes this template ships in","items":{"$ref":"#/components/schemas/template.Variant"},"type":"array"}},"type":"object"},"template.Variant":{"properties":{"framework":{"description":"only when it differs from the template's","type":"string"},"id":{"description":"selector, unique within the template (\"react\", \"grid-3-fluid\")","type":"string"},"kind":{"description":"the axis it varies: format | page | theme","type":"string"},"label":{"description":"human label for the picker","type":"string"},"source":{"description":"the repository this shape is forked from; the synthesized default shape carries the template's own","type":"string"}},"type":"object"},"template.kitList":{"properties":{"data":{"description":"Data is the public catalog followed by the caller org's own kits.","items":{"$ref":"#/components/schemas/template.StarterKit"},"type":"array"}},"type":"object"},"template.publishKitIn":{"properties":{"category":{"description":"Category groups the kit in the gallery browser.","type":"string"},"demo":{"description":"Demo is the deployed site itself, when there is one.","type":"string"},"description":{"description":"Description is the browse-card blurb, max 4096 characters.","type":"string"},"features":{"description":"Features are the highlights the card lists, at most 32.","items":{"type":"string"},"type":"array"},"framework":{"description":"Framework is the stack the kit is built on (\"Next.js 14\").","type":"string"},"preview":{"description":"Preview is the still image the browse card renders, max 4096 characters.","type":"string"},"slug":{"description":"Slug is the kit's identity — lowercase alphanumeric with dashes, max 40.","type":"string"},"source":{"description":"Source is the repository the kit is forked from, max 4096 characters.","type":"string"},"title":{"description":"Title is the display name. Required, max 200 characters.","type":"string"},"useCase":{"description":"UseCase is what the kit is for, in a phrase.","type":"string"},"variants":{"description":"Variants are the shapes this kit ships in, at most 32; the fork picks one.","items":{"$ref":"#/components/schemas/template.Variant"},"type":"array"}},"type":"object"},"template.replaceKitIn":{"properties":{"category":{"description":"Category groups the kit in the gallery browser.","type":"string"},"demo":{"description":"Demo is the deployed site itself, when there is one.","type":"string"},"description":{"description":"Description is the browse-card blurb, max 4096 characters.","type":"string"},"features":{"description":"Features are the highlights the card lists, at most 32.","items":{"type":"string"},"type":"array"},"framework":{"description":"Framework is the stack the kit is built on (\"Next.js 14\").","type":"string"},"preview":{"description":"Preview is the still image the browse card renders, max 4096 characters.","type":"string"},"slug":{"description":"Slug is the kit to replace, from the path.","type":"string"},"source":{"description":"Source is the repository the kit is forked from, max 4096 characters.","type":"string"},"title":{"description":"Title is the display name. Required, max 200 characters.","type":"string"},"useCase":{"description":"UseCase is what the kit is for, in a phrase.","type":"string"},"variants":{"description":"Variants are the shapes this kit ships in, at most 32; the fork picks one.","items":{"$ref":"#/components/schemas/template.Variant"},"type":"array"}},"type":"object"},"tool.AuthoredPlugin":{"properties":{"createdAt":{"description":"CreatedAt is when the plugin was last built, Unix seconds.","format":"int64","type":"integer"},"id":{"description":"ID is the plugin's id within the org, and the id a delete addresses.","type":"string"},"name":{"description":"Name is the plugin's name: one lowercase path segment, the id it runs by.","type":"string"},"org":{"description":"Org is the org that built the plugin — the validated caller's.","type":"string"},"provider":{"description":"Provider is the connectors provider whose credential this plugin uses at\nrun time. Absent for a plugin that needs none. The credential itself is\nnever here — it stays under KMS custody in the connectors plane.","type":"string"},"source":{"description":"Source is the TypeScript as authored (or as generated from a spec).","type":"string"}},"type":"object"},"tool.Kit":{"properties":{"excess":{"description":"Excess are servers left out, by id, because a run carries only so many.","items":{"type":"string"},"type":"array"},"muted":{"description":"Muted are the names the run's person took out of their own runs — a\nskill, a server's tool, or a server by its id. None of them is above.","items":{"type":"string"},"type":"array"},"omitted":{"description":"Omitted are activated skills left out because a run carries only so many.","items":{"type":"string"},"type":"array"},"servers":{"description":"Servers are the MCP servers an admin registered and activated tools of, at\nmost KitServers of them.","items":{"$ref":"#/components/schemas/tool.Remote"},"type":"array"},"skills":{"description":"Skills are the documents of the skills an admin activated, by name.","items":{"$ref":"#/components/schemas/tool.SkillDoc"},"type":"array"}},"type":"object"},"tool.MCPListing":{"properties":{"description":{"description":"Description is the publisher's one-line summary.","type":"string"},"featured":{"description":"Featured puts the listing on the front of the shelf. Curation.","type":"boolean"},"hidden":{"description":"Hidden keeps the listing out of the org-visible catalog. Curation: a sync\nnever changes it. Only a SuperAdmin sets it, and only a SuperAdmin sees a\nhidden entry listed.","type":"boolean"},"id":{"description":"ID addresses the listing in a URL. It is the reverse-DNS NAME with its one\nslash written as an underscore — reversible, because a namespace never\ncontains an underscore — so the id is readable and stable rather than a\nhash that means nothing to whoever reads a link.","type":"string"},"logo":{"description":"Logo is the brand mark to render for the listing — the publisher's icon when\nthe entry carries one, or the one an admin set. Curation.","type":"string"},"name":{"description":"Name is the publisher's reverse-DNS name, e.g. \"com.stripe/mcp\".","type":"string"},"official":{"description":"Official is whether this is the vendor's OWN server rather than someone\nelse's copy of it. Derived on every sync (see isOfficial) until a\nSuperAdmin sets it explicitly, after which the admin's answer stands.","type":"boolean"},"packages":{"description":"Packages are the runnable package forms — npm, pypi, oci — each with the\nruntime that launches it and the transport it then speaks.","items":{"$ref":"#/components/schemas/tool.MCPPackage"},"type":"array"},"registry":{"description":"Registry is the upstream this row was synced from.","type":"string"},"remotes":{"description":"Remotes are the hosted endpoints the publisher serves the server at.","items":{"$ref":"#/components/schemas/tool.MCPRemote"},"type":"array"},"repo":{"description":"Repo is the source repository URL, when the entry names one.","type":"string"},"site":{"description":"Site is the project's homepage, when the entry names one.","type":"string"},"synced":{"description":"Synced is when this row was last confirmed against upstream, Unix seconds.","format":"int64","type":"integer"},"title":{"description":"Title is the human-readable display name, when the entry carries one.","type":"string"},"transports":{"description":"Transports are the distinct transports this server can be reached over,\nsorted: some of \"stdio\", \"streamable-http\", \"sse\". A listing with\n\"streamable-http\" is one an org can enable here and now; a listing that is\nonly \"stdio\" needs a process to run it.","items":{"type":"string"},"type":"array"},"vendor":{"description":"Vendor is the namespace half of Name — the publisher, e.g. \"com.stripe\".","type":"string"},"version":{"description":"Version is the published version of this listing.","type":"string"}},"type":"object"},"tool.MCPPackage":{"properties":{"identifier":{"description":"Identifier is the package name or download URL.","type":"string"},"registry":{"description":"Registry is where the package is fetched from: npm, pypi, oci, nuget, mcpb.","type":"string"},"runtime":{"description":"Runtime is the publisher's hint for what launches it: npx, uvx, docker.","type":"string"},"transport":{"description":"Transport is what the launched process speaks: usually \"stdio\".","type":"string"},"version":{"description":"Version is the exact published package version.","type":"string"}},"type":"object"},"tool.MCPRemote":{"properties":{"transport":{"description":"Transport is \"streamable-http\" or \"sse\".","type":"string"},"url":{"description":"URL is the endpoint.","type":"string"}},"type":"object"},"tool.MCPServer":{"properties":{"admitted":{"description":"Admitted is whether an admin of the org, or a SuperAdmin, registered the\nserver. Only an admitted server is carried into the org's agent runs: a\nserver registered before registering one took an admin is not, until an\nadmin registers it again.","type":"boolean"},"authHeader":{"description":"AuthHeader is the request header the KMS-held credential is injected into,\ne.g. \"Authorization\". Absent when the server needs no credential.","type":"string"},"createdAt":{"description":"CreatedAt is when the server was registered, Unix seconds.","format":"int64","type":"integer"},"hasSecret":{"description":"HasSecret is whether a credential is sealed in KMS for this server. The\nVALUE is never returned by any route.","type":"boolean"},"id":{"description":"ID is the server's id within the org. It also PREFIXES every tool name the\nserver contributes, which is what keeps two servers' \"search\" apart.","type":"string"},"listing":{"description":"Listing is the catalog entry this server was enabled from, when it was.\nEmpty means the org typed the URL in itself.","type":"string"},"name":{"description":"Name is the org's label for the server.","type":"string"},"org":{"description":"Org is the org that registered the server — the validated caller's.","type":"string"},"reason":{"description":"Reason says why a server that is not \"ok\" is not, in words any member may\nbe shown: never the server's address.","type":"string"},"source":{"description":"Source is where the registration came from: \"catalog\" when it was enabled\noff the shelf, \"org\" when the org registered the URL itself. It is DERIVED\nfrom Listing rather than stored, because two columns for one fact is two\nchances to disagree.","type":"string"},"status":{"description":"Status is whether the server's tools could be listed when the org's\nservers were read: \"ok\", \"unreachable\", \"refused\" or \"error\". Only the\nlisting answers it; a registration does not.","type":"string"},"tools":{"description":"Tools is how many tools the server listed, when it listed them.","format":"int64","type":"integer"},"url":{"description":"URL is the server's JSON-RPC endpoint. Always a public http(s) host: the\nregistration boundary and the dialer both refuse anything else.","type":"string"}},"type":"object"},"tool.Price":{"properties":{"amount":{"description":"Amount is what ONE call costs, EXACTLY: an 18-decimal USD value, so a\nper-call price of $0.0025 is $0.0025 and not a cent-floored zero. Cents\ncannot hold a per-token price, and a tool plane is where per-token prices\nlive."},"currency":{"description":"Currency is the ISO 4217 code, e.g. \"USD\". Empty means USD.","type":"string"},"recipient":{"description":"Recipient is the payout wallet ref the marketplace seller is paid at.","type":"string"}},"type":"object"},"tool.Remote":{"properties":{"name":{"description":"Name is the server's id in the org, which also prefixes its tools on the\ntool plane, and names it to ToolsRelay.","type":"string"},"tools":{"description":"Tools are the tools of it an admin activated, each by the server's own\nname for it: all a run's harness may call of it.","items":{"type":"string"},"type":"array"}},"type":"object"},"tool.Skill":{"properties":{"admitted":{"description":"Admitted is whether an admin of the org, or a SuperAdmin, wrote this\ncontent. Only admitted content is carried into the org's agent runs. A\npush writes content nobody administering the org attested, and a skill\nwritten before writing one took an admin says no until an admin writes it\nagain.","type":"boolean"},"content":{"description":"Content is the SKILL.md body, markdown.","type":"string"},"createdAt":{"description":"CreatedAt is when the skill was last written, Unix seconds.","format":"int64","type":"integer"},"description":{"description":"Description is the one-line summary discovery shows for the skill.","type":"string"},"id":{"description":"ID is the skill's id within the org. It is DERIVED from Name, so writing\nthe same name again revises that skill rather than adding another.","type":"string"},"name":{"description":"Name is the skill's name: one lowercase path segment (a-z0-9, _ or -).","type":"string"},"org":{"description":"Org is the org that authored the skill — the validated caller's, never a\nvalue the body supplied.","type":"string"},"source":{"description":"Source is the repository the skill was read from, \"\u003cproject\u003e/\u003cname\u003e\" or\n\"\u003cname\u003e\"; empty for a skill written through the API. A push replaces every\nskill of its source at once, so a skill leaves when its file does.","type":"string"}},"type":"object"},"tool.SkillDoc":{"properties":{"content":{"description":"Content is the skill's SKILL.md, verbatim.","type":"string"},"name":{"description":"Name is the skill's bare name, which is also the directory its SKILL.md\nis written into.","type":"string"}},"type":"object"},"tool.Tool":{"properties":{"activated":{"description":"Activated is filled by the registry from the activation store for the\nrequesting (org,project); providers leave it zero. An unactivated tool is\ndiscoverable but refused 403 at dispatch.","type":"boolean"},"description":{"description":"Description is the prose a model reads to decide whether to call the tool.","type":"string"},"dispatchable":{"description":"Dispatchable is whether the tool can be CALLED. False for a listing-only\nentry: a skill is activated and attached to an agent, never called.","type":"boolean"},"inputSchema":{"description":"Schema is the JSON Schema of the call arguments — the MCP inputSchema.\nAbsent for a tool that takes none."},"name":{"description":"Name is the tool's id in the flat, fleet-wide tool namespace — the value a\ntools/call passes. Unique across sources: a collision is resolved by source\nprecedence before the caller ever sees it.","type":"string"},"price":{"$ref":"#/components/schemas/tool.Price","description":"Price is what a call costs and who is paid, absent for a free tool.\nEnforcement is the x402 settlement client; this is the declaration."},"source":{"description":"Source is where the tool comes from: connector, function, zap-service,\nagent, skill or mcp.","type":"string"}},"type":"object"},"tool.activationReq":{"properties":{"activate":{"description":"Activate switches these tool names on for the caller's org and project.","items":{"type":"string"},"type":"array"},"deactivate":{"description":"Deactivate switches these tool names off.","items":{"type":"string"},"type":"array"}},"type":"object"},"tool.activationSet":{"properties":{"enabled":{"description":"Enabled is every tool name activated for the caller's org and project.","items":{"type":"string"},"type":"array"}},"type":"object"},"tool.authoredPluginList":{"properties":{"plugins":{"description":"Plugins is every plugin this org built, newest first, each carrying the\nTypeScript as authored. The bundled artifact is never rendered.","items":{"$ref":"#/components/schemas/tool.AuthoredPlugin"},"type":"array"}},"type":"object"},"tool.authoredSkillList":{"properties":{"skills":{"description":"Skills is every skill this org authored, each with its SKILL.md content.","items":{"$ref":"#/components/schemas/tool.Skill"},"type":"array"}},"type":"object"},"tool.buildOut":{"properties":{"bytes":{"description":"Bytes is the size of the bundled CommonJS the runtime will execute.","format":"int64","type":"integer"},"generated":{"description":"Generated is whether a model wrote the source from a spec, rather than the\ncaller posting the source itself.","type":"boolean"},"plugin":{"$ref":"#/components/schemas/tool.AuthoredPlugin","description":"Plugin is the plugin as stored, with its derived id and build time."}},"type":"object"},"tool.buildRequest":{"properties":{"name":{"description":"Name is the plugin's name: one lowercase path segment (a-z0-9, _ or -),\nand the id the runtime loads it by.","type":"string"},"provider":{"description":"Provider is the connectors provider whose credential the plugin reads at\nrun time. Empty for a plugin that needs none.","type":"string"},"source":{"description":"Source is TypeScript to build as-is. Exactly one of Source or Spec.","type":"string"},"spec":{"description":"Spec is API documentation — an OpenAPI document, or prose describing the\nendpoints — that the generator turns into Source. The generated source is\nreturned in the response, so a caller can read what will run before it runs.","type":"string"}},"type":"object"},"tool.createServerReq":{"properties":{"authHeader":{"description":"AuthHeader is the request header the credential is injected into, e.g.\n\"Authorization\". Empty means the server needs no credential.","type":"string"},"listing":{"description":"Listing enables a CATALOG entry instead — the id from GET /v1/tool/catalog.\nThe endpoint is the listing's own streamable-http remote, so a listing that\nonly ships a stdio package is refused: there is nothing to reach yet.","type":"string"},"name":{"description":"Name labels the server for the org. Required with URL; with Listing it\ndefaults to the listing's own title.","type":"string"},"secret":{"description":"Secret is the credential VALUE. It is sealed into KMS under a per-org ref\nand never stored in SQLite, never listed, and never returned.","type":"string"},"url":{"description":"URL is the server's JSON-RPC endpoint. It must be an http(s) URL naming a\nPUBLIC host: loopback, link-local, private and cloud-metadata addresses are\nrefused here and again when the dialer connects. A URL carrying a credential\n(user:password@) is refused: the credential is the secret.","type":"string"}},"type":"object"},"tool.mcpCatalog":{"properties":{"catalog":{"description":"Catalog is this page of listings, featured first, then by name.","items":{"$ref":"#/components/schemas/tool.MCPListing"},"type":"array"},"limit":{"description":"Limit is the page size that was actually applied — the default or the clamp,\nwhen the request asked for neither or for too much.","format":"int64","type":"integer"},"offset":{"description":"Offset is where this page started, so a caller pages from what the server\ndid rather than from what it asked for.","format":"int64","type":"integer"},"total":{"description":"Total is how many listings the filter matched, which is more than this page\nholds whenever there is a next one.","format":"int64","type":"integer"}},"type":"object"},"tool.mcpServerList":{"properties":{"servers":{"description":"Servers is every external MCP server this org has registered. No secret\nVALUE is ever included — only whether one is set.","items":{"$ref":"#/components/schemas/tool.MCPServer"},"type":"array"}},"type":"object"},"tool.muteReq":{"properties":{"mute":{"description":"Mute takes these out of the caller's runs: a skill (skill_\u003cname\u003e), a\nserver's tool (\u003cserver\u003e_\u003ctool\u003e) or a whole server (\u003cserver\u003e), each one the\norg's kit carries.","items":{"type":"string"},"type":"array"},"unmute":{"description":"Unmute gives these back, as far as the org's kit carries them.","items":{"type":"string"},"type":"array"}},"type":"object"},"tool.pluginDeleted":{"properties":{"deleted":{"description":"Deleted is the plugin id that is now gone.","type":"string"}},"type":"object"},"tool.pluginMount":{"properties":{"enabled":{"description":"Enabled is whether this subsystem is switched on in this deployment.","type":"boolean"},"name":{"description":"Name is the subsystem's name, the same label a traced request resolves to.","type":"string"},"prefixes":{"description":"Prefixes are the URL prefixes this subsystem serves.","items":{"type":"string"},"type":"array"}},"type":"object"},"tool.pluginMountList":{"properties":{"plugins":{"description":"Plugins is every subsystem the composition root declared, filtered to the\nenabled ones unless all=true.","items":{"$ref":"#/components/schemas/tool.pluginMount"},"type":"array"}},"type":"object"},"tool.skillDeleted":{"properties":{"deleted":{"description":"Deleted is the skill id that is now gone.","type":"string"}},"type":"object"},"tool.skillIn":{"properties":{"content":{"description":"Content is the SKILL.md body. Required, at most 256 KiB.","type":"string"},"description":{"description":"Description is the one-line summary discovery shows for the skill.","type":"string"},"name":{"description":"Name is the skill's id within the org: one lowercase path segment\n(a-z0-9, _ or -). Writing an existing name REVISES that skill.","type":"string"}},"type":"object"},"tool.skillWritten":{"properties":{"skill":{"$ref":"#/components/schemas/tool.Skill","description":"Skill is the skill as stored, with its derived id and creation time."}},"type":"object"},"tool.sourceToolList":{"properties":{"source":{"description":"Source is the source these tools came from.","type":"string"},"tools":{"description":"Tools is the caller's tools from that source. Never null.","items":{"$ref":"#/components/schemas/tool.Tool"},"type":"array"}},"type":"object"},"tool.toolCall":{"properties":{"arguments":{"additionalProperties":{},"description":"Arguments is the tool's own input object, passed through verbatim to\nwhichever source owns it.","type":"object"},"name":{"description":"Name is the tool to run, exactly as GET /v1/tool reports it.","type":"string"}},"type":"object"},"tool.toolList":{"properties":{"tools":{"description":"Tools is every tool the caller may see, deduplicated by name with source\nprecedence applied.","items":{"$ref":"#/components/schemas/tool.Tool"},"type":"array"}},"type":"object"},"tool.toolResult":{"properties":{"name":{"description":"Name is the tool that ran.","type":"string"},"result":{"description":"Result is the tool's own output, verbatim — its shape is the tool's, not\nthis plane's."}},"type":"object"},"train.Adaptation":{"properties":{"alpha":{"description":"Alpha is an adapter's scale.","format":"double","type":"number"},"basis":{"description":"Basis is a basis artifact, by sha256 or `basis://\u003cbase\u003e/\u003cname\u003e`.","type":"string"},"chose":{"$ref":"#/components/schemas/train.Chose","description":"Chose is what auto resolved to and why; absent unless auto was asked."},"mode":{"description":"Mode is full, readout (the head alone, over the frozen base), lora, qlora,\nbasis or auto.","type":"string"},"rank":{"description":"Rank is an adapter's rank, or how many of a basis's directions are used.","format":"int64","type":"integer"},"residual_rank":{"description":"ResidualRank is the rank of an orthonormal residual learned beside a basis's\ncoefficients; 0 trains the coefficients alone.","format":"int64","type":"integer"},"sources":{"description":"Sources are lora artifacts (sha256) a basis is built from, in place of Basis.","items":{"type":"string"},"type":"array"},"targets":{"description":"Targets are the modules an adapter or a basis attaches to.","items":{"type":"string"},"type":"array"}},"type":"object"},"train.Assignment":{"properties":{"job":{"$ref":"#/components/schemas/train.Job","description":"Job is the job it belongs to."},"org":{"description":"Org is the job's org. A platform executor reports for the task acting in it.","type":"string"},"task":{"$ref":"#/components/schemas/train.Claimed","description":"Task is the unit this executor now holds."}},"type":"object"},"train.Budget":{"properties":{"accuracy":{"description":"Accuracy is the largest accuracy drop allowed.","format":"double","type":"number"},"ece":{"description":"ECE is the largest calibration-error rise allowed.","format":"double","type":"number"}},"type":"object"},"train.Capability":{"properties":{"by":{"type":"string"},"corrections":{"description":"Corrections are the corrections it is taught from.","items":{"type":"string"},"type":"array"},"created":{"format":"int64","type":"integer"},"installed":{"description":"Installed is the version in the org's published set, 0 when none.","format":"int64","type":"integer"},"live":{"$ref":"#/components/schemas/train.Live","description":"Live is what its installed version did since it went in."},"name":{"description":"Name is its name, one per org; it is the name its versions install under.","type":"string"},"question":{"$ref":"#/components/schemas/train.Question","description":"Question is what it answers: the route it is installed behind."},"state":{"description":"State is where it is in its life: draft, trained, evaluated, publishable,\ninstalled, active, disabled or needs_validation.","type":"string"},"updated":{"format":"int64","type":"integer"},"version":{"description":"Version is its latest version, 0 in draft.","format":"int64","type":"integer"},"versions":{"description":"Versions are its versions, newest first (one capability read).","items":{"$ref":"#/components/schemas/train.Version"},"type":"array"}},"type":"object"},"train.Capture":{"properties":{"on":{"type":"boolean"},"retention_days":{"description":"RetentionDays is how long a decision's states are kept unless a correction\nnames it.","format":"int64","type":"integer"}},"type":"object"},"train.Chose":{"properties":{"mode":{"description":"Mode is the mode the job runs.","type":"string"},"why":{"description":"Why says what decided it.","type":"string"}},"type":"object"},"train.Claimed":{"properties":{"coordinator":{"description":"Coordinator is where a join task reaches its lead.","type":"string"},"device":{"description":"Device is the accelerator kind it runs on, and Devices how many of them.","type":"string"},"devices":{"format":"int64","type":"integer"},"held":{"description":"Held is the device-seconds held for it. The cloud meters the task by the\nclock and stops its job before it runs past them.","format":"int64","type":"integer"},"id":{"description":"ID names the task.","type":"string"},"job":{"description":"Job names its job.","type":"string"},"lease":{"description":"Lease authenticates every report for the task; it is answered once.","type":"string"},"report":{"description":"Report is the most seconds that may pass between its reports.","format":"int64","type":"integer"},"role":{"description":"Role is lead or join.","type":"string"}},"type":"object"},"train.Correction":{"properties":{"answer":{"type":"string"},"at":{"format":"int64","type":"integer"},"base":{"type":"string"},"by":{"type":"string"},"cohort":{"type":"string"},"decision":{"type":"string"},"id":{"type":"string"},"labels":{"items":{"type":"string"},"type":"array"},"note":{"type":"string"},"question":{"type":"string"},"state":{"type":"string"},"type":{"type":"string"}},"type":"object"},"train.CorrectionGroup":{"properties":{"corrections":{"format":"int64","type":"integer"},"key":{"type":"string"},"labels":{"items":{"type":"string"},"type":"array"},"type":{"type":"string"}},"type":"object"},"train.Dataset":{"properties":{"splits":{"additionalProperties":{"type":"string"},"description":"Splits maps a role (train, validation) to the dataset's own split name.","type":"object"},"uri":{"description":"URI names the data.","type":"string"}},"type":"object"},"train.Download":{"properties":{"created":{"description":"Created is when it was registered, unix seconds.","format":"int64","type":"integer"},"expires":{"description":"Expires is when URL stops working, unix seconds.","format":"int64","type":"integer"},"job":{"description":"Job is the job that produced it; empty for an upload.","type":"string"},"kind":{"description":"Kind is checkpoint, lora, capability, basis or merged, or dataset for an upload.","type":"string"},"meta":{"description":"Meta describes it: its base and revision, its modules, a basis's address."},"name":{"description":"Name labels it.","type":"string"},"sha256":{"description":"SHA256 is the hex digest of its bytes, and its name in the object store.","type":"string"},"size":{"description":"Size is its byte count.","format":"int64","type":"integer"},"state":{"description":"State is pending until its bytes are read back, then stored; deleted once\nthe org deleted it or it outlived its retention unpublished.","type":"string"},"url":{"description":"URL fetches the bytes until Expires; absent until the artifact is stored.","type":"string"}},"type":"object"},"train.Evaluation":{"properties":{"suites":{"description":"Suites are the suites the job is meant to improve.","items":{"type":"string"},"type":"array"}},"type":"object"},"train.Family":{"properties":{"adaptations":{"description":"Adaptations are the methods it trains by: a create's adaptation.mode.","items":{"type":"string"},"type":"array"},"base":{"description":"Base is the base model: `kai`, or `engine` for the models the engine loads.","type":"string"},"datasets":{"description":"Datasets are the dataset URI schemes it reads.","items":{"type":"string"},"type":"array"},"devices":{"description":"Devices are the accelerator kinds it runs on, wherever it runs.","items":{"type":"string"},"type":"array"},"executor":{"description":"Executor is what runs it.","type":"string"},"nouns":{"description":"Nouns are the resources that run it: jobs, clients.","items":{"type":"string"},"type":"array"},"outputs":{"description":"Outputs are the output kinds it produces.","items":{"type":"string"},"type":"array"},"protect":{"description":"Protect are the protections it runs: projection, distillation, capabilities.","items":{"type":"string"},"type":"array"},"runs":{"description":"Runs are where it runs, each with what a device-second costs there.","items":{"$ref":"#/components/schemas/train.Run"},"type":"array"},"terms":{"description":"Terms are the objective terms it runs.","items":{"type":"string"},"type":"array"}},"type":"object"},"train.Job":{"properties":{"adaptation":{"$ref":"#/components/schemas/train.Adaptation","description":"Adaptation is how the update is parameterized."},"artifacts":{"description":"Artifacts are its outputs.","items":{"$ref":"#/components/schemas/train.artifact"},"type":"array"},"base_model":{"description":"BaseModel is the base the capability is taught to: `kai`, or a model the engine\nloads for a client.","type":"string"},"created":{"description":"Created, Started and Ended are unix seconds; 0 is not yet.","format":"int64","type":"integer"},"created_by":{"description":"CreatedBy is the principal that created it.","type":"string"},"dataset":{"$ref":"#/components/schemas/train.Dataset","description":"Dataset is what the job trains on."},"ended":{"format":"int64","type":"integer"},"error":{"description":"Error says why a job failed or stopped. A job stopped at what its payer or\nits own bounds could hold says budget, max_seconds, insufficient_balance,\nspend_cap, balance_unavailable or no_payer.","type":"string"},"evaluation":{"$ref":"#/components/schemas/train.Evaluation","description":"Evaluation names the target suites the result reports."},"from":{"description":"From is an artifact the job starts from, by sha256.","type":"string"},"id":{"description":"ID names the job.","type":"string"},"objective":{"$ref":"#/components/schemas/train.Objective","description":"Objective is the loss and the terms beside it."},"output":{"$ref":"#/components/schemas/train.Output","description":"Output is what the job produces."},"project":{"description":"Project is the creator's project scope.","type":"string"},"protect":{"$ref":"#/components/schemas/train.Protect","description":"Protect names what the base already does that must hold, and the budget."},"published":{"description":"Published is the publish record, once published."},"resources":{"$ref":"#/components/schemas/train.Resources","description":"Resources places and bounds the run."},"result":{"description":"Result is the lead's evaluation and verdict, once reported."},"revision":{"description":"Revision pins the base. For kai: a finished run's name on the executor, or\n`hub:\u003crepo\u003e@\u003crev\u003e`.","type":"string"},"started":{"format":"int64","type":"integer"},"status":{"description":"Status is queued, running, evaluating, succeeded, rejected, failed,\ncancelled or stopped.","type":"string"},"tasks":{"description":"Tasks are its units of execution.","items":{"$ref":"#/components/schemas/train.TaskView"},"type":"array"},"usage":{"$ref":"#/components/schemas/train.Usage","description":"Usage is what its tasks used and what that cost."}},"type":"object"},"train.Live":{"properties":{"damage":{"format":"int64","type":"integer"},"damage_rate":{"format":"double","type":"number"},"fires":{"description":"Fires counts decisions it answered otherwise than the base would have.","format":"int64","type":"integer"},"last_fired":{"description":"LastFired is when it last fired, unix seconds; 0 never.","format":"int64","type":"integer"},"neutral":{"format":"int64","type":"integer"},"repair_rate":{"format":"double","type":"number"},"repairs":{"description":"Repairs are fires that changed the label and no correction contradicts;\nDamage, fires whose label a correction put back to the base's; Neutral,\nfires that kept the base's label.","format":"int64","type":"integer"},"version":{"format":"int64","type":"integer"}},"type":"object"},"train.Object":{"properties":{"expires":{"description":"Expires is when retention deletes it unless published, unix seconds; absent\nwhile it is published, pending, or retention keeps everything.","format":"int64","type":"integer"},"jobs":{"description":"Jobs are the jobs that produced or hold it; none for an upload.","items":{"type":"string"},"type":"array"},"kind":{"description":"Kind is dataset for an upload, else the output kind a job produced it as.","type":"string"},"name":{"description":"Name labels it.","type":"string"},"published":{"description":"Published says a job of the org has it published.","type":"boolean"},"sha256":{"description":"SHA256 names the bytes.","type":"string"},"size":{"description":"Size is its byte count.","format":"int64","type":"integer"},"state":{"description":"State is pending until its bytes are read back, then stored.","type":"string"},"stored":{"description":"Stored is when its bytes were read back, unix seconds.","format":"int64","type":"integer"},"url":{"description":"URL fetches the bytes for ten minutes, on a read of one stored object.","type":"string"}},"type":"object"},"train.Objective":{"properties":{"loss":{"description":"Loss is `cross_entropy`.","type":"string"},"terms":{"description":"Terms are added to each row's loss.","items":{"$ref":"#/components/schemas/train.Term"},"type":"array"}},"type":"object"},"train.Options":{"properties":{"labels":{"description":"Labels are its option labels, in order: a choice's criteria, a score's levels\nas text, a noul's two sides.","items":{"type":"string"},"type":"array"},"type":{"description":"Type is choice, score or noul.","type":"string"}},"type":"object"},"train.Output":{"properties":{"kind":{"description":"Kind is checkpoint, lora, capability, basis or merged.","type":"string"},"name":{"description":"Name labels it.","type":"string"}},"type":"object"},"train.Projection":{"properties":{"strength":{"description":"Strength is λ in [0, 1]; absent is 1, the whole of P g removed.","format":"double","type":"number"}},"type":"object"},"train.Protect":{"properties":{"budget":{"$ref":"#/components/schemas/train.Budget","description":"Budget bounds the regression per protected suite."},"capabilities":{"description":"Capabilities are capability artifacts, by sha256.","items":{"type":"string"},"type":"array"},"distillation":{"description":"Distillation adds KL to the base's answers on a preservation set drawn from\nthe suites.","type":"boolean"},"projection":{"$ref":"#/components/schemas/train.Projection","description":"Projection projects every update off the protected directions — the suites'\ngradient subspace at the base and each named capability's subspace — by its\nstrength; absent is no projection."},"suites":{"description":"Suites are capabilities the base already has, by suite.","items":{"type":"string"},"type":"array"}},"type":"object"},"train.Question":{"properties":{"key":{"type":"string"},"labels":{"items":{"type":"string"},"type":"array"},"type":{"type":"string"}},"type":"object"},"train.Resources":{"properties":{"budget":{"description":"Budget bounds what the job's compute costs, in US cents; 0 is none beyond\nthe payer's balance. Only a job Hanzo runs costs anything, so only it takes one.","format":"int64","type":"integer"},"devices":{"description":"Devices are the accelerator kinds the job may run on — cuda, rocm, metal,\nvulkan, cpu; none named is any its base runs.","items":{"type":"string"},"type":"array"},"machines":{"description":"Machines are the org's linked machines by name; the first leads. When it\nnames none, Hanzo's executor runs the job and its compute is charged by the\ndevice-second.","items":{"type":"string"},"type":"array"},"max_seconds":{"description":"MaxSeconds bounds the device-seconds the job's tasks use together; 0 is none.","format":"int64","type":"integer"},"steps":{"description":"Steps bounds optimizer steps; 0 runs the plan.","format":"int64","type":"integer"}},"type":"object"},"train.Route":{"properties":{"keys":{"description":"Keys are the question keys it answers.","items":{"type":"string"},"type":"array"},"options":{"additionalProperties":{"$ref":"#/components/schemas/train.Options"},"description":"Options narrows a key to one question: a question under that key routes here\nonly when its type and option labels are exactly these. A key not named here\nroutes whatever its question.","type":"object"}},"type":"object"},"train.Run":{"properties":{"devices":{"description":"Devices are the accelerator kinds it runs on there; none is the executor's own.","items":{"type":"string"},"type":"array"},"price_nano_usd":{"description":"Price is what one device-second costs there, in nano-USD: 0 on the org's\nmachines.","format":"int64","type":"integer"},"where":{"description":"Where is hanzo, Hanzo's devices, charged by the device-second to the payer\ninside the job's budget; or machines, the org's linked machines, charged\nnothing.","type":"string"}},"type":"object"},"train.Spec":{"properties":{"adaptation":{"$ref":"#/components/schemas/train.Adaptation","description":"Adaptation is how the update is parameterized."},"base_model":{"description":"BaseModel is the base the capability is taught to: `kai`, or a model the engine\nloads for a client.","type":"string"},"dataset":{"$ref":"#/components/schemas/train.Dataset","description":"Dataset is what the job trains on."},"evaluation":{"$ref":"#/components/schemas/train.Evaluation","description":"Evaluation names the target suites the result reports."},"from":{"description":"From is an artifact the job starts from, by sha256.","type":"string"},"objective":{"$ref":"#/components/schemas/train.Objective","description":"Objective is the loss and the terms beside it."},"output":{"$ref":"#/components/schemas/train.Output","description":"Output is what the job produces."},"protect":{"$ref":"#/components/schemas/train.Protect","description":"Protect names what the base already does that must hold, and the budget."},"resources":{"$ref":"#/components/schemas/train.Resources","description":"Resources places and bounds the run."},"revision":{"description":"Revision pins the base. For kai: a finished run's name on the executor, or\n`hub:\u003crepo\u003e@\u003crev\u003e`.","type":"string"}},"type":"object"},"train.Supports":{"properties":{"adaptations":{"description":"Adaptations are the modes it runs.","items":{"type":"string"},"type":"array"},"outputs":{"description":"Outputs are the output kinds it produces.","items":{"type":"string"},"type":"array"},"protect":{"description":"Protect are the protections it runs: projection, distillation, capabilities.","items":{"type":"string"},"type":"array"},"terms":{"description":"Terms are the objective terms it runs.","items":{"type":"string"},"type":"array"}},"type":"object"},"train.TaskView":{"properties":{"device":{"description":"Device is the accelerator class it runs on — gpu or cpu — and Devices how many.","type":"string"},"devices":{"format":"int64","type":"integer"},"held":{"format":"int64","type":"integer"},"host":{"description":"Host is the machine that claimed it.","type":"string"},"id":{"description":"ID names the task.","type":"string"},"machine":{"description":"Machine is the machine it was placed on, or empty for any.","type":"string"},"role":{"description":"Role is lead or join.","type":"string"},"seconds":{"description":"Seconds are the device-seconds its reports metered, and Held those held for it.","format":"int64","type":"integer"},"seen":{"description":"Seen is its last report, unix seconds.","format":"int64","type":"integer"},"status":{"description":"Status is open, claimed, done or lost.","type":"string"}},"type":"object"},"train.Term":{"properties":{"kind":{"description":"Kind names the term.","type":"string"},"margin":{"description":"Margin is a hinge's margin, in logits.","format":"double","type":"number"},"weight":{"description":"Weight scales it; 0 is off.","format":"double","type":"number"}},"type":"object"},"train.Usage":{"properties":{"cost_micro_usd":{"description":"CostMicroUSD is what Seconds were charged, in micro-USD: 0 on the org's own machines.","format":"int64","type":"integer"},"held":{"description":"Held are the device-seconds held beyond Seconds; 0 once it ended.","format":"int64","type":"integer"},"seconds":{"description":"Seconds are the device-seconds used.","format":"int64","type":"integer"}},"type":"object"},"train.Version":{"properties":{"at":{"format":"int64","type":"integer"},"base_sha256":{"description":"BaseSHA256 is Kai's weights it was taught over.","type":"string"},"by":{"type":"string"},"bytes":{"description":"Bytes is its artifact's size.","format":"int64","type":"integer"},"corrections":{"description":"Corrections are the corrections it was taught from.","items":{"type":"string"},"type":"array"},"evaluation":{"description":"Evaluation is its evaluation record, in the shared /evals words."},"form":{"description":"Form is calibration, head or pair; Rank its place, 1 the smallest.","type":"string"},"passed":{"description":"Passed says its evaluation passed the gate: it is publishable.","type":"boolean"},"questions":{"description":"Questions are the question keys it answers.","items":{"type":"string"},"type":"array"},"rank":{"format":"int64","type":"integer"},"representation":{"description":"Representation is what it reads of Kai (the weights, tokenizer, layout and\npooling, hashed): the only Kai it serves on, whatever the release.","type":"string"},"sha256":{"description":"SHA256 is its artifact's: the tar the decision service installs.","type":"string"},"version":{"format":"int64","type":"integer"}},"type":"object"},"train.artifact":{"properties":{"created":{"description":"Created is when it was registered, unix seconds.","format":"int64","type":"integer"},"job":{"description":"Job is the job that produced it; empty for an upload.","type":"string"},"kind":{"description":"Kind is checkpoint, lora, capability, basis or merged, or dataset for an upload.","type":"string"},"meta":{"description":"Meta describes it: its base and revision, its modules, a basis's address."},"name":{"description":"Name labels it.","type":"string"},"sha256":{"description":"SHA256 is the hex digest of its bytes, and its name in the object store.","type":"string"},"size":{"description":"Size is its byte count.","format":"int64","type":"integer"},"state":{"description":"State is pending until its bytes are read back, then stored; deleted once\nthe org deleted it or it outlived its retention unpublished.","type":"string"}},"type":"object"},"train.artifactsOut":{"properties":{"data":{"description":"Data is the job's artifacts.","items":{"$ref":"#/components/schemas/train.Download"},"type":"array"}},"type":"object"},"train.capabilitiesOut":{"properties":{"data":{"items":{"$ref":"#/components/schemas/train.Capability"},"type":"array"}},"type":"object"},"train.captureIn":{"properties":{"on":{"type":"boolean"}},"type":"object"},"train.catalog":{"properties":{"data":{"description":"Data is every base the caller can train, each with its methods, where it\nruns and what a device-second costs there.","items":{"$ref":"#/components/schemas/train.Family"},"type":"array"}},"type":"object"},"train.claimIn":{"properties":{"bases":{"description":"Bases are the base models its trainer runs.","items":{"type":"string"},"type":"array"},"devices":{"description":"Devices are its accelerators, one entry per device: cuda, rocm, metal,\nvulkan, cpu. A task runs on those of one kind its job allows.","items":{"type":"string"},"type":"array"},"machine":{"description":"Machine is the machine claiming, by name: one of the org's linked machines,\nor for a platform claim the Hanzo host.","type":"string"},"platform":{"description":"Platform claims for Hanzo's executor: a task of any org's job that names no\nmachines. A SuperAdmin's claim alone, and on the platform's audit trail.","type":"boolean"},"supports":{"$ref":"#/components/schemas/train.Supports","description":"Supports is what its build runs."}},"type":"object"},"train.clientList":{"properties":{"clients":{"description":"Clients are the org's live clients, as the engine reports them.","items":{},"type":"array"}},"type":"object"},"train.correctionsOut":{"properties":{"data":{"items":{"$ref":"#/components/schemas/train.Correction"},"type":"array"},"questions":{"items":{"$ref":"#/components/schemas/train.CorrectionGroup"},"type":"array"}},"type":"object"},"train.createClientIn":{"properties":{"adaptation":{"$ref":"#/components/schemas/train.Adaptation","description":"Adaptation is lora, the one mode clients run; its shape is lora_config."},"base_model":{"description":"BaseModel is a model the engine loads: a Hugging Face repo id or a local path.","type":"string"},"lora_config":{"description":"LoraConfig is the adapter's shape, as the engine's wire takes it."},"protect":{"$ref":"#/components/schemas/train.Protect","description":"Protect is refused: clients protect nothing yet."}},"type":"object"},"train.createIn":{"properties":{"corrections":{"description":"Corrections are the corrections it is taught from: captured corrections of\none question, which becomes its route.","items":{"type":"string"},"type":"array"},"name":{"description":"Name is its name: lowercase words joined by hyphens, at most 64.","type":"string"}},"type":"object"},"train.deletedOut":{"properties":{"deleted":{"description":"Deleted is true.","type":"boolean"},"sha256":{"description":"SHA256 names the object deleted.","type":"string"}},"type":"object"},"train.event":{"properties":{"at":{"description":"At is when it was recorded, unix seconds.","format":"int64","type":"integer"},"event":{"description":"Body is the event as its executor reported it."},"seq":{"description":"Seq orders the job's events from 1.","format":"int64","type":"integer"},"task":{"description":"Task is the task that reported it.","type":"string"}},"type":"object"},"train.eventsOut":{"properties":{"data":{"description":"Data is the events after the cursor, in order.","items":{"$ref":"#/components/schemas/train.event"},"type":"array"},"next":{"description":"Next is the cursor to pass as after.","format":"int64","type":"integer"},"status":{"description":"Status is the job's status as of this answer.","type":"string"}},"type":"object"},"train.forwardIn":{"properties":{"data":{"description":"Data are the examples: {prompt, completion} text, or tokenized datums.","items":{},"type":"array"},"id":{"description":"ID names the client.","type":"string"}},"type":"object"},"train.jobsOut":{"properties":{"data":{"description":"Data is the org's jobs, newest first.","items":{"$ref":"#/components/schemas/train.Job"},"type":"array"}},"type":"object"},"train.metricsOut":{"properties":{"data":{"description":"Data is one series per metric name.","items":{"$ref":"#/components/schemas/train.series"},"type":"array"}},"type":"object"},"train.objectsOut":{"properties":{"data":{"description":"Data is the org's objects, newest first.","items":{"$ref":"#/components/schemas/train.Object"},"type":"array"}},"type":"object"},"train.optimIn":{"properties":{"adam_params":{"description":"AdamParams are the optimizer's parameters for this step."},"id":{"description":"ID names the client.","type":"string"}},"type":"object"},"train.part":{"properties":{"headers":{"additionalProperties":{"type":"string"},"description":"Headers must be sent verbatim; the signature covers them.","type":"object"},"number":{"description":"Number orders the part from 1.","format":"int64","type":"integer"},"offset":{"description":"Offset is the part's first byte in the object.","format":"int64","type":"integer"},"size":{"description":"Size is the part's byte count.","format":"int64","type":"integer"},"url":{"description":"URL is the presigned address to PUT the range to.","type":"string"}},"type":"object"},"train.publishCapIn":{"properties":{"name":{"type":"string"},"version":{"description":"Version is the version to install; the newest that passed when absent.","format":"int64","type":"integer"}},"type":"object"},"train.publishIn":{"properties":{"force":{"description":"Force publishes a rejected job's output, and is recorded.","type":"boolean"},"id":{"description":"ID names the job.","type":"string"},"name":{"description":"Name is the published name; the output's name when absent. Publishing a\nname the org already published replaces that capability.","type":"string"},"route":{"$ref":"#/components/schemas/train.Route","description":"Route is which questions the capability answers: required to publish a\ncapability, refused for any other output."}},"type":"object"},"train.registerIn":{"properties":{"id":{"description":"ID names the job, from the path.","type":"string"},"kind":{"description":"Kind is checkpoint, lora, capability, basis or merged.","type":"string"},"lease":{"description":"Lease is the task's lease.","type":"string"},"meta":{"additionalProperties":{},"description":"Meta describes it: its base and revision, its modules, a basis's address.","type":"object"},"name":{"description":"Name labels it.","type":"string"},"sha256":{"description":"SHA256 is the hex digest of the bytes.","type":"string"},"size":{"description":"Size is the byte count.","format":"int64","type":"integer"},"task":{"description":"Task is the reporting task.","type":"string"}},"type":"object"},"train.registerOut":{"properties":{"sha256":{"description":"SHA256 names the artifact.","type":"string"},"stored":{"description":"Stored says the org already holds these bytes: nothing to upload.","type":"boolean"},"upload":{"$ref":"#/components/schemas/train.upload","description":"Upload is the grant to PUT the bytes, when they are not stored."}},"type":"object"},"train.reportIn":{"properties":{"events":{"description":"Events are the task's new events, in order.","items":{},"type":"array"},"id":{"description":"ID names the job, from the path.","type":"string"},"lease":{"description":"Lease is the task's lease, as the claim answered it.","type":"string"},"task":{"description":"Task is the reporting task.","type":"string"}},"type":"object"},"train.reportOut":{"properties":{"cancel":{"description":"Cancel says the job was cancelled, or stopped at what its payer or its own\nbounds could hold: kill the trainer, report nothing more.","type":"boolean"},"held":{"description":"Held is the device-seconds held for the task now.","format":"int64","type":"integer"},"seq":{"description":"Seq is the job's last event seq.","format":"int64","type":"integer"},"status":{"description":"Status is the job's status after this report.","type":"string"}},"type":"object"},"train.sampleIn":{"properties":{"id":{"description":"ID names the client.","type":"string"},"num_samples":{"description":"NumSamples is how many sequences to decode.","format":"int64","type":"integer"},"prompt":{"description":"Prompt is a text prompt; exactly one of prompt and tokens.","type":"string"},"sampling_params":{"description":"SamplingParams are the decoding parameters."},"tokens":{"description":"Tokens is a tokenized prompt.","items":{"format":"uint32","type":"integer"},"type":"array"}},"type":"object"},"train.saveIn":{"properties":{"id":{"description":"ID names the client.","type":"string"},"name":{"description":"Name is the adapter's name.","type":"string"},"output":{"$ref":"#/components/schemas/train.Output","description":"Output is lora, the one kind a client writes."}},"type":"object"},"train.series":{"properties":{"name":{"description":"Name is the metric.","type":"string"},"points":{"description":"Points are [step, value, at] in step order.","items":{"items":{"format":"double","type":"number"},"type":"array"},"type":"array"}},"type":"object"},"train.trainIn":{"properties":{"corrections":{"description":"Corrections, when given, replace the corrections it is taught from: captured\ncorrections of its question.","items":{"type":"string"},"type":"array"},"name":{"type":"string"}},"type":"object"},"train.unmadeOut":{"properties":{"deleted":{"type":"boolean"},"name":{"type":"string"}},"type":"object"},"train.upload":{"properties":{"expires":{"description":"Expires is when the grant stops being accepted, unix seconds.","format":"int64","type":"integer"},"headers":{"additionalProperties":{"type":"string"},"description":"Headers must be sent verbatim with the single PUT; the signature covers them.","type":"object"},"method":{"description":"Method is PUT.","type":"string"},"parts":{"description":"Parts are the object's consecutive byte ranges, each PUT to its own address.","items":{"$ref":"#/components/schemas/train.part"},"type":"array"},"url":{"description":"URL is the presigned address of a single PUT; empty when Parts is given.","type":"string"}},"type":"object"},"train.uploadIn":{"properties":{"kind":{"description":"Kind is dataset: JSON Lines rows a job reads as `artifact:\u003csha256\u003e`.","type":"string"},"name":{"description":"Name labels it.","type":"string"},"sha256":{"description":"SHA256 is the hex digest of the bytes.","type":"string"},"size":{"description":"Size is the byte count.","format":"int64","type":"integer"}},"type":"object"},"translate.MemoryEntry":{"properties":{"actor":{"description":"Actor is the validated user id that last wrote this entry by hand. Empty on an\nentry an engine produced, and on one written before attribution existed.","type":"string"},"format":{"description":"Format is the markup the source carried: text, html or markdown. Part of the\nidentity.","type":"string"},"glossary_version":{"description":"Glossary is the glossary VERSION the entry was translated under — the digest\nversion() derives from the terms, so changing a term changes the key and the\nstale rendering can never be served.","type":"string"},"lang":{"description":"Lang is the source language the translate call declared, empty when the\nengine detected it. Part of the identity; an entry with none also serves a\ncall that declares one.","type":"string"},"model":{"description":"Model is the quality-tier model the translate call named, empty for the\ndefault. Part of the identity: one model's rendering never answers for\nanother's.","type":"string"},"request_id":{"description":"RequestID is the X-Request-Id of the translate call whose engine produced\nthe entry. Empty on an entry a human wrote, and on one older than the field.","type":"string"},"source":{"description":"Source is the ORIGINAL string this entry translates. Part of the identity.","type":"string"},"state":{"description":"State is the entry's position on the review ladder: machine, suggested,\napproved or published.","type":"string"},"target":{"description":"Target is the target language tag (BCP-47, e.g. \"es\" or \"pt-BR\"). Part of the\nidentity.","type":"string"},"text":{"description":"Text is the stored translation. A memory hit returns it verbatim, which is the\nidempotence contract.","type":"string"},"tier":{"description":"Tier is the engine tier the entry belongs to, quality or bulk. Part of the\nidentity: the two tiers keep separate renderings of the same source.","type":"string"},"updated_at":{"description":"UpdatedAt is the unix second the entry last changed.","format":"int64","type":"integer"}},"type":"object"},"translate.MemoryPage":{"properties":{"data":{"description":"Data is the matching memory entries, newest first.","items":{"$ref":"#/components/schemas/translate.MemoryEntry"},"type":"array"}},"type":"object"},"translate.ReviewRequest":{"properties":{"format":{"description":"Format is the markup the source carries: text (the default), html or markdown.\nPart of the entry's identity.","type":"string"},"glossary":{"additionalProperties":{"type":"string"},"description":"Glossary is the terminology the entry was translated under. Its VERSION — the\ndigest of the sorted terms — is part of the entry's identity, so editing a term\nyields a new entry rather than overwriting the old rendering.","type":"object"},"lang":{"description":"Lang is the source language the translate calls this entry serves declare\n(their `source`), empty for calls that let the engine detect it. Part of the\nentry's identity; an entry with none also serves calls that declare one.","type":"string"},"model":{"description":"Model is the quality-tier model the translate calls this entry serves name;\nempty for the default. Part of the entry's identity, and refused with bulk.","type":"string"},"source":{"description":"Source is the ORIGINAL string this entry translates. Required; part of the\nentry's identity, so a different source is a different entry.","type":"string"},"state":{"description":"State is the entry's new position on the review ladder: suggested, approved or\npublished. `machine` is engine-only and is refused here — a human may not demote\na string back into the churn.","type":"string"},"target":{"description":"Target is the target language tag (BCP-47, e.g. \"es\" or \"pt-BR\"). Required;\npart of the entry's identity.","type":"string"},"text":{"description":"Text is the reviewed translation to store. A human write always wins over the\nstored value.","type":"string"},"tier":{"description":"Tier is the engine tier the entry belongs to, quality (the default) or bulk.\nPart of the entry's identity: the two tiers keep separate renderings.","type":"string"}},"type":"object"},"treasury.SharePolicy":{"properties":{"revenueShareBps":{"format":"int64","type":"integer"},"updatedAt":{"format":"int64","type":"integer"}},"type":"object"},"treasury.TreasuryReport":{"properties":{"accruedCents":{"description":"lifetime revenue-share into the fund","format":"int64","type":"integer"},"byProgramCents":{"additionalProperties":{"format":"int64","type":"integer"},"description":"program → lifetime paid","type":"object"},"paidCents":{"description":"lifetime backed payouts out of the fund","format":"int64","type":"integer"},"policy":{"$ref":"#/components/schemas/treasury.SharePolicy","description":"current revenue-share policy"},"reserveCents":{"description":"fund:reserve balance (available now)","format":"int64","type":"integer"},"solventForPayout":{"description":"reserve \u003e 0: at least some payout is backable","type":"boolean"}},"type":"object"},"treasury.accountView":{"properties":{"address":{"description":"Address is the ledger account address (\"org:acme:wallet\", \"fund:reserve\", …).","type":"string"},"balanceCents":{"description":"BalanceCents is that account's signed balance in minor units.","format":"int64","type":"integer"}},"type":"object"},"treasury.accountsOut":{"properties":{"accounts":{"description":"Accounts are the ledger accounts in scope with their balances.","items":{"$ref":"#/components/schemas/treasury.accountView"},"type":"array"},"scope":{"description":"Scope is the scope actually served: \"org\" or \"house\".","type":"string"},"tenant":{"description":"Tenant is the org whose accounts these are (empty for the house scope's own rows).","type":"string"}},"type":"object"},"trust.centre":{"properties":{"controls":{"description":"Controls is the control inventory, each entry naming what it asserts, the\nmechanism, where it is enforced, how it is verified and the clauses it maps\nto.","items":{},"type":"array"},"coverage":{"description":"Coverage is the per-framework counts, computed from Controls against each\nframework's whole published clause list.","items":{"$ref":"#/components/schemas/trust.coverRow"},"type":"array"},"documents":{"description":"Documents are the artifacts, each saying whether this reader may read it.","items":{"$ref":"#/components/schemas/trust.docRow"},"type":"array"},"faq":{"description":"Faq is the knowledge base — the questions a reviewer asks, answered.","items":{},"type":"array"},"frameworks":{"description":"Frameworks are the clause universes the coverage is computed against.","items":{"$ref":"#/components/schemas/trust.frameworkRow"},"type":"array"},"generated":{"description":"Generated is when this answer was computed, unix milliseconds.","format":"int64","type":"integer"},"inventory":{"$ref":"#/components/schemas/trust.trustTally","description":"Inventory is how the controls themselves stand, independent of framework."},"org":{"description":"Org is whose centre this is.","type":"string"},"policies":{"description":"Policies are the published policies.","items":{},"type":"array"},"profile":{"description":"Profile is the organization's own description of itself."},"risk":{"description":"Risk is the risk profile — label and value pairs describing what this\norganization handles and how."},"subprocessors":{"description":"Subprocessors are the third parties this organization sends data to.","items":{},"type":"array"},"updates":{"description":"Updates is the changelog, newest as the organization ordered it.","items":{},"type":"array"},"version":{"description":"Version is the embedded inventory's version.","type":"string"}},"type":"object"},"trust.clauseCoverage":{"properties":{"automated":{"description":"Automated is how many clauses have an automated control behind them that\nsomething can fail on behalf of.","format":"int64","type":"integer"},"clauses":{"description":"Clauses is every clause the standard publishes, with what stands behind it.","items":{"$ref":"#/components/schemas/trust.clauseRow"},"type":"array"},"edition":{"description":"Edition is which edition this clause list is taken from.","type":"string"},"framework":{"description":"Framework is the framework id — \"soc2\", \"iso27001\", \"nist80053\".","type":"string"},"generated":{"description":"Generated is when this was computed, unix milliseconds.","format":"int64","type":"integer"},"name":{"description":"Name is the published standard's name.","type":"string"},"none":{"description":"None is how many have nothing behind them.","format":"int64","type":"integer"},"note":{"description":"Note is what this clause list is scoped to, when a count alone would\nmisrepresent it.","type":"string"},"partial":{"description":"Partial is how many are answered in part.","format":"int64","type":"integer"},"publisher":{"description":"Publisher is who publishes it — AICPA, ISO/IEC, NIST.","type":"string"},"statement":{"description":"Statement is the counts as one sentence, carrying the unit.","type":"string"},"total":{"description":"Total is the framework's WHOLE published clause list — the denominator.","format":"int64","type":"integer"},"unit":{"description":"Unit is what ONE clause is — \"criterion\", \"control\", \"family\".","type":"string"},"units":{"description":"Units is the plural of Unit, for rendering a sentence.","type":"string"},"version":{"description":"Version is the embedded inventory's version.","type":"string"}},"type":"object"},"trust.clauseRow":{"properties":{"controls":{"description":"Controls are the ids behind it, strongest first. Empty when nothing covers\nit — and an absent control is never listed here, however it maps.","items":{"type":"string"},"type":"array"},"group":{"description":"Group is the clause's section within the standard, when it has one.","type":"string"},"id":{"description":"ID is the clause id as the standard publishes it — \"CC6.1\", \"A.5.15\", \"AC\".","type":"string"},"level":{"description":"Level is what the strongest control pointed at this clause is worth:\n\"automated\", \"partial\" or \"none\".","type":"string"},"title":{"description":"Title is the standard's own words for that clause.","type":"string"}},"type":"object"},"trust.controlList":{"properties":{"absent":{"description":"Absent is how many the organization does not have. Each still names the\nclause it would satisfy, and none of them moves a coverage number.","format":"int64","type":"integer"},"automated":{"description":"Automated is how many run with nobody in the loop.","format":"int64","type":"integer"},"controls":{"description":"Controls is every control, opaque because the organization owns its shape.","items":{},"type":"array"},"partial":{"description":"Partial is how many run but do not cover their whole claim.","format":"int64","type":"integer"},"statement":{"description":"Statement is the counts as one sentence, safe to quote.","type":"string"},"total":{"description":"Total is how many controls this organization publishes.","format":"int64","type":"integer"},"unverified":{"description":"Unverified is how many rest on somebody having read the source rather than\non a test or an audit row.","format":"int64","type":"integer"},"version":{"description":"Version is the embedded inventory's version.","type":"string"}},"type":"object"},"trust.coverRow":{"properties":{"automated":{"description":"Automated is how many clauses have an automated control behind them that\nsomething can fail on behalf of.","format":"int64","type":"integer"},"edition":{"description":"Edition is which edition the clause list is taken from.","type":"string"},"framework":{"description":"Framework is the framework id — \"soc2\", \"iso27001\", \"nist80053\".","type":"string"},"name":{"description":"Name is the published standard's name.","type":"string"},"none":{"description":"None is how many have nothing behind them. It stays visible rather than\ndropping out of the fraction.","format":"int64","type":"integer"},"note":{"description":"Note is what the clause list itself is scoped to, when the framework's\ncatalog says something a count alone would misrepresent.","type":"string"},"partial":{"description":"Partial is how many are answered in part.","format":"int64","type":"integer"},"publisher":{"description":"Publisher is who publishes it — AICPA, ISO/IEC, NIST.","type":"string"},"statement":{"description":"Statement is the counts as one sentence, carrying the unit.","type":"string"},"total":{"description":"Total is the framework's WHOLE published clause list — the denominator.\nCounting only the clauses some control happened to name would report 100%\nevery time.","format":"int64","type":"integer"},"unit":{"description":"Unit is what ONE clause is — \"criterion\", \"control\", \"family\". A count\nwithout its unit is not a fact, so it travels with every number here.","type":"string"},"units":{"description":"Units is the plural of Unit, for rendering a sentence.","type":"string"}},"type":"object"},"trust.docRow":{"properties":{"attested":{"description":"Attested reports whether somebody OUTSIDE this organization put their name\nto it. Those are the artifacts a reviewer asks for, and they are released\nthrough a grant rather than published — there is no field that can say\notherwise.","type":"boolean"},"href":{"description":"Href is where to read it, present only when this reader may.","type":"string"},"id":{"description":"ID is the document's id within this organization's centre.","type":"string"},"kind":{"description":"Kind is the artifact type — soc2, iso, pentest, letter, caiq, sig, vsa,\nquestionnaire, policy or other.","type":"string"},"label":{"description":"Label is the artifact type in words, for rendering.","type":"string"},"note":{"description":"Note is anything the organization says about this artifact.","type":"string"},"released":{"description":"Released reports whether THIS reader may read it. False means the artifact\nexists and is available on request.","type":"boolean"},"tier":{"description":"Tier is \"public\" or \"gated\". It defaults to gated, so a new artifact is\nclosed until somebody opens it deliberately.","type":"string"},"title":{"description":"Title is what the document is called.","type":"string"},"updated":{"description":"Updated is when the record last changed, unix milliseconds.","format":"int64","type":"integer"}},"type":"object"},"trust.dropped":{"properties":{"deleted":{"description":"Deleted is always true; a record that was not there is a 404 instead.","type":"boolean"},"id":{"description":"ID is the record removed.","type":"string"},"kind":{"description":"Kind is the section.","type":"string"}},"type":"object"},"trust.faqList":{"properties":{"faq":{"description":"Faq is the questions and their answers.","items":{},"type":"array"}},"type":"object"},"trust.frameworkList":{"properties":{"frameworks":{"description":"Frameworks is each framework and how many clauses it publishes.","items":{"$ref":"#/components/schemas/trust.frameworkRow"},"type":"array"}},"type":"object"},"trust.frameworkRow":{"properties":{"edition":{"description":"Edition is which edition this clause list is taken from.","type":"string"},"framework":{"description":"Framework is the framework id.","type":"string"},"name":{"description":"Name is the published standard's name.","type":"string"},"publisher":{"description":"Publisher is who publishes it.","type":"string"},"total":{"description":"Total is how many clauses the standard publishes.","format":"int64","type":"integer"},"unit":{"description":"Unit is what one clause is; Units is its plural.","type":"string"},"units":{"description":"Units is Unit's plural, carried so a caller renders \"12 controls\" without\nhaving to pluralise a word it does not know.","type":"string"}},"type":"object"},"trust.policyList":{"properties":{"policies":{"description":"Policies is the organization's published policy documents, each as the\ncentre holds it.","items":{},"type":"array"}},"type":"object"},"trust.sectionWrite":{"properties":{"data":{"description":"Data is the record. What may be in it depends on the section, and every\nsection's required fields are validated: a control is held to the same rule\na committed one is, a subprocessor must say what it is for, an update must\ncarry the date it describes."},"id":{"description":"ID is the record's id. Omit it on a create and one is minted; the\nsingle-valued sections (profile, risk) hold one record whatever is named.","type":"string"},"kind":{"description":"Kind is the section being written. The URL is the authority.","type":"string"},"ord":{"description":"Ord orders this record within its section, ascending, ties broken by id.\nIt is the organization's own ordering — the page renders in it.","format":"int64","type":"integer"}},"type":"object"},"trust.subprocessorList":{"properties":{"subprocessors":{"description":"Subprocessors is the list, each naming at least what it is and what it is\nfor — a name alone says nothing.","items":{},"type":"array"}},"type":"object"},"trust.trustCoverage":{"properties":{"controls":{"$ref":"#/components/schemas/trust.trustTally","description":"Controls is how the controls stand, independent of any framework."},"frameworks":{"description":"Frameworks is the per-framework counts.","items":{"$ref":"#/components/schemas/trust.coverRow"},"type":"array"},"generated":{"description":"Generated is when this was computed, unix milliseconds.","format":"int64","type":"integer"},"version":{"description":"Version is the embedded inventory's version.","type":"string"}},"type":"object"},"trust.trustDocuments":{"properties":{"documents":{"description":"Documents is the list; a gated entry carries no address.","items":{"$ref":"#/components/schemas/trust.docRow"},"type":"array"}},"type":"object"},"trust.trustTally":{"properties":{"absent":{"description":"Absent is how many the organization does not have. An absent control still\nnames the clause it would satisfy — that is a roadmap — but it never moves\na coverage number.","format":"int64","type":"integer"},"automated":{"description":"Automated is how many run with nobody in the loop.","format":"int64","type":"integer"},"partial":{"description":"Partial is how many run but do not cover their whole claim. Each says what\nis missing.","format":"int64","type":"integer"},"statement":{"description":"Statement is the counts as one sentence, safe to quote.","type":"string"},"total":{"description":"Total is how many controls this organization publishes.","format":"int64","type":"integer"},"unverified":{"description":"Unverified is how many rest on somebody having READ the source rather than\non a test or an audit row. Only a check that can FAIL counts as verified,\nand coverage counts those one rung weaker than they claim to be.","format":"int64","type":"integer"}},"type":"object"},"trust.updateList":{"properties":{"updates":{"description":"Updates is the entries, each carrying the date it describes.","items":{},"type":"array"}},"type":"object"},"trust.written":{"properties":{"id":{"description":"ID is the record's id — the one supplied, or the one minted when the\ncaller supplied none.","type":"string"},"kind":{"description":"Kind is the section written.","type":"string"},"updated":{"description":"Updated is when it was written, unix milliseconds.","format":"int64","type":"integer"}},"type":"object"},"usage.Accounts":{"properties":{"account":{"$ref":"#/components/schemas/usage.SourceState","description":"Account is the state of the caller's own linked-account side."},"hanzo":{"$ref":"#/components/schemas/usage.SourceState","description":"Hanzo is the state of the org's Hanzo-routed side."},"rows":{"description":"Rows is the two row sets CONCATENATED, never summed — each row says which\nside it came from. A percent is not money and a provider's own spend is not\na Hanzo charge, so adding them would produce a number that means nothing.","items":{"$ref":"#/components/schemas/usage.TotalView"},"type":"array"}},"type":"object"},"usage.CategorySpend":{"properties":{"category":{"description":"Category is what the lines metered, as it reads on a bill: \"Desktop sandbox\",\n\"Agent sessions\", or an AI model's own id. It is the same name\n/v1/billing/usage gives each row. A line that recorded nothing is\n\"Uncategorized\".","type":"string"},"cents":{"description":"Cents is what the org spent in that bucket over the window, in US cents.","format":"int64","type":"integer"},"count":{"description":"Count is how many ledger lines rolled up into it.","format":"int64","type":"integer"}},"type":"object"},"usage.Kai":{"properties":{"available":{"description":"Available is false when the warehouse was not connected or a query blipped.\nThe totals below are then honest zeros, NOT measured ones.","type":"boolean"},"costCents":{"description":"CostCents is what they cost the org, in US cents.","format":"int64","type":"integer"},"decisions":{"description":"Decisions is how many decisions Kai answered in the window.","format":"int64","type":"integer"},"inputTokens":{"description":"InputTokens is the input tokens those decisions were billed on.","format":"int64","type":"integer"}},"type":"object"},"usage.LLM":{"properties":{"available":{"description":"Available is false when the warehouse was not connected or a query blipped.\nThe totals below are then honest zeros, NOT measured ones.","type":"boolean"},"cacheReadTokens":{"description":"CacheReadTokens is how many of the prompt tokens the provider's prompt cache\nserved, at the cache-read price.","format":"int64","type":"integer"},"cacheSavedCents":{"description":"CacheSavedCents is what the prompt cache took off the bill, in US cents: each\ncall's cache-read tokens at the model's input price less the same tokens at its\ncache-read price, from the price that call was billed at. A call recorded\nbefore this was measured counts 0, so it is a floor.","format":"int64","type":"integer"},"cacheWriteTokens":{"description":"CacheWriteTokens is how many prompt tokens were written to the prompt cache.","format":"int64","type":"integer"},"cachedShare":{"description":"CachedShare is CacheReadTokens over PromptTokens, 0 to 1 at four decimals; 0\nwhen nothing was prompted.","format":"double","type":"number"},"completionTokens":{"description":"CompletionTokens is the output half.","format":"int64","type":"integer"},"costCents":{"description":"CostCents is what they cost the org, in US cents. This IS a Hanzo charge.","format":"int64","type":"integer"},"models":{"description":"Models is how many distinct models were used.","format":"int64","type":"integer"},"promptTokens":{"description":"PromptTokens is the input half of that total.","format":"int64","type":"integer"},"requests":{"description":"Requests is how many completions the org made in the window.","format":"int64","type":"integer"},"source":{"description":"Source names the warehouse table the totals came from.","type":"string"},"tokens":{"description":"Tokens is the total tokens those completions consumed.","format":"int64","type":"integer"}},"type":"object"},"usage.ProviderBreakdown":{"properties":{"available":{"description":"Available is false when the warehouse could not be read, which means \"no\nanswer\" and NOT \"no usage\" — Items is then empty for a reason.","type":"boolean"},"items":{"description":"Items is one row per provider, most tokens first.","items":{"$ref":"#/components/schemas/usage.ProviderRow"},"type":"array"},"source":{"description":"Source names the warehouse table the rows came from.","type":"string"}},"type":"object"},"usage.ProviderRow":{"properties":{"costCents":{"description":"CostCents is what they cost the org, in US cents.","format":"int64","type":"integer"},"provider":{"description":"Provider is the upstream the requests were routed to, e.g. anthropic.","type":"string"},"requests":{"description":"Requests is how many completions the org made against that provider.","format":"int64","type":"integer"},"tokens":{"description":"Tokens is the total tokens those completions consumed, prompt plus\ncompletion.","format":"int64","type":"integer"}},"type":"object"},"usage.SourceState":{"properties":{"available":{"description":"Available is whether this side's ledger answered. False means its rows are\nmissing, not that there were none.","type":"boolean"},"note":{"description":"Note is the human sentence that says what this side's numbers mean, so a\nboard cannot present a plan percentage as a Hanzo charge.","type":"string"},"scope":{"description":"Scope is whose rows this side carries: \"user\" or \"org\".","type":"string"},"source":{"description":"Source is the table of record the rows came from.","type":"string"}},"type":"object"},"usage.Sources":{"properties":{"commerce":{"description":"Commerce is whether the billing ledger answered the spend block.","type":"boolean"},"warehouse":{"description":"Warehouse is whether the usage warehouse answered the LLM block.","type":"boolean"}},"type":"object"},"usage.Spend":{"properties":{"available":{"description":"Available is false when the commerce ledger was unconfigured or\nunreachable. Every number below is then an honest zero, NOT a measured one.","type":"boolean"},"availableCents":{"description":"AvailableCents is what of that balance is still spendable.","format":"int64","type":"integer"},"balanceCents":{"description":"BalanceCents is the prepaid wallet's balance, in US cents.","format":"int64","type":"integer"},"byCategory":{"description":"ByCategory is the window's spend split by ledger category, largest first.","items":{"$ref":"#/components/schemas/usage.CategorySpend"},"type":"array"},"mtdCents":{"description":"MTDCents is commerce's authoritative month-to-date consumed figure, which\nis a different period from the window and is not derived from it.","format":"int64","type":"integer"},"overageCents":{"description":"OverageCents is month-to-date consumption beyond the plan's allowance.","format":"int64","type":"integer"},"series":{"description":"Series is the window's spend over time, gap-filled at the window's\ninterval.","items":{"$ref":"#/components/schemas/usage.SpendPoint"},"type":"array"},"source":{"description":"Source names where the roll-up came from.","type":"string"},"totalCents":{"description":"TotalCents is consumption over the requested window, in US cents. It is\nself-consistent with ByCategory and Series.","format":"int64","type":"integer"}},"type":"object"},"usage.SpendPoint":{"properties":{"cents":{"description":"Cents is the consumption recorded in that bucket, in US cents.","format":"int64","type":"integer"},"t":{"description":"T is the bucket's start instant, RFC3339 UTC. Buckets are gap-filled, so a\nwindow with no spend still has its points.","type":"string"}},"type":"object"},"usage.TotalView":{"properties":{"confidence":{"description":"Confidence says how much the counters mean; a percentage-only meter leaves\nthem at zero.","type":"string"},"costCents":{"description":"CostCents is the row's cost in US cents. For an \"account\" row this is the\nPROVIDER's own charge, not a Hanzo one.","format":"int64","type":"integer"},"provider":{"description":"Provider is the upstream the usage was measured against.","type":"string"},"requests":{"description":"Requests is how many requests the row covers.","format":"int64","type":"integer"},"scope":{"description":"Scope is whose row it is: \"user\" for the caller's own linked accounts,\n\"org\" for the whole tenant's Hanzo-routed usage.","type":"string"},"source":{"description":"Source is where the row came from: \"account\" is the provider's own meter\non the caller's linked account, \"hanzo\" is Hanzo-routed inference. The two\nare never summed.","type":"string"},"tokens":{"description":"Tokens is the total tokens the row covers.","format":"int64","type":"integer"},"usedPct":{"description":"UsedPct is how much of a plan window the row consumed, 0–100. It is a\nshare, never money.","format":"double","type":"number"},"window":{"description":"Window is the meter window class the row rolls up, when it has one.","type":"string"},"windows":{"description":"Windows is how many window instances rolled up into the row.","format":"int64","type":"integer"}},"type":"object"},"usage.dashResp":{"properties":{"account":{"description":"Account is the linked account that was asked about, when one was named.","type":"string"},"available":{"description":"Available is false when the warehouse could not be read. That means \"no\nanswer\", NOT \"no usage\" — the two lists below are then empty for a reason.","type":"boolean"},"current":{"description":"Current is the newest window instance of each lane — the dash headline.","items":{"$ref":"#/components/schemas/usage.usageWindowView"},"type":"array"},"from":{"description":"From is the inclusive start of that window, RFC3339 UTC.","type":"string"},"provider":{"description":"Provider is the upstream that was asked about, echoed back.","type":"string"},"range":{"description":"Range is the window that was served: 1h, 24h, 7d or 30d.","type":"string"},"scope":{"description":"Scope says whose rows these are: the caller's own linked accounts.","type":"string"},"source":{"description":"Source names the meter of record — the provider's own login, not Hanzo.","type":"string"},"to":{"description":"To is the exclusive end of that window, RFC3339 UTC.","type":"string"},"windows":{"description":"Windows is every instance in range, newest first — the history behind it.","items":{"$ref":"#/components/schemas/usage.usageWindowView"},"type":"array"}},"type":"object"},"usage.reportReq":{"properties":{"account":{"description":"Account is the linked account the window was metered from.","type":"string"},"cachedInputTokens":{"description":"CachedInputTokens is the prompt tokens the provider served from cache.","format":"int64","type":"integer"},"confidence":{"description":"Confidence says how much the counters below mean.","type":"string"},"costCents":{"description":"CostCents is what the window cost on the PROVIDER's own plan, in US cents.","format":"int64","type":"integer"},"costLimitCents":{"description":"CostLimitCents is the plan's spend ceiling for the window, in US cents.","format":"int64","type":"integer"},"currency":{"description":"Currency is the provider's currency when it is not US cents.","type":"string"},"inputTokens":{"description":"InputTokens is prompt tokens consumed in the window.","format":"int64","type":"integer"},"kind":{"description":"Kind is subscription or apikey. Empty is accepted; anything else is\nrefused.","type":"string"},"lane":{"description":"Lane is the meter lane within the account.","type":"string"},"machine":{"description":"Machine is the host whose meter read the window. Required on every sample.","type":"string"},"outputTokens":{"description":"OutputTokens is completion tokens produced in the window.","format":"int64","type":"integer"},"plan":{"description":"Plan is the subscription plan the account is on, as the provider names it.","type":"string"},"provider":{"description":"Provider is the upstream the account belongs to, e.g. anthropic. Required\non every sample.","type":"string"},"requests":{"description":"Requests is how many requests the window covers.","format":"int64","type":"integer"},"resetsAt":{"description":"ResetsAt is when the measured window rolls over, RFC3339.","type":"string"},"samples":{"description":"Samples is the batch form: every lane a poller measured, in one call. When\nit is non-empty the top-level sample fields are ignored.","items":{"$ref":"#/components/schemas/usage.sampleReq"},"type":"array"},"synthetic":{"description":"Synthetic marks a window the meter inferred rather than read.","type":"boolean"},"totalTokens":{"description":"TotalTokens is the window's total tokens.","format":"int64","type":"integer"},"usedPct":{"description":"UsedPct is how much of the window's allowance is consumed, 0–100.","format":"double","type":"number"},"window":{"description":"Window is the window class: 6h, day, week or month. Required, and a class\nthis surface does not know is refused rather than rewritten.","type":"string"},"windowMinutes":{"description":"WindowMinutes is the window's real length in minutes, as the meter reports\nit.","format":"int32","type":"integer"},"windowStart":{"description":"WindowStart is when the measured window opened, RFC3339. This is how a\nbackfill states WHICH window it measured; the server always owns the\nobservation clock, so there is no timestamp field.","type":"string"}},"type":"object"},"usage.reportResp":{"properties":{"accepted":{"description":"Accepted is how many samples passed validation. Every one of them was\naccepted, or the whole report was refused — there is no partial success.","format":"int64","type":"integer"},"stored":{"description":"Stored is whether the warehouse actually persisted them. False means the\ndatastore was unavailable and the poll of history was lost; the request\nstill succeeded, so a device retries without being blocked.","type":"boolean"}},"type":"object"},"usage.sampleReq":{"properties":{"account":{"description":"Account is the linked account the window was metered from.","type":"string"},"cachedInputTokens":{"description":"CachedInputTokens is the prompt tokens the provider served from cache.","format":"int64","type":"integer"},"confidence":{"description":"Confidence says how much the counters below mean.","type":"string"},"costCents":{"description":"CostCents is what the window cost on the PROVIDER's own plan, in US cents.","format":"int64","type":"integer"},"costLimitCents":{"description":"CostLimitCents is the plan's spend ceiling for the window, in US cents.","format":"int64","type":"integer"},"currency":{"description":"Currency is the provider's currency when it is not US cents.","type":"string"},"inputTokens":{"description":"InputTokens is prompt tokens consumed in the window.","format":"int64","type":"integer"},"kind":{"description":"Kind is subscription or apikey. Empty is accepted; anything else is\nrefused.","type":"string"},"lane":{"description":"Lane is the meter lane within the account.","type":"string"},"machine":{"description":"Machine is the host whose meter read the window. Required.","type":"string"},"outputTokens":{"description":"OutputTokens is completion tokens produced in the window.","format":"int64","type":"integer"},"plan":{"description":"Plan is the subscription plan the account is on, as the provider names it.","type":"string"},"provider":{"description":"Provider is the upstream the account belongs to, e.g. anthropic. Required.","type":"string"},"requests":{"description":"Requests is how many requests the window covers.","format":"int64","type":"integer"},"resetsAt":{"description":"ResetsAt is when the measured window rolls over, RFC3339. Empty is\nallowed; anything else that is not RFC3339 is refused.","type":"string"},"synthetic":{"description":"Synthetic marks a window the meter inferred rather than read.","type":"boolean"},"totalTokens":{"description":"TotalTokens is the window's total tokens.","format":"int64","type":"integer"},"usedPct":{"description":"UsedPct is how much of the window's allowance is consumed, 0–100.","format":"double","type":"number"},"window":{"description":"Window is the window class: 6h, day, week or month. Required, and a class\nthis surface does not know is refused rather than rewritten.","type":"string"},"windowMinutes":{"description":"WindowMinutes is the window's real length in minutes, as the meter reports\nit.","format":"int32","type":"integer"},"windowStart":{"description":"WindowStart is when the measured window opened, RFC3339. Empty is allowed;\nanything else that is not RFC3339 is refused.","type":"string"}},"type":"object"},"usage.usageAnalyticsAccess":{"properties":{"access":{"$ref":"#/components/schemas/usage.usageAnalyticsGrant","description":"Access is what that plan grants."},"plan":{"description":"Plan echoes the plan id that was resolved, exactly as it was asked for.","type":"string"}},"type":"object"},"usage.usageAnalyticsGrant":{"properties":{"datastore":{"description":"Datastore is whether the plan may read GET /v1/usage/analytics at all. The\nfree floor is false, and that is what a catalog outage resolves to.","type":"boolean"},"export":{"description":"Export is whether the plan may export the analytics it can read.","type":"boolean"},"retentionDays":{"description":"RetentionDays is how far back the plan may read. GET /v1/usage/analytics\nclamps a custom window's start to this, so an older `start` returns the\nclamped window rather than an error.","format":"int64","type":"integer"}},"type":"object"},"usage.usageAnalyticsView":{"properties":{"end":{"description":"End is the window's exclusive end, RFC3339 UTC.","type":"string"},"export":{"description":"Export is whether the resolved plan allows exporting these rows.","type":"boolean"},"plan":{"description":"Plan echoes the plan id the entitlement was resolved from.","type":"string"},"providers":{"$ref":"#/components/schemas/usage.ProviderBreakdown","description":"Providers is the per-provider roll-up over the window."},"range":{"description":"Range is the label that was ASKED for. A plan whose retention is shorter\nthan that window is served the retention instead, so read start and end for\nthe window the rows actually cover and retentionDays for the reason — on a\nclamped read the label is longer than what was served.","type":"string"},"retentionDays":{"description":"RetentionDays is how far back the resolved plan allows reading.","format":"int64","type":"integer"},"scope":{"$ref":"#/components/schemas/usage.usageScope","description":"Scope is the tenant the rows were read under — the validated principal's org."},"start":{"description":"Start is the window's inclusive start, RFC3339 UTC, AFTER the retention\nclamp — so it may be later than the start that was asked for.","type":"string"}},"type":"object"},"usage.usageScope":{"properties":{"org":{"description":"Org is the IAM org slug the rows were read under — the validated\nprincipal's, never a client header.","type":"string"},"user":{"description":"User is the caller's own subject, whose linked-account rows the accounts\nblock carries. Absent on a read that is org-scoped only.","type":"string"}},"type":"object"},"usage.usageSummary":{"properties":{"accounts":{"$ref":"#/components/schemas/usage.Accounts","description":"Accounts is the caller's own linked provider accounts beside the org's\nHanzo-routed usage, labelled row by row and never summed together."},"end":{"description":"End is the window's exclusive end, RFC3339 UTC.","type":"string"},"interval":{"description":"Interval is the bucket width the spend series is gap-filled at.","type":"string"},"kai":{"$ref":"#/components/schemas/usage.Kai","description":"Kai is the org's Kai decisions: count, input tokens and cost. Also counted in\nLLM."},"llm":{"$ref":"#/components/schemas/usage.LLM","description":"LLM is the org's Hanzo-routed inference totals from the warehouse."},"range":{"description":"Range is the window label that was served.","type":"string"},"scope":{"$ref":"#/components/schemas/usage.usageScope","description":"Scope is the tenant and subject the roll-up was answered for."},"sources":{"$ref":"#/components/schemas/usage.Sources","description":"Sources says which upstreams actually answered, so a zero can be read as\n\"no data yet\" rather than as a measurement."},"spend":{"$ref":"#/components/schemas/usage.Spend","description":"Spend is the categorized cost roll-up from the billing ledger."},"start":{"description":"Start is the window's inclusive start, RFC3339 UTC.","type":"string"}},"type":"object"},"usage.usageWindowView":{"properties":{"account":{"description":"Account is the linked provider account the window belongs to.","type":"string"},"cachedInputTokens":{"description":"CachedInputTokens is the prompt tokens served from the provider's cache;\nomitted when unknown.","format":"int64","type":"integer"},"confidence":{"description":"Confidence says how much the counters beside it mean — a meter that\nreported only a percentage leaves them at zero, and this is how a reader\ntells that from a true zero.","type":"string"},"costCents":{"description":"CostCents is what the window cost on the PROVIDER's own plan, in US cents.\nIt is not a Hanzo charge.","format":"int64","type":"integer"},"costLimitCents":{"description":"CostLimitCents is the plan's spend ceiling for the window, in US cents.","format":"int64","type":"integer"},"currency":{"description":"Currency is the provider's currency when it is not US cents.","type":"string"},"inputTokens":{"description":"InputTokens is prompt tokens consumed in the window; omitted when unknown.","format":"int64","type":"integer"},"lane":{"description":"Lane is the meter lane this instance belongs to, e.g. a provider's own\nrolling-window meter.","type":"string"},"machine":{"description":"Machine is the host whose meter reported the window.","type":"string"},"outputTokens":{"description":"OutputTokens is completion tokens produced in the window; omitted when\nunknown.","format":"int64","type":"integer"},"plan":{"description":"Plan is the subscription plan the account is on, as the provider names it.","type":"string"},"requests":{"description":"Requests is how many requests were made in the window; omitted when the\nmeter did not report it.","format":"int64","type":"integer"},"resetsAt":{"description":"ResetsAt is when this window rolls over, RFC3339 UTC; omitted when unknown.","type":"string"},"synthetic":{"description":"Synthetic marks an instance the meter inferred rather than read.","type":"boolean"},"totalTokens":{"description":"TotalTokens is the window's total tokens; omitted when unknown.","format":"int64","type":"integer"},"usedPct":{"description":"UsedPct is how much of the window's allowance is consumed, 0–100.","format":"double","type":"number"},"window":{"description":"Window is the window class: 6h, day, week or month.","type":"string"},"windowMinutes":{"description":"WindowMinutes is the window's real length in minutes when the meter\nreported one; omitted when it did not.","format":"int32","type":"integer"},"windowStart":{"description":"WindowStart is when this window opened, RFC3339 UTC; omitted when unknown.","type":"string"}},"type":"object"},"validator.challengeView":{"properties":{"expiresAt":{"description":"ExpiresAt is when the nonce stops being redeemable, as a Unix timestamp.","format":"int64","type":"integer"},"message":{"description":"Message is the EXACT text to personal_sign. It is reconstructed server-side\nfrom the validated org, the slot and the nonce at redemption, so signing\nanything else cannot claim the slot.","type":"string"},"nonce":{"description":"Nonce is the single-use, org-bound challenge value to send back with the\nsignature.","type":"string"},"tokenId":{"description":"TokenID is the slot the challenge was issued for.","format":"uint64","type":"integer"},"ttlSeconds":{"description":"TTLSeconds is the challenge lifetime in seconds.","format":"int64","type":"integer"}},"type":"object"},"validator.registrationView":{"properties":{"id":{"description":"ID is the registration's handle.","type":"string"},"nodeID":{"description":"NodeID is the luxd node the registration is for.","type":"string"},"status":{"description":"Status is the registration's lifecycle state; \"pending_owner_approval\" until\nthe owner co-signs it out of band.","type":"string"}},"type":"object"},"validator.slotView":{"properties":{"blsPubkey":{"description":"BLSPubkey is the node's BLS public key, hex.","type":"string"},"crName":{"description":"CRName is the LuxNetwork custom resource that materializes the node.","type":"string"},"createdAt":{"description":"CreatedAt is when the slot was first claimed, as a Unix timestamp.","format":"int64","type":"integer"},"namespace":{"description":"Namespace is the Kubernetes namespace the node's CR lives in.","type":"string"},"network":{"description":"Network is the luxd network slug the node joins.","type":"string"},"nodeID":{"description":"NodeID is the luxd node id derived from the sealed staking identity. It is\nstable across re-claims of the same slot.","type":"string"},"nodeStatus":{"description":"NodeStatus is the provisioning state of the node: \"node_created\" once the CR\nis applied, \"node_pending\" when no cluster is reachable (the slot is still\nclaimed and the keys are still sealed).","type":"string"},"registration":{"$ref":"#/components/schemas/validator.registrationView","description":"Registration is the queued owner-gated registration, absent until one exists."},"slot":{"description":"Slot is the validator slot number — the same value as tokenId, under the\nname the portal reads.","format":"uint64","type":"integer"},"tokenId":{"description":"TokenID is the GenesisNFT token id that IS this slot.","format":"uint64","type":"integer"},"updatedAt":{"description":"UpdatedAt is when the slot last changed, as a Unix timestamp.","format":"int64","type":"integer"},"wallet":{"description":"Wallet is the lowercase Ethereum address that proved ownership of the NFT.","type":"string"}},"type":"object"},"validator.validatorClaim":{"properties":{"nonce":{"description":"Nonce is the value GET /v1/validator/challenge issued for this slot.","type":"string"},"signature":{"description":"Signature is the wallet's personal_sign over the challenge message, hex with\na 0x prefix.","type":"string"},"tokenId":{"description":"TokenID is the Validator-tier GenesisNFT token id being claimed. It IS the\nvalidator slot.","format":"uint64","type":"integer"}},"type":"object"},"validator.validatorList":{"properties":{"data":{"description":"Data is one entry per slot this org has claimed.","items":{"$ref":"#/components/schemas/validator.slotView"},"type":"array"},"network":{"description":"Network is the luxd network slug new nodes join on this deployment.","type":"string"}},"type":"object"},"wallet.Wallet":{"properties":{"accountId":{"description":"AccountID names the WalletAccount grouping. Required when creating a wallet\nand it must be an account of the caller's own org; empty in a lookup means\nno narrowing by account.","type":"string"},"address":{"description":"Address is the on-chain address. For kms/mpc/treasury it is the EOA a\nsignature from this wallet recovers to; for safe it is the CREATE2 address\nof the Safe CONTRACT, which holds no key — its approvals recover to the MPC\nowner instead. Rotating a kms wallet mints a new key and therefore a NEW\naddress, and funds and approvals at the old one do not follow; mpc,\ntreasury and safe addresses are invariant under rotation.","type":"string"},"agent":{"description":"Agent narrows within the org to one agent. Empty means the dimension is\nunused — the wallet belongs to the org (or project) at large.","type":"string"},"chain":{"description":"Chain is the EVM chain the wallet is bound to, CAIP-2 \"eip155:\u003cn\u003e\" or a\nbare decimal chain id. Empty is chain-agnostic: the ring signs an unbound\ndigest, and a Safe falls back to the Hanzo L1 (36963) because a Safe and\nits EIP-712 domain must be chain-bound.","type":"string"},"createdAt":{"description":"CreatedAt is when the wallet was provisioned, Unix seconds. Listings order\nby it, newest first.","format":"int64","type":"integer"},"custody":{"description":"Custody is the backend holding the signing material, fixed at creation:\n\"kms\" (a secp256k1 key sealed under KMS and opened in-process), \"mpc\" or\n\"treasury\" (an m-of-n threshold key on the deployed ring, which differ by\ngovernance and not by signing mechanics), or \"safe\" (a Safe contract owned\nby an MPC key). A kind the deployment has not wired refuses with 503 rather\nthan fabricating a signature.","type":"string"},"financeAccount":{"description":"FinanceAccount is the finance ledger account bound to this wallet — the\nlookup that turns a ledger account back into an on-chain signer. Absent is\nthe normal state and means unbound; the column is NULL until something\nbinds it.","type":"string"},"id":{"description":"ID is the wallet id, minted by the server as \"wal_\" + 24 hex. It is the\nlast segment of the key ref, and it is the LEDGER SUBJECT an x402 payment\ninto this wallet credits — so it names money as well as key material.","type":"string"},"name":{"description":"Name is the display label given at creation. It addresses nothing: the key\nref is derived from the scope and the id, so renaming moves no material.","type":"string"},"org":{"description":"Org is the tenant. It is the hard isolation boundary, always present and\nnever crossed, stamped from the validated principal rather than read from a\nrequest. It is also the first segment of the key ref, which is what stops\nanother tenant from addressing this material.","type":"string"},"project":{"description":"Project narrows within the org to one project. On a wallet it is the\ncaller's ambient X-Project-Id at creation and never a body field, so key\nmaterial cannot be addressed under a scope no minter validated; the DEFAULT\nproject collapses to empty, which is what keeps an org's default-scope\nwallet on the un-suffixed ref. Empty means the dimension is unused.","type":"string"},"tier":{"description":"Tier is the wallet tier the ring keys its TierPolicy on: hot, warm, cold,\ngas, bridge, contract_admin, validator, quarantine or disaster_recovery.\nIt defaults to hot and is refused at the boundary if it is none of the nine.","type":"string"}},"type":"object"},"wallet.WalletAccount":{"properties":{"createdAt":{"description":"CreatedAt is when the account was opened, Unix seconds. Listings order by\nit, newest first.","format":"int64","type":"integer"},"id":{"description":"ID is the account id, minted by the server as \"acct_\" + 24 hex. Wallets\nname it as their accountId, and it becomes a segment of each of their key\nrefs — so it addresses key material and cannot be reassigned.","type":"string"},"name":{"description":"Name is the label given at creation, trimmed and required. It groups\nwallets: it is not a key, holds no balance, and is not unique in the org.","type":"string"},"org":{"description":"Org is the tenant that owns the account, stamped from the validated\nprincipal rather than taken from the request. Every read is physically\nscoped to it, so another tenant's accounts are not reachable at all.","type":"string"}},"type":"object"},"wallet.accountList":{"properties":{"accounts":{"description":"Accounts are the org's accounts, newest first.","items":{"$ref":"#/components/schemas/wallet.WalletAccount"},"type":"array"}},"type":"object"},"wallet.createAccountIn":{"properties":{"name":{"description":"Name is the account's label. Required, trimmed; it groups wallets and is\nnot itself a key.","type":"string"}},"type":"object"},"wallet.createWalletIn":{"properties":{"accountId":{"description":"AccountID is the account this wallet belongs to. Required, and it must be\nan account of the caller's own org — an unknown one is a 404.","type":"string"},"agent":{"description":"Agent optionally narrows the wallet to one agent within the org. It becomes\na segment of the key ref, so it must be a url-safe segment with no slash.","type":"string"},"chain":{"description":"Chain is the EVM chain this wallet is for, as \"eip155:\u003cn\u003e\" or a bare\ndecimal chain id. Optional; a Safe defaults to the Hanzo L1 (36963).","type":"string"},"custody":{"description":"Custody selects the signing backend: \"kms\" (in-process, always available),\n\"mpc\" or \"treasury\" (the deployed MPC ring), or \"safe\" (a Safe smart wallet\nowned by an MPC key). Empty uses the deployment's default. A backend that is\nnot configured fails CLOSED with 503 rather than fabricating a signature.","type":"string"},"name":{"description":"Name is the wallet's display label. Optional.","type":"string"},"tier":{"description":"Tier is the MPC wallet tier: hot, warm, cold, gas, bridge, contract_admin,\nvalidator, quarantine or disaster_recovery. Empty defaults to hot.","type":"string"}},"type":"object"},"wallet.safeProposal":{"properties":{"r":{"description":"R is the r component of the MPC threshold signature over the Safe-tx hash.","type":"string"},"s":{"description":"S is the s component of that signature.","type":"string"},"safeAddress":{"description":"SafeAddress is the Safe contract this transaction is for.","type":"string"},"safeTxHash":{"description":"SafeTxHash is the EIP-712 Safe transaction hash, bound to the Safe contract\nand the chain id — the value the owner approval signs.","type":"string"},"walletId":{"description":"WalletID is the wallet whose Safe this is.","type":"string"}},"type":"object"},"wallet.safeTxIn":{"properties":{"chainId":{"description":"ChainID is the EVM chain the Safe transaction is bound to. 0 uses the\nwallet's own chain, or the Hanzo L1 (36963) when it is chain-agnostic.","format":"int64","type":"integer"},"data":{"description":"Data is the call data, hex-encoded.","type":"string"},"nonce":{"description":"Nonce is the Safe's transaction nonce.","format":"int64","type":"integer"},"to":{"description":"To is the transaction's target address.","type":"string"},"value":{"description":"Value is the native-token amount to send, as a decimal string in wei.","type":"string"}},"type":"object"},"wallet.signIn":{"properties":{"digest":{"description":"Digest is a pre-computed 32-byte digest as hex, with or without the 0x\nprefix. When present it is signed verbatim and message is ignored.","type":"string"},"message":{"description":"Message is arbitrary text to hash with Keccak256 and sign. Used only when\ndigest is empty.","type":"string"}},"type":"object"},"wallet.signature":{"properties":{"address":{"description":"Address is the wallet's on-chain address, the one this signature recovers to.","type":"string"},"digest":{"description":"Digest is the 32-byte digest that was signed, hex with an 0x prefix.","type":"string"},"signature":{"description":"Signature is the 65-byte secp256k1 signature, hex with an 0x prefix.","type":"string"},"walletId":{"description":"WalletID is the wallet that signed.","type":"string"}},"type":"object"},"wallet.walletList":{"properties":{"wallets":{"description":"Wallets are the matching wallets, newest first.","items":{"$ref":"#/components/schemas/wallet.Wallet"},"type":"array"}},"type":"object"},"web3.Chain":{"properties":{"chainId":{"description":"ChainID is the EIP-155 id, so a caller can check it matches the wallet\nthey are about to sign with.","format":"int64","type":"integer"},"id":{"description":"ID is the URL name: the value of :chain.","type":"string"},"name":{"description":"Name is for humans.","type":"string"}},"type":"object"},"web3.balances":{"properties":{"address":{"description":"Address is the account they belong to.","type":"string"},"chain":{"description":"Chain is the chain the balances were read from.","type":"string"},"native":{"description":"Native is the chain's own currency, as a 0x-quantity — the RPC's own\nencoding, not a float, because a wei value does not survive float64.","type":"string"}},"type":"object"},"web3.chainList":{"properties":{"chains":{"description":"Chains is every chain this deployment is configured to reach, sorted by\nid. Empty when none are configured — never a fabricated entry.","items":{"$ref":"#/components/schemas/web3.Chain"},"type":"array"}},"type":"object"},"web3.chainStatus":{"properties":{"chainId":{"description":"ChainID is the EIP-155 id, so a caller can check it matches the wallet\nthey are about to sign with.","format":"int64","type":"integer"},"height":{"description":"Height is the latest block, omitted when the chain did not answer rather\nthan reported as zero — a zero height is a real value on a fresh chain.","format":"int64","type":"integer"},"id":{"description":"ID is the URL name: the value of :chain.","type":"string"},"live":{"description":"Live is whether the upstream answered eth_blockNumber.","type":"boolean"},"name":{"description":"Name is for humans.","type":"string"}},"type":"object"},"web3.rpcError":{"properties":{"code":{"description":"Code is the JSON-RPC error code the chain reported, passed through as it\ncame. -32603 (internal error) is the one value this deployment mints\nitself, for an upstream that could not be reached at all.","format":"int64","type":"integer"},"message":{"description":"Message is the chain's own explanation, e.g. \"execution reverted\". It is\n\"upstream unavailable\" when the deployment minted the error rather than the\nchain — that is the one message this side writes.","type":"string"}},"type":"object"},"web3.rpcIn":{"properties":{"chain":{"description":"Chain is the registry id, from the URL.","type":"string"},"id":{"description":"ID is echoed back untouched."},"jsonrpc":{"description":"JSONRPC must be \"2.0\" when present.","type":"string"},"method":{"description":"Method is the RPC method, e.g. eth_getBalance.","type":"string"},"params":{"description":"Params is the method's parameters, passed through unread."}},"type":"object"},"web3.rpcOut":{"properties":{"error":{"$ref":"#/components/schemas/web3.rpcError","description":"Error is the JSON-RPC error object, present instead of Result. Its presence\nis the ONLY way a failure shows up here: the HTTP status stays 200, because\nthat is what a standard JSON-RPC client parses."},"id":{"description":"ID is the request's id, echoed back untouched — any JSON value, because\nJSON-RPC lets the caller choose. A request with no id is sent upstream as 1."},"jsonrpc":{"description":"JSONRPC is always \"2.0\". An upstream that omits it has it filled in, so a\nclient never has to cope with a response that is missing the one field\ntelling it which protocol it is reading.","type":"string"},"result":{"description":"Result is the chain's answer, passed through unread: an eth_getBalance\nresult is a 0x-quantity string, a block is an object. Absent when Error is\npresent — JSON-RPC 2.0 requires exactly one of the two, and this is what the\nchain answered rather than something reassembled here."}},"type":"object"},"webhook.DeliveryRow":{"properties":{"attempt":{"description":"Attempt is which try this row is, starting at 1. The ladder waits 1s, then 5s,\nthen 25s before the next one.","format":"int64","type":"integer"},"created":{"description":"Created is when the attempt was made, RFC3339 in UTC.","type":"string"},"delivery":{"description":"DeliveryID groups the attempts for ONE event to ONE endpoint. Rows sharing it\nare the same delivery being retried, not separate events.","type":"string"},"durationMs":{"description":"DurationMs is how long this attempt took end to end, in MILLISECONDS.","format":"int64","type":"integer"},"endpoint":{"description":"EndpointID is which subscriber this attempt was for.","type":"string"},"error":{"description":"Error says what went wrong on a non-ok attempt. Empty on success.","type":"string"},"httpStatus":{"description":"HTTPStatus is what the subscriber answered. ZERO means it never answered — a\nrefused connection, a DNS failure or a timeout — which is why a zero here is\nnot a 200.","format":"int64","type":"integer"},"status":{"description":"Status is \"ok\" when the subscriber accepted it, \"retrying\" while a further\nattempt will follow, and \"failed\" when none will. Exactly one row of a delivery\nis terminal.","type":"string"},"subject":{"description":"Subject is the event that was delivered (\"commerce.order.created\"). A manual\ntest send carries \"webhook.test\".","type":"string"}},"type":"object"},"webhook.Endpoint":{"properties":{"created":{"description":"CreatedAt is when the endpoint was registered, RFC3339 in UTC — stored in that\nspelling because it sorts as a string.","type":"string"},"deliveries7d":{"description":"Deliveries7d is how many deliveries SETTLED in the trailing 7 days — the\nattempts that ended ok or failed, so a delivery still retrying is in neither\ncounter yet. It is counted from the log at read time rather than stored, and\nit is filled only on a list or a get; a create answers 0 because there is no\nhistory, which is why it is never omitted.","format":"int64","type":"integer"},"description":{"description":"Description is the operator's own label for the endpoint. Never sent anywhere.","type":"string"},"events":{"description":"Events are the subject patterns this endpoint subscribes to\n(\"commerce.order.\u003e\"). An EMPTY list means every event, not none.","items":{"type":"string"},"type":"array"},"failures7d":{"description":"Failures7d is how many of those settled as failed — the subscriber never\naccepted it and no further attempt will be made. It is the numerator to\nDeliveries7d, over the same window.","format":"int64","type":"integer"},"id":{"description":"ID is the endpoint's handle, server-minted and stable for its life. It is what\nevery other route here addresses.","type":"string"},"org":{"description":"Org is the tenant that owns the endpoint, taken from the validated principal\nrather than from any request field.","type":"string"},"secret":{"description":"Secret is the HMAC-SHA256 signing key a subscriber recomputes the signature\nwith. It is returned exactly ONCE, on create: a later read of the endpoint\nomits it, so a lost secret is replaced rather than recovered.","type":"string"},"status":{"description":"Status is \"active\" or \"disabled\" — nothing else is accepted. A disabled\nendpoint keeps its subscription and receives no deliveries, except a manual\ntest send, which goes out anyway.","type":"string"},"updated":{"description":"UpdatedAt is when its url, events, status or description last changed.","type":"string"},"url":{"description":"URL is where the POST goes. Changing it is the one edit that redirects an\norg's events, which is why it is never bindable from a query string.","type":"string"}},"type":"object"},"webhook.createEndpointIn":{"properties":{"description":{"description":"Description is a free-text label for the console. Optional, clipped to 1024 bytes.","type":"string"},"events":{"description":"Events are NATS subject patterns to subscribe to (e.g. \"commerce.order.\u003e\").\nAn empty or omitted list means EVERY event on the platform bus. Max 64\npatterns, each max 256 bytes.","items":{"type":"string"},"type":"array"},"status":{"description":"Status is \"active\" or \"disabled\". Empty defaults to active. A disabled\nendpoint receives no bus deliveries, but can still be exercised with\nPOST /v1/webhook/{id}/test.","type":"string"},"url":{"description":"URL is the https:// address each matching event is POSTed to. Required,\nmax 2048 bytes; http:// and every other scheme is refused, because a\nwebhook carries signed event data and must not travel in the clear.","type":"string"}},"type":"object"},"webhook.deliveryList":{"properties":{"data":{"description":"Data is the matching attempts, newest first.","items":{"$ref":"#/components/schemas/webhook.DeliveryRow"},"type":"array"}},"type":"object"},"webhook.endpointList":{"properties":{"data":{"description":"Data is the org's endpoints, newest first, each with its signing secret\nREDACTED — the secret leaves the server only on create and on rotate.","items":{"$ref":"#/components/schemas/webhook.Endpoint"},"type":"array"}},"type":"object"},"webhook.testResult":{"properties":{"delivered":{"description":"Delivered is whether the subscriber accepted the test POST. It is the whole\nanswer: the send is synchronous and is not retried.","type":"boolean"},"durationMs":{"description":"DurationMs is how long the single attempt took, in MILLISECONDS.","format":"int64","type":"integer"},"error":{"description":"Error says what stopped it. Empty when delivered.","type":"string"},"httpStatus":{"description":"HTTPStatus is what the subscriber answered, or 0 if it never answered.","format":"int64","type":"integer"}},"type":"object"},"webhook.updateEndpointIn":{"properties":{"description":{"description":"Description is a free-text label for the console. Optional, clipped to 1024 bytes.","type":"string"},"events":{"description":"Events are NATS subject patterns to subscribe to. An empty or omitted list\nmeans EVERY event. Max 64 patterns, each max 256 bytes.","items":{"type":"string"},"type":"array"},"status":{"description":"Status is \"active\" or \"disabled\". Empty defaults to active.","type":"string"},"url":{"description":"URL is the https:// address each matching event is POSTed to. Required,\nmax 2048 bytes; http:// and every other scheme is refused.","type":"string"}},"type":"object"},"websearch.searchEngine":{"properties":{"acceptsKey":{"description":"AcceptsKey is whether the engine takes an API key at all.","type":"boolean"},"available":{"description":"Available is whether the engine answers from this cluster as things\nstand: it needs no key there (bing, ddg), or its key is held. Mojeek's\nkeyless page still runs as a fallback but does not count, because it does\nnot answer from this cluster's egress.","type":"boolean"},"enabled":{"description":"Enabled is whether searches run it.","type":"boolean"},"keyed":{"description":"Keyed is whether the platform holds a key for it in KMS. The key itself is\nnever returned by any operation.","type":"boolean"},"name":{"description":"Name is the engine: `mojeek`, `bing`, `brave` or `ddg`.","type":"string"},"needsKey":{"description":"NeedsKey is whether the engine answers only with a key.","type":"boolean"},"options":{"$ref":"#/components/schemas/websearch.searchEngineOptions","description":"Options are the values the engine is asked with, defaults filled in."},"order":{"description":"Order is its place among the enabled engines, from 1; 0 when disabled.","format":"int64","type":"integer"},"supports":{"description":"Supports lists the options the engine reads, with each one's bounds.","items":{"$ref":"#/components/schemas/websearch.searchEngineOption"},"type":"array"}},"type":"object"},"websearch.searchEngineKey":{"properties":{"key":{"description":"Key is the API key. Sealed in KMS and never returned, logged or echoed.\nNever read from the query string.","type":"string"},"name":{"description":"Name is the engine, from the path.","type":"string"}},"type":"object"},"websearch.searchEngineKeyed":{"properties":{"keyed":{"description":"Keyed is whether a key is now held.","type":"boolean"},"name":{"description":"Name is the engine.","type":"string"}},"type":"object"},"websearch.searchEngineOption":{"properties":{"default":{"description":"Default is the count used when none is set. Absent for a text option,\nwhose default is unset.","format":"int64","type":"integer"},"max":{"description":"Max is the most count the engine accepts. Absent for a text option.","format":"int64","type":"integer"},"min":{"description":"Min is the least count the engine accepts. Absent for a text option.","format":"int64","type":"integer"},"name":{"description":"Name is the option: `count`, `language` or `region`.","type":"string"},"param":{"description":"Param is the engine's own query parameter the option sets, such as `t`\nor `rb` for Mojeek.","type":"string"}},"type":"object"},"websearch.searchEngineOptions":{"properties":{"count":{"description":"Count is how many hits the engine is asked for per search. 0 or absent on\na write means the engine's default; a read reports the value in force.","format":"int64","type":"integer"},"language":{"description":"Language is the default language the engine is asked in, as a tag like\n`en` or `en-US`. A search that names its own language overrides it.","type":"string"},"region":{"description":"Region is a two-letter country code the engine favours, like `GB`.\nStored upper case.","type":"string"}},"type":"object"},"websearch.searchEngines":{"properties":{"engines":{"description":"Engines are the enabled engines in the order they run, then the rest by\nname.","items":{"$ref":"#/components/schemas/websearch.searchEngine"},"type":"array"},"saved":{"description":"Saved is whether a setting is stored. False means the default is in\nforce: Mojeek alone when its key is held, else bing, ddg and Mojeek.","type":"boolean"}},"type":"object"},"websearch.searchEnginesSet":{"properties":{"enabled":{"description":"Enabled are the engines searches run, in order. At least one, each a\nregistered engine named once, and at least one of them must be available.","items":{"type":"string"},"type":"array"},"options":{"additionalProperties":{"$ref":"#/components/schemas/websearch.searchEngineOptions"},"description":"Options are each engine's values, by engine name — for any registered\nengine, enabled or not. An engine or a field left out takes its default:\nthe setting replaces the stored one whole.","type":"object"}},"type":"object"},"websearch.webEngine":{"properties":{"name":{"description":"Name is the engine, matching the `engine` stamped on each result.","type":"string"},"outcome":{"description":"Outcome is \"answered\", \"blind\" or \"failed\" — see outcome.go. \"blind\" means\nthe page came back and no results could be read out of it.","type":"string"},"results":{"description":"Results is how many hits this engine contributed, before the merge\ndeduplicated them against the others.","format":"int64","type":"integer"}},"type":"object"},"websearch.webResult":{"properties":{"content":{"description":"Content is the ENGINE's snippet — the few lines shown under the title, not\nthe page's text. Read the page itself with POST /v1/crawl.","type":"string"},"engine":{"description":"Engine names the backend that found this hit, so one engine's view of a\nquery can be told from another's.","type":"string"},"title":{"description":"Title is the page's title.","type":"string"},"url":{"description":"URL is the page's address, as the engine reported it.","type":"string"}},"type":"object"},"websearch.webSearchQuery":{"properties":{"language":{"description":"Language narrows the engines to a locale, BCP-47-ish (\"en\", \"ja\", \"de\").\nEmpty means no narrowing.","type":"string"},"q":{"description":"Q is the query. Required — an empty one is refused rather than answered\nwith the whole web.","type":"string"}},"type":"object"},"websearch.webSearchResults":{"properties":{"engines":{"description":"Engines is one entry per engine asked, in the order they were asked. It is\nADDITIVE to the SearXNG contract, which the LibreChat client ignores as an\nunknown field exactly as it ignores `engine` on a result.","items":{"$ref":"#/components/schemas/websearch.webEngine"},"type":"array"},"number_of_results":{"description":"NumberOfResults is len(results) — what this answer carries, never an\nestimate of what the web holds.","format":"int64","type":"integer"},"query":{"description":"Query is the query that ran, echoed back.","type":"string"},"results":{"description":"Results are the merged hits, deduplicated by normalised URL and capped at\n30. Always an array and never null: no hits is an ANSWER, not a fault.","items":{"$ref":"#/components/schemas/websearch.webResult"},"type":"array"}},"type":"object"},"world.Filters":{"properties":{"keywords":{"description":"Keywords keeps only items whose TITLE contains one of these,\ncase-insensitively. They are also the GDELT queries the feed fans out to,\none per keyword of three characters or more — so a keyword both widens what\nis fetched and narrows what is kept.","items":{"type":"string"},"type":"array"},"regions":{"description":"Regions keeps only items whose TITLE contains one of these, matched\ncase-insensitively as a substring. Empty keeps every region.","items":{"type":"string"},"type":"array"},"sources":{"description":"Sources keeps only items whose outlet name contains one of these,\ncase-insensitively. Empty keeps every outlet.","items":{"type":"string"},"type":"array"}},"type":"object"},"world.NewsItem":{"properties":{"image":{"description":"Image is a lead-image URL when the upstream carried one.","type":"string"},"lang":{"description":"Lang is the article's language code when the upstream reported one.","type":"string"},"link":{"description":"Link is the article's URL at the outlet.","type":"string"},"pubDate":{"description":"PubDate is when the outlet published it, RFC3339 UTC. Empty when the\nupstream gave no date this could parse — items with no date sort last.","type":"string"},"source":{"description":"Source is the outlet the item came from, as the upstream named it.","type":"string"},"title":{"description":"Title is the headline.","type":"string"},"tone":{"description":"Tone is GDELT's own sentiment score for the article, as text. Only GDELT\nitems carry it.","type":"string"}},"type":"object"},"world.limitsBlock":{"properties":{"apiRateLimit":{"description":"APIRateLimit is requests per minute allowed against the REST /v1/world\nsurface. -1 means unlimited.","format":"int64","type":"integer"},"maxAlerts":{"description":"MaxAlerts is how many saved OSINT alert rules the plan allows. -1 means\nunlimited.","format":"int64","type":"integer"},"mcpRateLimit":{"description":"MCPRateLimit is requests per minute allowed against the MCP surface. -1\nmeans unlimited.","format":"int64","type":"integer"},"modelApi":{"description":"ModelAPI is whether the plan reaches the World model endpoint and the SSE\nstream. The free floor is false, and that is what a catalog outage\nresolves to.","type":"boolean"}},"type":"object"},"world.limitsView":{"properties":{"limits":{"$ref":"#/components/schemas/world.limitsBlock","description":"Limits is the plan's decision."},"plan":{"description":"Plan echoes the plan id the limits were resolved for, after the empty-means-\nworld-free default.","type":"string"},"unit":{"description":"Unit names what the two rate numbers are counted in: requests/minute.","type":"string"}},"type":"object"},"world.newsResponse":{"properties":{"items":{"description":"Items is the merged, filtered, deduped feed, freshest first and capped at\n50. A source that failed is skipped rather than failing the read, so this\ncan be shorter than the pipeline's reach — it is never an error.","items":{"$ref":"#/components/schemas/world.NewsItem"},"type":"array"}},"type":"object"},"world.pipelineReq":{"properties":{"feeds":{"description":"Feeds is the RSS/Atom feed URLs to read, at most 64. Each must be an\nhttp(s) URL whose host is on the server's allowlist — the SSRF guard is\napplied here, at the write, so a stored pipeline can never name a host the\nfetcher would refuse. Blank entries are dropped and duplicates collapse.","items":{"type":"string"},"type":"array"},"filters":{"$ref":"#/components/schemas/world.Filters","description":"Filters narrows the merged feed. Terms are trimmed, de-duplicated\ncase-insensitively, and capped at 64 per axis."}},"type":"object"},"world.pipelineView":{"properties":{"createdAt":{"description":"CreatedAt is when the pipeline was first stored, RFC3339 UTC. Absent on the\ndefault.","type":"string"},"default":{"description":"Default is true when no pipeline is stored for this project and these are\nthe built-in world feeds. Writing one turns it false.","type":"boolean"},"feeds":{"description":"Feeds is the RSS/Atom feed URLs the pipeline reads. Every host is on the\nserver's allowlist — a URL that is not cannot be stored.","items":{"type":"string"},"type":"array"},"filters":{"$ref":"#/components/schemas/world.Filters","description":"Filters narrows the merged feed."},"org":{"description":"Org is the tenant the pipeline belongs to, resolved server-side from the\nvalidated principal.","type":"string"},"project":{"description":"Project is the org sub-scope the pipeline belongs to.","type":"string"},"updatedAt":{"description":"UpdatedAt is when it was last written, RFC3339 UTC. Absent on the default.","type":"string"}},"type":"object"},"world.worldIndex":{"properties":{"product":{"description":"Product is the product's name as customers know it.","type":"string"},"summary":{"description":"Summary is one sentence naming what this surface serves.","type":"string"},"wires":{"description":"Wires is every protocol entry point onto World, REST first. It is\ndeliberately NOT a list of REST operations: GET /v1/openapi.json is the one\nenumeration of those, and a second copy here would be a second thing to keep\ntrue.","items":{"$ref":"#/components/schemas/world.worldWire"},"type":"array"}},"type":"object"},"world.worldWire":{"properties":{"auth":{"description":"Auth states what the wire asks of the caller, including which parts of it\nanswer without a token.","type":"string"},"name":{"description":"Name is the wire's short id — rest, mcp or zap.","type":"string"},"path":{"description":"Path is the address the wire answers on, under this same origin.","type":"string"},"protocol":{"description":"Protocol names what the wire speaks, so a caller knows which client to\npoint at it.","type":"string"},"spec":{"description":"Spec is where this wire's operations are enumerated, when they are\nenumerated in a document at all. Empty for a wire that describes itself\nover its own protocol.","type":"string"}},"type":"object"},"x402.Receipt":{"properties":{"amount":{"description":"Amount is what actually moved, as an exact 18-decimal-place USD string. It\nis NOT the atomic-unit figure the client signed: the challenge quotes the\nasset's own units (USDC's 6 dp) and truncates to fit them, while the ledger\nmoves this exact value.","type":"string"},"category":{"description":"Category is what the payment was for — service, goods, transfer or royalty\n— as the price table said it: a tool call is a service, a job is what its\nparties agreed.","type":"string"},"from":{"description":"From is the payer's EVM address: the account that signed the EIP-3009\nauthorization, recovered from the signature rather than taken on trust.","type":"string"},"id":{"description":"ID is the settle-once key: \"x402_\" + keccak(from|nonce) in hex. It is\nDERIVED, not minted, so a client that re-submits the same authorization\naddresses the same settlement and is served again for free rather than\ncharged twice. It is also the id GET /v1/x402/settlements/:id takes.","type":"string"},"network":{"description":"Network is the CAIP-2 identifier the payment was settled under, e.g.\n\"eip155:36963\". Its eip155 reference is the chain id in the EIP-712 domain\nthe payer signed, so it is not a label — changing it invalidates the\nsignature.","type":"string"},"nonce":{"description":"Nonce is the client-chosen nonce from the authorization, hex — up to 32\nbytes, left-padded to the contract's bytes32. It is the replay anchor: the\ntoken contract refuses a second on-chain transfer for one (from, nonce), and\nthis rail refuses a second settlement for the same pair, so a ledger\nsettlement inherits the identical guarantee.","type":"string"},"payee":{"description":"Payee is the recipient's EVM address — the `payTo` the challenge advertised\nand the authorization named. A payment to any other address never settles.","type":"string"},"payeeOrg":{"description":"PayeeOrg is the tenant that owns the recipient wallet, resolved at\nsettlement. It is who got PAID, as Payer is who paid.","type":"string"},"payer":{"description":"Payer is the payer ORG — the tenant whose ledger was debited — and not an\naddress. It is the org the request was authenticated as, so it answers who\nis billed, which the payer address alone cannot.","type":"string"},"resource":{"description":"Resource is what was paid for, in the same spelling the price table and the\nchallenge used: the request path for a priced route, \"tool:\u003cid\u003e\" for a\npriced tool.","type":"string"},"settledAt":{"description":"SettledAt is when this settlement was CLAIMED, in unix seconds — the moment\nthe authorization was accepted, which is also the moment the time window it\ncarried stopped applying. A settlement finished later by reconciliation\nkeeps this instant.","format":"int64","type":"integer"},"settledVia":{"description":"SettledVia is which rail moved the money: \"ledger\", the live default, or\n\"chain\" when the authorization is broadcast. Those two values and no others.","type":"string"},"txHash":{"description":"TxHash is the chain transaction hash, present only for a \"chain\"\nsettlement. Empty on a ledger settlement — that is the normal case today,\nand it means the money moved without a chain, not that it failed. The\nwire's PAYMENT-RESPONSE `transaction` falls back to ID when this is empty.","type":"string"}},"type":"object"},"x402.settlementList":{"properties":{"settlements":{"description":"Settlements is at most 1000 receipts.","items":{"$ref":"#/components/schemas/x402.Receipt"},"type":"array"}},"type":"object"}},"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"The caller's credential, sent as `Authorization: Bearer \u003ctoken\u003e`. It is either an access token minted by Hanzo IAM or an API key (pk-/sk-). X-Authorization, and HTTP Basic carrying the token as the password, are accepted spellings of the same header for clients that cannot set Authorization; a browser presents the session cookie instead. Every operation requires it unless it says `security: []`."}}}}