[{"Service":"account","Name":"appearance-create","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.","Method":"POST","Path":"/v1/account/appearance","Args":[],"Flags":[{"Name":"accent","Field":"accent","Type":"string","Help":"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.","Required":false},{"Name":"density","Field":"density","Type":"string","Help":"Density is the spacing step: \"compact\", \"default\" or \"comfortable\".","Required":false},{"Name":"type","Field":"type","Type":"number","Help":"Type is the text-size multiplier, clamped to the ramp window [0.85, 1.4].\nAbsent (0) leaves the published default.","Required":false}],"Example":{"accent":"#8b5cf6","density":"compact","type":1.15}},{"Service":"account","Name":"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.","Method":"GET","Path":"/v1/account/appearance","Args":[],"Flags":null,"Example":null},{"Service":"account","Name":"avatar-create","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.","Method":"POST","Path":"/v1/account/avatar","Args":[],"Flags":null,"Example":null},{"Service":"account","Name":"avatar-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.","Method":"GET","Path":"/v1/account/avatar/:org/:user/:digest","Args":[{"Name":"org","Help":""},{"Name":"user","Help":""},{"Name":"digest","Help":""}],"Flags":null,"Example":null},{"Service":"account","Name":"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.","Method":"GET","Path":"/v1/account/csrf","Args":[],"Flags":null,"Example":null},{"Service":"account","Name":"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.","Method":"GET","Path":"/v1/account/embed","Args":[],"Flags":[{"Name":"app","Field":"app","Type":"string","Help":"App is the embedded app to report on: cms (Content Studio), erp or help.","Required":false}],"Example":{"app":"cms"}},{"Service":"account","Name":"keys-create","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.","Method":"POST","Path":"/v1/account/keys","Args":[],"Flags":[{"Name":"budget","Field":"budget","Type":"json","Help":"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.","Required":false},{"Name":"expires","Field":"expires","Type":"string","Help":"Expires is when the key stops working, RFC 3339. Omitted means never.","Required":false},{"Name":"limit","Field":"limit","Type":"json","Help":"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\"]}","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name labels the key. Omitted names it \"key N\".","Required":false},{"Name":"rate","Field":"rate","Type":"integer","Help":"Rate caps the key's requests a minute; past it a request is refused 429.\nOmitted means no limit of its own.","Required":false},{"Name":"type","Field":"type","Type":"string","Help":"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.","Required":false}],"Example":{"budget":{"month":5000,"total":0},"name":"production","rate":600,"type":"secret"}},{"Service":"account","Name":"keys-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.","Method":"DELETE","Path":"/v1/account/keys/:id","Args":[{"Name":"id","Help":"ID is the key to act on, from the path."}],"Flags":null,"Example":null},{"Service":"account","Name":"keys-list","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.","Method":"GET","Path":"/v1/account/keys","Args":[],"Flags":null,"Example":null},{"Service":"account","Name":"keys-update","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.","Method":"PATCH","Path":"/v1/account/keys/:id","Args":[{"Name":"id","Help":"ID is the key to edit, from the path."}],"Flags":[{"Name":"budget","Field":"budget","Type":"json","Help":"Budget replaces the key's spend caps, in cents; a zero drops that cap.","Required":false},{"Name":"expires","Field":"expires","Type":"string","Help":"Expires replaces when the key stops working, RFC 3339. An empty string means\nnever.","Required":false},{"Name":"limit","Field":"limit","Type":"json","Help":"Limit replaces what the key may reach. An empty list makes it unrestricted.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name relabels the key.","Required":false},{"Name":"rate","Field":"rate","Type":"integer","Help":"Rate replaces the key's requests a minute; zero drops the limit.","Required":false}],"Example":{"budget":{"month":5000,"total":0},"limit":["read:*"],"name":"staging","rate":60}},{"Service":"account","Name":"orgs-create","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.","Method":"POST","Path":"/v1/account/orgs","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"Name is the organization's display name. Ignored when personal is true, which\nderives the name from the caller's own username instead.","Required":false},{"Name":"personal","Field":"personal","Type":"boolean","Help":"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.","Required":false}],"Example":{"name":"Acme"}},{"Service":"ad","Name":"campaigns-create","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.","Method":"POST","Path":"/v1/ad/campaigns","Args":[],"Flags":[{"Name":"account","Field":"account","Type":"string","Help":"Account is the provider ad-account this campaign runs on (Meta act_\u003cid\u003e). Optional.","Required":false},{"Name":"budget","Field":"budget","Type":"integer","Help":"Budget is the campaign budget in MINOR units (cents). Negative values clamp to 0.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the campaign's display label. Required; trimmed and bounded to 1024 bytes.","Required":false},{"Name":"objective","Field":"objective","Type":"string","Help":"Objective is the campaign goal as the provider names it. Optional, bounded to 1024 bytes.","Required":false},{"Name":"platform","Field":"platform","Type":"string","Help":"Platform is the ad network: meta, google, tiktok or x. Empty defaults to meta.","Required":false},{"Name":"spend","Field":"spend","Type":"integer","Help":"Spend is the amount spent so far in MINOR units (cents). Negative values clamp to 0.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status is the lifecycle state: draft, active, paused or completed. Empty defaults to draft.","Required":false}],"Example":{"budget":50000,"name":"Spring Launch","objective":"conversions","platform":"meta"}},{"Service":"ad","Name":"campaigns-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.","Method":"DELETE","Path":"/v1/ad/campaigns/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":{"id":"camp_2f9c1d"}},{"Service":"ad","Name":"campaigns-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.","Method":"GET","Path":"/v1/ad/campaigns/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":{"id":"camp_2f9c1d"}},{"Service":"ad","Name":"campaigns-launch","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.","Method":"POST","Path":"/v1/ad/campaigns/:id/launch","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"ad","Name":"campaigns-list","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.","Method":"GET","Path":"/v1/ad/campaigns","Args":[],"Flags":[{"Name":"status","Field":"status","Type":"string","Help":"Status filters to one lifecycle state (draft, active, paused, completed).\nEmpty returns every campaign the org has.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many campaigns come back: default 200, maximum 1000. A\nvalue that is not a positive integer reads as the default.","Required":false}],"Example":{"limit":50,"status":"active"}},{"Service":"ad","Name":"campaigns-update","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.","Method":"PUT","Path":"/v1/ad/campaigns/:id","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"account","Field":"account","Type":"string","Help":"Account is the provider ad-account this campaign runs on (Meta act_\u003cid\u003e). Optional.","Required":false},{"Name":"budget","Field":"budget","Type":"integer","Help":"Budget is the campaign budget in MINOR units (cents). Negative values clamp to 0.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the campaign's display label. Required; trimmed and bounded to 1024 bytes.","Required":false},{"Name":"objective","Field":"objective","Type":"string","Help":"Objective is the campaign goal as the provider names it. Optional, bounded to 1024 bytes.","Required":false},{"Name":"platform","Field":"platform","Type":"string","Help":"Platform is the ad network: meta, google, tiktok or x. Empty defaults to meta.","Required":false},{"Name":"spend","Field":"spend","Type":"integer","Help":"Spend is the amount spent so far in MINOR units (cents). Negative values clamp to 0.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status is the lifecycle state: draft, active, paused or completed. Empty defaults to draft.","Required":false}],"Example":{"budget":75000,"id":"camp_2f9c1d","name":"Spring Launch","platform":"meta","status":"paused"}},{"Service":"ad","Name":"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.","Method":"GET","Path":"/v1/ad/summary","Args":[],"Flags":null,"Example":null},{"Service":"affiliate","Name":"apply-create","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.","Method":"POST","Path":"/v1/affiliate/apply","Args":[],"Flags":[{"Name":"requested-code","Field":"requestedCode","Type":"string","Help":"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.","Required":false}],"Example":{"requestedCode":"acme"}},{"Service":"affiliate","Name":"attribute-create","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.","Method":"POST","Path":"/v1/affiliate/attribute","Args":[],"Flags":[{"Name":"code","Field":"code","Type":"string","Help":"Code is the affiliate code the referred org arrived with. Body-only: the\nURL cannot supply it.","Required":false}],"Example":{"code":"acme"}},{"Service":"affiliate","Name":"click-create","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.","Method":"POST","Path":"/v1/affiliate/click","Args":[],"Flags":[{"Name":"code","Field":"code","Type":"string","Help":"Code is the share-link code that was clicked. Body-only: the URL cannot\nsupply it.","Required":false}],"Example":{"code":"acme"}},{"Service":"affiliate","Name":"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.","Method":"GET","Path":"/v1/affiliate/leaderboard","Args":[],"Flags":null,"Example":null},{"Service":"affiliate","Name":"list","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.","Method":"GET","Path":"/v1/affiliate","Args":[],"Flags":null,"Example":null},{"Service":"affiliate","Name":"me-earnings-list","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`.","Method":"GET","Path":"/v1/affiliate/me/earnings","Args":[],"Flags":null,"Example":null},{"Service":"affiliate","Name":"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.","Method":"GET","Path":"/v1/affiliate/me","Args":[],"Flags":null,"Example":null},{"Service":"affiliate","Name":"me-handle-create","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.","Method":"POST","Path":"/v1/affiliate/me/handle","Args":[],"Flags":[{"Name":"handle","Field":"handle","Type":"string","Help":"Handle is the public leaderboard display name; empty opts out. Body-only:\nthe URL cannot supply it.","Required":false}],"Example":{"handle":"acme partners"}},{"Service":"affiliate","Name":"me-links-create","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.","Method":"POST","Path":"/v1/affiliate/me/links","Args":[],"Flags":[{"Name":"code","Field":"code","Type":"string","Help":"Code is an optional vanity code; it must be free across the whole\ndirectory, and omitting it mints a random one. Body-only.","Required":false},{"Name":"label","Field":"label","Type":"string","Help":"Label is cosmetic — trimmed, stripped of control characters, capped — and\nnever part of a code. Body-only: the URL cannot supply it.","Required":false}],"Example":{"label":"twitter"}},{"Service":"affiliate","Name":"me-links-list","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.","Method":"GET","Path":"/v1/affiliate/me/links","Args":[],"Flags":null,"Example":null},{"Service":"agent","Name":"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 [].","Method":"GET","Path":"/v1/agent/activity","Args":[],"Flags":null,"Example":null},{"Service":"agent","Name":"ask-create","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.","Method":"POST","Path":"/v1/agent/ask","Args":[],"Flags":null,"Example":null},{"Service":"agent","Name":"builds-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.","Method":"GET","Path":"/v1/agent/builds/:org/:project","Args":[{"Name":"org","Help":"Org is the org that published the build, from the path."},{"Name":"project","Help":"Project is the product's slug, from the path."}],"Flags":null,"Example":{"org":"hanzo","project":"landing"}},{"Service":"agent","Name":"builds-list","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.","Method":"GET","Path":"/v1/agent/builds","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the page. Absent, zero or over 500 reads as 100.","Required":false}],"Example":null},{"Service":"agent","Name":"chat-conversations-create","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.","Method":"POST","Path":"/v1/agent/chat/conversations","Args":[],"Flags":null,"Example":null},{"Service":"agent","Name":"chat-conversations-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.","Method":"DELETE","Path":"/v1/agent/chat/conversations/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"agent","Name":"chat-conversations-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.","Method":"DELETE","Path":"/v1/agent/chat/conversations/:id/shares/:share","Args":[{"Name":"id","Help":""},{"Name":"share","Help":""}],"Flags":null,"Example":null},{"Service":"agent","Name":"chat-conversations-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.","Method":"DELETE","Path":"/v1/agent/chat/conversations/:id/shares/:share/viewers/:viewer","Args":[{"Name":"id","Help":""},{"Name":"share","Help":""},{"Name":"viewer","Help":""}],"Flags":null,"Example":null},{"Service":"agent","Name":"chat-conversations-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.","Method":"GET","Path":"/v1/agent/chat/conversations/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"agent","Name":"chat-conversations-list","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.","Method":"GET","Path":"/v1/agent/chat/conversations","Args":[],"Flags":null,"Example":null},{"Service":"agent","Name":"chat-conversations-shares","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.","Method":"POST","Path":"/v1/agent/chat/conversations/:id/shares","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"agent","Name":"chat-conversations-shares-list","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.","Method":"GET","Path":"/v1/agent/chat/conversations/:id/shares","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"agent","Name":"chat-conversations-update","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.","Method":"PATCH","Path":"/v1/agent/chat/conversations/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"agent","Name":"chat-create","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.","Method":"POST","Path":"/v1/agent/chat","Args":[],"Flags":null,"Example":null},{"Service":"agent","Name":"chat-presets-list","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.","Method":"GET","Path":"/v1/agent/chat/presets","Args":[],"Flags":null,"Example":null},{"Service":"agent","Name":"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.","Method":"GET","Path":"/v1/agent/chat/shared","Args":[],"Flags":null,"Example":null},{"Service":"agent","Name":"chat-shared-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.","Method":"GET","Path":"/v1/agent/chat/shared/:share","Args":[{"Name":"share","Help":""}],"Flags":null,"Example":null},{"Service":"agent","Name":"chat-shares-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.","Method":"DELETE","Path":"/v1/agent/chat/shares/:share","Args":[{"Name":"share","Help":""}],"Flags":null,"Example":null},{"Service":"agent","Name":"chat-shares-list","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.","Method":"GET","Path":"/v1/agent/chat/shares","Args":[],"Flags":null,"Example":null},{"Service":"agent","Name":"chat-shares-read-create","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.","Method":"POST","Path":"/v1/agent/chat/shares/read","Args":[],"Flags":null,"Example":null},{"Service":"agent","Name":"coding-artifacts-list","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.","Method":"GET","Path":"/v1/agent/coding/:session/artifacts","Args":[{"Name":"session","Help":"Session is the run's handle — the sessionId POST /v1/agent/coding answered\nwith — from the path."}],"Flags":null,"Example":{"session":"sess_0123456789abcdef0123456789abcdef"}},{"Service":"agent","Name":"coding-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.","Method":"GET","Path":"/v1/agent/coding/:session/blob","Args":[{"Name":"session","Help":"Session is the run's handle, from the path."}],"Flags":[{"Name":"path","Field":"path","Type":"string","Help":"Path is repo-relative, from the query. Empty is the repository's root.","Required":false}],"Example":{"path":"api/server.go","session":"sess_0123456789abcdef0123456789abcdef"}},{"Service":"agent","Name":"coding-changes-list","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.","Method":"GET","Path":"/v1/agent/coding/:session/changes","Args":[{"Name":"session","Help":"Session is the run's handle — the sessionId POST /v1/agent/coding answered\nwith — from the path."}],"Flags":null,"Example":{"session":"sess_0123456789abcdef0123456789abcdef"}},{"Service":"agent","Name":"coding-create","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.","Method":"POST","Path":"/v1/agent/coding","Args":[],"Flags":[{"Name":"after","Field":"after","Type":"string","Help":"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.","Required":false},{"Name":"agent-ref","Field":"agentRef","Type":"string","Help":"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.","Required":false},{"Name":"base","Field":"base","Type":"string","Help":"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.","Required":false},{"Name":"desktop","Field":"desktop","Type":"boolean","Help":"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.","Required":false},{"Name":"effort","Field":"effort","Type":"string","Help":"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.","Required":false},{"Name":"issue","Field":"issue","Type":"integer","Help":"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.","Required":false},{"Name":"mode","Field":"mode","Type":"string","Help":"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.","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"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.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project scopes the run to one board's work when the org keeps more than one.\nEmpty is the org's default.","Required":false},{"Name":"prompt","Field":"prompt","Type":"string","Help":"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.","Required":false},{"Name":"reply","Field":"reply","Type":"json","Help":"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.","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"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.","Required":false},{"Name":"target-id","Field":"targetId","Type":"string","Help":"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.","Required":false},{"Name":"task","Field":"task","Type":"string","Help":"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.","Required":false},{"Name":"timeout-seconds","Field":"timeoutSeconds","Type":"integer","Help":"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.","Required":false},{"Name":"tool","Field":"tool","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"agent","Name":"coding-merge","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.","Method":"POST","Path":"/v1/agent/coding/:session/merge","Args":[{"Name":"session","Help":"Session is the run's handle — the sessionId POST /v1/agent/coding answered\nwith — from the path."}],"Flags":null,"Example":{"session":"sess_0123456789abcdef0123456789abcdef"}},{"Service":"agent","Name":"coding-steer","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.","Method":"POST","Path":"/v1/agent/coding/:session/steer","Args":[{"Name":"session","Help":"Session identifies the running or paused coding session from the path."}],"Flags":[{"Name":"text","Field":"text","Type":"string","Help":"Text is the new instruction to carry into the follow-up run.","Required":false}],"Example":null},{"Service":"agent","Name":"coding-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.","Method":"GET","Path":"/v1/agent/coding/:session/tree","Args":[{"Name":"session","Help":"Session is the run's handle, from the path."}],"Flags":[{"Name":"path","Field":"path","Type":"string","Help":"Path is repo-relative, from the query. Empty is the repository's root.","Required":false}],"Example":{"path":"api","session":"sess_0123456789abcdef0123456789abcdef"}},{"Service":"agent","Name":"create","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.","Method":"POST","Path":"/v1/agent","Args":[],"Flags":[{"Name":"avatar","Field":"avatar","Type":"string","Help":"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.","Required":false},{"Name":"cap-micro-usd","Field":"cap_micro_usd","Type":"integer","Help":"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.","Required":false},{"Name":"compute-ref","Field":"computeRef","Type":"string","Help":"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.","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"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.","Required":false},{"Name":"emoji","Field":"emoji","Type":"string","Help":"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.","Required":false},{"Name":"execution-mode","Field":"executionMode","Type":"string","Help":"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.","Required":false},{"Name":"instructions","Field":"instructions","Type":"string","Help":"Instructions is the system prompt, up to 32 KiB, stored verbatim. This is what\nthe model reads; Description is what other CALLERS read.","Required":false},{"Name":"max-task-micro-usd","Field":"max_task_micro_usd","Type":"integer","Help":"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.","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false},{"Name":"parent","Field":"parent","Type":"string","Help":"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.","Required":false},{"Name":"period","Field":"period","Type":"string","Help":"Period is the window the cap resets on: day, week or month.","Required":false},{"Name":"schedule","Field":"schedule","Type":"string","Help":"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.","Required":false},{"Name":"service-account-id","Field":"serviceAccountId","Type":"string","Help":"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.","Required":false},{"Name":"tools","Field":"tools","Type":"json","Help":"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.","Required":false}],"Example":{"instructions":"be terse","model":"enso-flash","name":"helper"}},{"Service":"agent","Name":"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.","Method":"DELETE","Path":"/v1/agent/:ref","Args":[{"Name":"ref","Help":"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."}],"Flags":null,"Example":{"ref":"helper"}},{"Service":"agent","Name":"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.","Method":"GET","Path":"/v1/agent/:ref","Args":[{"Name":"ref","Help":"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."}],"Flags":null,"Example":{"ref":"helper"}},{"Service":"agent","Name":"list","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.","Method":"GET","Path":"/v1/agent","Args":[],"Flags":null,"Example":null},{"Service":"agent","Name":"mcp-create","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.","Method":"POST","Path":"/v1/agent/mcp/:server","Args":[{"Name":"server","Help":""}],"Flags":null,"Example":null},{"Service":"agent","Name":"metrics-list","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.","Method":"GET","Path":"/v1/agent/metrics","Args":[],"Flags":[{"Name":"range","Field":"range","Type":"string","Help":"Range is the window to bucket: 24H, 7D or 30D. Anything else reads as 30D.","Required":false}],"Example":{"range":"7D"}},{"Service":"agent","Name":"run","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.","Method":"POST","Path":"/v1/agent/:ref/run","Args":[{"Name":"ref","Help":""}],"Flags":null,"Example":null},{"Service":"agent","Name":"runs-list","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.","Method":"GET","Path":"/v1/agent/:ref/runs","Args":[{"Name":"ref","Help":"Ref is the agent's public id or its org-unique name, from the path."}],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many runs come back, newest first. Absent, zero or out of\nrange (1..200) reads as 50.","Required":false}],"Example":{"limit":20,"ref":"helper"}},{"Service":"agent","Name":"runs-list","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.","Method":"GET","Path":"/v1/agent/runs","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many runs come back, newest first. Absent, zero or out of\nrange (1..200) reads as 50.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"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.","Required":false}],"Example":{"limit":20,"status":"error"}},{"Service":"agent","Name":"sessions-budget","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","Method":"POST","Path":"/v1/agent/sessions/:id/budget","Args":[{"Name":"id","Help":"ID is the session, from the path."}],"Flags":[{"Name":"budget-micro-usd","Field":"budget_micro_usd","Type":"integer","Help":"BudgetMicroUSD is the new cap, or null to remove the cap for good.","Required":false}],"Example":null},{"Service":"agent","Name":"sessions-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.","Method":"GET","Path":"/v1/agent/sessions/:id/control","Args":[{"Name":"id","Help":"ID is the session whose commands are being drained, from the path."}],"Flags":[{"Name":"after","Field":"after","Type":"integer","Help":"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.","Required":false}],"Example":{"after":12,"id":"sess_1"}},{"Service":"agent","Name":"sessions-create","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.","Method":"POST","Path":"/v1/agent/sessions","Args":[],"Flags":[{"Name":"account","Field":"account","Type":"string","Help":"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.","Required":false},{"Name":"agent","Field":"agent","Type":"string","Help":"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.","Required":false},{"Name":"budget-micro-usd","Field":"budget_micro_usd","Type":"integer","Help":"BudgetMicroUSD caps what this session may spend, integer micro-USD. Zero\nmeans no cap; a cap can be raised or removed later, never added.","Required":false},{"Name":"cwd","Field":"cwd","Type":"string","Help":"Cwd is the directory the session starts in, up to 1024 characters. It can be\nmoved later, because a linked shell walks around.","Required":false},{"Name":"host","Field":"host","Type":"string","Help":"Execution context — where this session runs (all optional).","Required":false},{"Name":"parent-session-id","Field":"parentSessionId","Type":"string","Help":"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.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"The readable build (provenance.go): which product this session builds, and\nwhether its story may be read by the world.","Required":false},{"Name":"provider","Field":"provider","Type":"string","Help":"Account tag — the linked AI account this session ran under (login manager).","Required":false},{"Name":"published","Field":"published","Type":"boolean","Help":"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.","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"Repo is the code being worked on, up to 512 characters. A label the surface\nstates; nothing resolves it against the forge.","Required":false},{"Name":"room","Field":"room","Type":"string","Help":"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.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"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.","Required":false},{"Name":"target","Field":"target","Type":"string","Help":"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.","Required":false},{"Name":"task-run-id","Field":"taskRunId","Type":"string","Help":"TaskRunID is that workflow's particular run, same bound. Recorded, not\nresolved: this surface does not check the workflow exists.","Required":false},{"Name":"task-workflow-id","Field":"taskWorkflowId","Type":"string","Help":"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.","Required":false},{"Name":"terminal","Field":"terminal","Type":"string","Help":"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.","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"Title is the human line a card shows, up to 512 characters. Optional, and\nchangeable later.","Required":false}],"Example":{"agent":"hanzo-dev","host":"gpu-01","title":"ship the landing page"}},{"Service":"agent","Name":"sessions-events","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.","Method":"POST","Path":"/v1/agent/sessions/:id/events","Args":[{"Name":"id","Help":"ID is the session to append to, from the path."}],"Flags":[{"Name":"actor","Field":"actor","Type":"string","Help":"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.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"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.","Required":false},{"Name":"payload","Field":"payload","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"agent","Name":"sessions-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.","Method":"GET","Path":"/v1/agent/sessions/:id","Args":[{"Name":"id","Help":"ID is the session to act on, from the path."}],"Flags":null,"Example":{"id":"sess_1"}},{"Service":"agent","Name":"sessions-list","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.","Method":"GET","Path":"/v1/agent/sessions","Args":[],"Flags":[{"Name":"root","Field":"root","Type":"string","Help":"Root scopes the page to one subagent tree (its root session id).","Required":false},{"Name":"parent","Field":"parent","Type":"string","Help":"Parent scopes the page to the direct children of one session. Ignored when\nroot is set; with neither, only ROOT sessions come back.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status filters to running, paused, done or error.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project filters to the sessions tagged with one product slug.","Required":false},{"Name":"room","Field":"room","Type":"string","Help":"Room filters to the sessions started in one collaborative room — the query a\nspace view runs to show what has been run in it.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind filters to the sessions of one kind of run: \"coding\" lists coding runs,\neach carrying its repo, base, branch, environment and pull request.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the page. Absent, zero or over 500 reads as 100.","Required":false},{"Name":"after","Field":"after","Type":"string","Help":"After is the `next` of the previous page. Absent starts at the newest.","Required":false}],"Example":{"limit":20,"status":"running"}},{"Service":"agent","Name":"sessions-message","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.","Method":"POST","Path":"/v1/agent/sessions/:id/message","Args":[{"Name":"id","Help":"ID is the session to steer, from the path."}],"Flags":[{"Name":"message","Field":"message","Type":"string","Help":"Message is free text for the running agent, up to 16 KiB. On a stop it is\nrecorded as the cancellation reason.","Required":false},{"Name":"payload","Field":"payload","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"agent","Name":"sessions-pause","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.","Method":"POST","Path":"/v1/agent/sessions/:id/pause","Args":[{"Name":"id","Help":"ID is the session to steer, from the path."}],"Flags":[{"Name":"message","Field":"message","Type":"string","Help":"Message is free text for the running agent, up to 16 KiB. On a stop it is\nrecorded as the cancellation reason.","Required":false},{"Name":"payload","Field":"payload","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"agent","Name":"sessions-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.","Method":"GET","Path":"/v1/agent/sessions/:id/progress","Args":[{"Name":"id","Help":"ID is the session to act on, from the path."}],"Flags":null,"Example":{"id":"sess_1"}},{"Service":"agent","Name":"sessions-resume","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.","Method":"POST","Path":"/v1/agent/sessions/:id/resume","Args":[{"Name":"id","Help":"ID is the session to steer, from the path."}],"Flags":[{"Name":"message","Field":"message","Type":"string","Help":"Message is free text for the running agent, up to 16 KiB. On a stop it is\nrecorded as the cancellation reason.","Required":false},{"Name":"payload","Field":"payload","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"agent","Name":"sessions-stop","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.","Method":"POST","Path":"/v1/agent/sessions/:id/stop","Args":[{"Name":"id","Help":"ID is the session to steer, from the path."}],"Flags":[{"Name":"message","Field":"message","Type":"string","Help":"Message is free text for the running agent, up to 16 KiB. On a stop it is\nrecorded as the cancellation reason.","Required":false},{"Name":"payload","Field":"payload","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"agent","Name":"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.","Method":"GET","Path":"/v1/agent/sessions/stream","Args":[],"Flags":null,"Example":null},{"Service":"agent","Name":"sessions-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.","Method":"GET","Path":"/v1/agent/sessions/:id/tree","Args":[{"Name":"id","Help":"ID is the session to act on, from the path."}],"Flags":null,"Example":{"id":"sess_1"}},{"Service":"agent","Name":"sessions-update","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).","Method":"PATCH","Path":"/v1/agent/sessions/:id","Args":[{"Name":"id","Help":"ID is the session to update, from the path."}],"Flags":[{"Name":"cwd","Field":"cwd","Type":"string","Help":"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.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"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.","Required":false},{"Name":"published","Field":"published","Type":"boolean","Help":"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.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"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.","Required":false},{"Name":"target","Field":"target","Type":"string","Help":"Target re-dispatches a session to a run-target (the #48 association). \"\" detaches.","Required":false},{"Name":"terminal","Field":"terminal","Type":"string","Help":"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.","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"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.","Required":false}],"Example":{"id":"sess_1","status":"done"}},{"Service":"agent","Name":"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.","Method":"GET","Path":"/v1/agent/:ref/spend","Args":[{"Name":"ref","Help":"Ref is the agent's public id or its org-unique name."}],"Flags":[{"Name":"by","Field":"by","Type":"string","Help":"By groups the answer: \"component\" is the only grouping today.","Required":false}],"Example":null},{"Service":"agent","Name":"targets-claim","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.","Method":"POST","Path":"/v1/agent/targets/:id/claim","Args":[{"Name":"id","Help":"ID is the target to act on, from the path."}],"Flags":null,"Example":{"id":"tgt_1"}},{"Service":"agent","Name":"targets-create","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.","Method":"POST","Path":"/v1/agent/targets","Args":[],"Flags":[{"Name":"capacity","Field":"capacity","Type":"string","Help":"Capacity is a human summary of the machine's size, up to 256 characters. Prose\nonly; a scheduler reads Spec.","Required":false},{"Name":"host","Field":"host","Type":"string","Help":"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.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind is laptop | cloud | gpu | cluster | machine. Empty registers a `machine`;\nanything outside the five is a 400.","Required":false},{"Name":"label","Field":"label","Type":"string","Help":"Label is the name to show for this machine, up to 128 characters. REQUIRED —\nit is the only field here a person reads.","Required":false},{"Name":"metrics","Field":"metrics","Type":"json","Help":"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.","Required":false},{"Name":"spec","Field":"spec","Type":"json","Help":"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.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"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.","Required":false}],"Example":{"host":"gpu-01","kind":"gpu","label":"workshop"}},{"Service":"agent","Name":"targets-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.","Method":"DELETE","Path":"/v1/agent/targets/:id","Args":[{"Name":"id","Help":"ID is the target to act on, from the path."}],"Flags":null,"Example":{"id":"tgt_1"}},{"Service":"agent","Name":"targets-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.","Method":"GET","Path":"/v1/agent/targets/:id","Args":[{"Name":"id","Help":"ID is the target to act on, from the path."}],"Flags":null,"Example":{"id":"tgt_1"}},{"Service":"agent","Name":"targets-key","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.","Method":"POST","Path":"/v1/agent/targets/:id/key","Args":[{"Name":"id","Help":"ID is the target to act on, from the path."}],"Flags":null,"Example":{"id":"tgt_1"}},{"Service":"agent","Name":"targets-list","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.","Method":"GET","Path":"/v1/agent/targets","Args":[],"Flags":null,"Example":null},{"Service":"agent","Name":"targets-report","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.","Method":"POST","Path":"/v1/agent/targets/:id/runs/:runId/report","Args":[{"Name":"id","Help":"ID is the machine reporting, from the path."},{"Name":"runId","Help":"RunID is the routed run being completed, from the path."}],"Flags":[{"Name":"branch","Field":"branch","Type":"string","Help":"Branch, CommitSha and Diffstat describe what the run produced; Error is the\nfailure when OK is false. Each is clamped, never rejected.","Required":false},{"Name":"changed","Field":"changed","Type":"boolean","Help":"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.","Required":false},{"Name":"commit-sha","Field":"commitSha","Type":"string","Help":"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.","Required":false},{"Name":"diffstat","Field":"diffstat","Type":"string","Help":"Diffstat is the run's own summary of what it changed, as text, clamped to\n64 KiB. Free-form: it is shown, never parsed.","Required":false},{"Name":"error","Field":"error","Type":"string","Help":"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.","Required":false},{"Name":"ok","Field":"ok","Type":"boolean","Help":"OK is whether the run succeeded; Changed whether it produced any commit.","Required":false}],"Example":{"branch":"hanzo/fix","changed":true,"id":"tgt_1","ok":true,"runId":"run_1"}},{"Service":"agent","Name":"targets-update","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.","Method":"PATCH","Path":"/v1/agent/targets/:id","Args":[{"Name":"id","Help":"ID is the target to update, from the path."}],"Flags":[{"Name":"capacity","Field":"capacity","Type":"string","Help":"Capacity rewrites the human summary, up to 256 characters. \"\" clears it.","Required":false},{"Name":"host","Field":"host","Type":"string","Help":"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.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind re-files it under laptop | cloud | gpu | cluster | machine.","Required":false},{"Name":"label","Field":"label","Type":"string","Help":"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.","Required":false},{"Name":"metrics","Field":"metrics","Type":"json","Help":"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.","Required":false},{"Name":"spec","Field":"spec","Type":"json","Help":"Spec replaces the static capability whole, sanitized and clamped the same way\na register's is.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"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.","Required":false}],"Example":{"id":"tgt_1","status":"draining"}},{"Service":"agent","Name":"update","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.","Method":"PATCH","Path":"/v1/agent/:ref","Args":[{"Name":"ref","Help":"Ref is the agent to update — its public id or org-unique name, from the path."}],"Flags":[{"Name":"avatar","Field":"avatar","Type":"string","Help":"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.","Required":false},{"Name":"cap-micro-usd","Field":"cap_micro_usd","Type":"integer","Help":"The budget, any part of it. Changing the period opens a new window.","Required":false},{"Name":"compute-ref","Field":"computeRef","Type":"string","Help":"ComputeRef re-binds (or, with \"\", unbinds) the visor machine. Opaque here.","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"Description replaces the line other agents read in the tool catalogue.","Required":false},{"Name":"emoji","Field":"emoji","Type":"string","Help":"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.","Required":false},{"Name":"execution-mode","Field":"executionMode","Type":"string","Help":"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.","Required":false},{"Name":"instructions","Field":"instructions","Type":"string","Help":"Instructions replaces the system prompt whole, up to 32 KiB. There is no\nappend: a prompt is one text, and sending \"\" clears it.","Required":false},{"Name":"max-task-micro-usd","Field":"max_task_micro_usd","Type":"integer","Help":"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.","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"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.","Required":false},{"Name":"period","Field":"period","Type":"string","Help":"Period is the window the cap resets on: day, week or month.","Required":false},{"Name":"schedule","Field":"schedule","Type":"string","Help":"Schedule replaces the cron. It is validated against the mode this update\nleaves behind, and dropped if that mode is one-shot.","Required":false},{"Name":"service-account-id","Field":"serviceAccountId","Type":"string","Help":"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.","Required":false},{"Name":"tools","Field":"tools","Type":"json","Help":"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.","Required":false}],"Example":{"instructions":"be terse and cite sources","ref":"helper"}},{"Service":"ai","Name":"account-get","OperationID":"get_ai_account","Summary":"Account","Description":"","Method":"GET","Path":"/v1/ai/account","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"activities-list","OperationID":"get_ai_activities","Summary":"List activities","Description":"List the caller's activities.","Method":"GET","Path":"/v1/ai/activities","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"answer-get","OperationID":"get_ai_answer","Summary":"Answer","Description":"","Method":"GET","Path":"/v1/ai/answer","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"articles-create","OperationID":"post_ai_articles","Summary":"Create a article","Description":"Create one article.","Method":"POST","Path":"/v1/ai/articles","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"articles-delete","OperationID":"delete_ai_articles_by_owner_by_name","Summary":"Delete a article","Description":"Delete one article.","Method":"DELETE","Path":"/v1/ai/articles/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"articles-get","OperationID":"get_ai_articles_by_owner_by_name","Summary":"Retrieve a article","Description":"Read one article by its (owner, name) key.","Method":"GET","Path":"/v1/ai/articles/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"articles-global-get","OperationID":"get_ai_articles_global","Summary":"List articles across tenants","Description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","Method":"GET","Path":"/v1/ai/articles/global","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"articles-list","OperationID":"get_ai_articles","Summary":"List articles","Description":"List the caller's articles.","Method":"GET","Path":"/v1/ai/articles","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"articles-update","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.","Method":"PATCH","Path":"/v1/ai/articles/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"articles-update","OperationID":"put_ai_articles_by_owner_by_name","Summary":"Replace a article","Description":"Identical to PATCH — the handler takes a whole object either way.","Method":"PUT","Path":"/v1/ai/articles/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"assets-create","OperationID":"post_ai_assets","Summary":"Create a asset","Description":"Create one asset.","Method":"POST","Path":"/v1/ai/assets","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"assets-delete","OperationID":"delete_ai_assets_by_owner_by_name","Summary":"Delete a asset","Description":"Delete one asset.","Method":"DELETE","Path":"/v1/ai/assets/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"assets-get","OperationID":"get_ai_assets_by_owner_by_name","Summary":"Retrieve a asset","Description":"Read one asset by its (owner, name) key.","Method":"GET","Path":"/v1/ai/assets/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"assets-list","OperationID":"get_ai_assets","Summary":"List assets","Description":"List the caller's assets.","Method":"GET","Path":"/v1/ai/assets","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"assets-scan","OperationID":"post_ai_assets_by_owner_by_name_scan","Summary":"Scan (asset)","Description":"","Method":"POST","Path":"/v1/ai/assets/:owner/:name/scan","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"assets-scan-create","OperationID":"post_ai_assets_scan","Summary":"Scan (asset)","Description":"","Method":"POST","Path":"/v1/ai/assets/scan","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"assets-update","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.","Method":"PATCH","Path":"/v1/ai/assets/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"assets-update","OperationID":"put_ai_assets_by_owner_by_name","Summary":"Replace a asset","Description":"Identical to PATCH — the handler takes a whole object either way.","Method":"PUT","Path":"/v1/ai/assets/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"chat","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.","Method":"POST","Path":"/v1/ai/mcp/chat","Args":[],"Flags":[{"Name":"max-tokens","Field":"max_tokens","Type":"integer","Help":"MaxTokens bounds the answer in tokens; 0 leaves it to the model.","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"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.","Required":false},{"Name":"prompt","Field":"prompt","Type":"string","Help":"Prompt is what to ask.","Required":false},{"Name":"system","Field":"system","Type":"string","Help":"System is the system message ahead of the prompt, when set.","Required":false}],"Example":null},{"Service":"ai","Name":"chats-create","OperationID":"post_ai_chats","Summary":"Create a chat","Description":"Create one chat.","Method":"POST","Path":"/v1/ai/chats","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"chats-delete","OperationID":"delete_ai_chats_by_owner_by_name","Summary":"Delete a chat","Description":"Delete one chat.","Method":"DELETE","Path":"/v1/ai/chats/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"chats-get","OperationID":"get_ai_chats_by_owner_by_name","Summary":"Retrieve a chat","Description":"Read one chat by its (owner, name) key.","Method":"GET","Path":"/v1/ai/chats/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"chats-global-get","OperationID":"get_ai_chats_global","Summary":"List chats across tenants","Description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","Method":"GET","Path":"/v1/ai/chats/global","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"chats-list","OperationID":"get_ai_chats","Summary":"List chats","Description":"List the caller's chats.","Method":"GET","Path":"/v1/ai/chats","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"chats-update","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.","Method":"PATCH","Path":"/v1/ai/chats/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"chats-update","OperationID":"put_ai_chats_by_owner_by_name","Summary":"Replace a chat","Description":"Identical to PATCH — the handler takes a whole object either way.","Method":"PUT","Path":"/v1/ai/chats/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"connections-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.","Method":"GET","Path":"/v1/ai/connections/:provider/authorize","Args":[{"Name":"provider","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"connections-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.","Method":"GET","Path":"/v1/ai/connections/:provider/callback","Args":[{"Name":"provider","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"connections-create","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.","Method":"POST","Path":"/v1/ai/connections","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"connections-create","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.","Method":"POST","Path":"/v1/ai/connections/:provider","Args":[{"Name":"provider","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"connections-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.","Method":"DELETE","Path":"/v1/ai/connections/:provider","Args":[{"Name":"provider","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"connections-list","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.","Method":"GET","Path":"/v1/ai/connections","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"connections-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.","Method":"GET","Path":"/v1/ai/connections/:provider/usage","Args":[{"Name":"provider","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"dashboards-agents-list","OperationID":"get_ai_dashboards_agents","Summary":"Dashboards Agents","Description":"","Method":"GET","Path":"/v1/ai/dashboards/agents","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"dashboards-vm-get","OperationID":"get_ai_dashboards_vm","Summary":"Dashboards Vm","Description":"","Method":"GET","Path":"/v1/ai/dashboards/vm","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"decide","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.","Method":"POST","Path":"/v1/ai/mcp/decisions","Args":[],"Flags":[{"Name":"handle","Field":"handle","Type":"string","Help":"Handle decides over a state this org observed earlier, in place of State and\nQuestions.","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"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).","Required":false},{"Name":"observe","Field":"observe","Type":"string","Help":"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.","Required":false},{"Name":"questions","Field":"questions","Type":"json","Help":"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.","Required":false},{"Name":"state","Field":"state","Type":"json","Help":"State is what the questions are about: a string, an object or an array, kept\nas written. Not sent with a Handle.","Required":false}],"Example":null},{"Service":"ai","Name":"deployments-create","OperationID":"post_ai_deployments","Summary":"Create a application","Description":"Create one application.","Method":"POST","Path":"/v1/ai/deployments","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"deployments-delete","OperationID":"delete_ai_deployments_by_owner_by_name","Summary":"Delete a application","Description":"Delete one application.","Method":"DELETE","Path":"/v1/ai/deployments/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"deployments-deploy","OperationID":"post_ai_deployments_by_owner_by_name_deploy","Summary":"Deploy (application)","Description":"","Method":"POST","Path":"/v1/ai/deployments/:owner/:name/deploy","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"deployments-get","OperationID":"get_ai_deployments_by_owner_by_name","Summary":"Retrieve a application","Description":"Read one application by its (owner, name) key.","Method":"GET","Path":"/v1/ai/deployments/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"deployments-list","OperationID":"get_ai_deployments","Summary":"List deployments","Description":"List the caller's deployments.","Method":"GET","Path":"/v1/ai/deployments","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"deployments-undeploy","OperationID":"post_ai_deployments_by_owner_by_name_undeploy","Summary":"Undeploy (application)","Description":"","Method":"POST","Path":"/v1/ai/deployments/:owner/:name/undeploy","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"deployments-update","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.","Method":"PATCH","Path":"/v1/ai/deployments/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"deployments-update","OperationID":"put_ai_deployments_by_owner_by_name","Summary":"Replace a application","Description":"Identical to PATCH — the handler takes a whole object either way.","Method":"PUT","Path":"/v1/ai/deployments/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"feedback-create","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}.","Method":"POST","Path":"/v1/ai/feedback","Args":[],"Flags":[{"Name":"rating","Field":"rating","Type":"number","Help":"","Required":false},{"Name":"request-id","Field":"request_id","Type":"string","Help":"","Required":true},{"Name":"reward","Field":"reward","Type":"number","Help":"","Required":false},{"Name":"signal","Field":"signal","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"ai","Name":"files-activate-create","OperationID":"post_ai_files_activate","Summary":"Activate (file)","Description":"","Method":"POST","Path":"/v1/ai/files/activate","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"files-active-get","OperationID":"get_ai_files_active","Summary":"Active (file)","Description":"","Method":"GET","Path":"/v1/ai/files/active","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"files-create","OperationID":"post_ai_files","Summary":"Create a file","Description":"Create one file.","Method":"POST","Path":"/v1/ai/files","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"files-delete","OperationID":"delete_ai_files_by_owner_by_name","Summary":"Delete a file","Description":"Delete one file.","Method":"DELETE","Path":"/v1/ai/files/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"files-get","OperationID":"get_ai_files_by_owner_by_name","Summary":"Retrieve a file","Description":"Read one file by its (owner, name) key.","Method":"GET","Path":"/v1/ai/files/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"files-global-get","OperationID":"get_ai_files_global","Summary":"List files across tenants","Description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","Method":"GET","Path":"/v1/ai/files/global","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"files-list","OperationID":"get_ai_files","Summary":"List files","Description":"List the caller's files.","Method":"GET","Path":"/v1/ai/files","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"files-update","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.","Method":"PATCH","Path":"/v1/ai/files/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"files-update","OperationID":"put_ai_files_by_owner_by_name","Summary":"Replace a file","Description":"Identical to PATCH — the handler takes a whole object either way.","Method":"PUT","Path":"/v1/ai/files/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"files-upload-create","OperationID":"post_ai_files_upload","Summary":"Upload (file)","Description":"","Method":"POST","Path":"/v1/ai/files/upload","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"files-vectors","OperationID":"post_ai_files_by_owner_by_name_vectors","Summary":"Vectors (file)","Description":"","Method":"POST","Path":"/v1/ai/files/:owner/:name/vectors","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"finetune-cancel-create","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=","Method":"POST","Path":"/v1/ai/finetune/cancel","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"finetune-deploy-create","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=","Method":"POST","Path":"/v1/ai/finetune/deploy","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"finetune-hf-datasets-list","OperationID":"get_ai_finetune_hf_datasets","Summary":"Proxies a HuggingFace dataset search (dataset picker).","Description":"Proxies a HuggingFace dataset search (dataset picker).","Method":"GET","Path":"/v1/ai/finetune/hf/datasets","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"finetune-hf-models-list","OperationID":"get_ai_finetune_hf_models","Summary":"Proxies a HuggingFace model search (base-model picker).","Description":"Proxies a HuggingFace model search (base-model picker).","Method":"GET","Path":"/v1/ai/finetune/hf/models","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"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","Method":"GET","Path":"/v1/ai/finetune/hf/repo","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"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=","Method":"GET","Path":"/v1/ai/finetune/job","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"finetune-jobs-create","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.","Method":"POST","Path":"/v1/ai/finetune/jobs","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"finetune-jobs-list","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.","Method":"GET","Path":"/v1/ai/finetune/jobs","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"finetune-presets-list","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.","Method":"GET","Path":"/v1/ai/finetune/presets","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"forms-create","OperationID":"post_ai_forms","Summary":"Create a form","Description":"Create one form.","Method":"POST","Path":"/v1/ai/forms","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"forms-data-get","OperationID":"get_ai_forms_data","Summary":"Data (form)","Description":"","Method":"GET","Path":"/v1/ai/forms/data","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"forms-delete","OperationID":"delete_ai_forms_by_owner_by_name","Summary":"Delete a form","Description":"Delete one form.","Method":"DELETE","Path":"/v1/ai/forms/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"forms-get","OperationID":"get_ai_forms_by_owner_by_name","Summary":"Retrieve a form","Description":"Read one form by its (owner, name) key.","Method":"GET","Path":"/v1/ai/forms/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"forms-global-get","OperationID":"get_ai_forms_global","Summary":"List forms across tenants","Description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","Method":"GET","Path":"/v1/ai/forms/global","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"forms-list","OperationID":"get_ai_forms","Summary":"List forms","Description":"List the caller's forms.","Method":"GET","Path":"/v1/ai/forms","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"forms-update","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.","Method":"PATCH","Path":"/v1/ai/forms/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"forms-update","OperationID":"put_ai_forms_by_owner_by_name","Summary":"Replace a form","Description":"Identical to PATCH — the handler takes a whole object either way.","Method":"PUT","Path":"/v1/ai/forms/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"graphs-create","OperationID":"post_ai_graphs","Summary":"Create a graph","Description":"Create one graph.","Method":"POST","Path":"/v1/ai/graphs","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"graphs-delete","OperationID":"delete_ai_graphs_by_owner_by_name","Summary":"Delete a graph","Description":"Delete one graph.","Method":"DELETE","Path":"/v1/ai/graphs/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"graphs-get","OperationID":"get_ai_graphs_by_owner_by_name","Summary":"Retrieve a graph","Description":"Read one graph by its (owner, name) key.","Method":"GET","Path":"/v1/ai/graphs/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"graphs-global-get","OperationID":"get_ai_graphs_global","Summary":"List graphs across tenants","Description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","Method":"GET","Path":"/v1/ai/graphs/global","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"graphs-list","OperationID":"get_ai_graphs","Summary":"List graphs","Description":"List the caller's graphs.","Method":"GET","Path":"/v1/ai/graphs","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"graphs-update","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.","Method":"PATCH","Path":"/v1/ai/graphs/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"graphs-update","OperationID":"put_ai_graphs_by_owner_by_name","Summary":"Replace a graph","Description":"Identical to PATCH — the handler takes a whole object either way.","Method":"PUT","Path":"/v1/ai/graphs/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"k8s-status-get","OperationID":"get_ai_k8s-status","Summary":"K8s Status","Description":"","Method":"GET","Path":"/v1/ai/k8s-status","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"limits","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.","Method":"GET","Path":"/v1/ai/limits","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"mcp-tools","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.","Method":"GET","Path":"/v1/ai/mcp/tools","Args":[],"Flags":[{"Name":"names","Field":"names","Type":"boolean","Help":"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.","Required":false}],"Example":null},{"Service":"ai","Name":"memory-delete-create","OperationID":"post_ai_memory_delete","Summary":"Delete one of the authenticated user's memories","Description":"Delete one of the authenticated user's memories","Method":"POST","Path":"/v1/ai/memory/delete","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"memory-facts-list","OperationID":"get_ai_memory_facts","Summary":"List the authenticated user's stored facts","Description":"List the authenticated user's stored facts","Method":"GET","Path":"/v1/ai/memory/facts","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"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","Method":"GET","Path":"/v1/ai/memory/list","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"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","Method":"GET","Path":"/v1/ai/memory/recall","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"memory-remember-create","OperationID":"post_ai_memory_remember","Summary":"Store a memory for the authenticated user","Description":"Store a memory for the authenticated user","Method":"POST","Path":"/v1/ai/memory/remember","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"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)","Method":"GET","Path":"/v1/ai/memory/search","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"memory-update-create","OperationID":"post_ai_memory_update","Summary":"Update one of the authenticated user's memories","Description":"Update one of the authenticated user's memories","Method":"POST","Path":"/v1/ai/memory/update","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"messages-answer-get","OperationID":"get_ai_messages_by_owner_by_name_answer","Summary":"Answer (message)","Description":"","Method":"GET","Path":"/v1/ai/messages/:owner/:name/answer","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"messages-create","OperationID":"post_ai_messages","Summary":"Create a message","Description":"Create one message.","Method":"POST","Path":"/v1/ai/messages","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"messages-delete","OperationID":"delete_ai_messages_by_owner_by_name","Summary":"Delete a message","Description":"Delete one message.","Method":"DELETE","Path":"/v1/ai/messages/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"messages-get","OperationID":"get_ai_messages_by_owner_by_name","Summary":"Retrieve a message","Description":"Read one message by its (owner, name) key.","Method":"GET","Path":"/v1/ai/messages/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"messages-list","OperationID":"get_ai_messages","Summary":"List messages","Description":"List the caller's messages.","Method":"GET","Path":"/v1/ai/messages","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"messages-update","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.","Method":"PATCH","Path":"/v1/ai/messages/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"messages-update","OperationID":"put_ai_messages_by_owner_by_name","Summary":"Replace a message","Description":"Identical to PATCH — the handler takes a whole object either way.","Method":"PUT","Path":"/v1/ai/messages/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"messages-welcome-delete","OperationID":"delete_ai_messages_welcome","Summary":"Welcome (message)","Description":"","Method":"DELETE","Path":"/v1/ai/messages/welcome","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"models","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.","Method":"GET","Path":"/v1/ai/mcp/models","Args":[],"Flags":[{"Name":"q","Field":"q","Type":"string","Help":"Q matches the model's id, name, description or owner, ignoring case.","Required":false},{"Name":"class","Field":"class","Type":"string","Help":"Class keeps one class: premium (third-party frontier models), ours (Hanzo's\npriced models) or free.","Required":false},{"Name":"family","Field":"family","Type":"string","Help":"Family keeps one Hanzo family: enso, zen, kai or zoo.","Required":false},{"Name":"capability","Field":"capability","Type":"string","Help":"Capability keeps the models that have it: tools, vision or reasoning, or a\nmodality they take or give (text, image, audio, file, video, decision).","Required":false},{"Name":"free","Field":"free","Type":"boolean","Help":"Free keeps the models a call to which bills nothing (bounded by the free\nallowances instead of a balance).","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit is the most models to answer, 1 to 500; 0 answers 50.","Required":false}],"Example":null},{"Service":"ai","Name":"nodes-create","OperationID":"post_ai_nodes","Summary":"Create a node","Description":"Create one node.","Method":"POST","Path":"/v1/ai/nodes","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"nodes-delete","OperationID":"delete_ai_nodes_by_owner_by_name","Summary":"Delete a node","Description":"Delete one node.","Method":"DELETE","Path":"/v1/ai/nodes/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"nodes-get","OperationID":"get_ai_nodes_by_owner_by_name","Summary":"Retrieve a node","Description":"Read one node by its (owner, name) key.","Method":"GET","Path":"/v1/ai/nodes/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"nodes-list","OperationID":"get_ai_nodes","Summary":"List nodes","Description":"List the caller's nodes.","Method":"GET","Path":"/v1/ai/nodes","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"nodes-tunnel","OperationID":"post_ai_nodes_by_owner_by_name_tunnel","Summary":"Tunnel (node)","Description":"","Method":"POST","Path":"/v1/ai/nodes/:owner/:name/tunnel","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"nodes-tunnel-get","OperationID":"get_ai_nodes_by_owner_by_name_tunnel","Summary":"Tunnel (node)","Description":"","Method":"GET","Path":"/v1/ai/nodes/:owner/:name/tunnel","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"nodes-update","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.","Method":"PATCH","Path":"/v1/ai/nodes/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"nodes-update","OperationID":"put_ai_nodes_by_owner_by_name","Summary":"Replace a node","Description":"Identical to PATCH — the handler takes a whole object either way.","Method":"PUT","Path":"/v1/ai/nodes/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"org-settings-create","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.","Method":"POST","Path":"/v1/ai/org/settings","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"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.","Method":"DELETE","Path":"/v1/ai/org/settings","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"org-settings-list","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.","Method":"GET","Path":"/v1/ai/org/settings","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"org-settings-list-create","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.","Method":"POST","Path":"/v1/ai/org/settings/list","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"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.","Method":"DELETE","Path":"/v1/ai/org/settings/list","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"org-settings-list-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.","Method":"GET","Path":"/v1/ai/org/settings/list","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"org-settings-list-update","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.","Method":"PATCH","Path":"/v1/ai/org/settings/list","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"org-settings-list-update","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.","Method":"PUT","Path":"/v1/ai/org/settings/list","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"org-settings-update","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.","Method":"PATCH","Path":"/v1/ai/org/settings","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"org-settings-update","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.","Method":"PUT","Path":"/v1/ai/org/settings","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"preferences-update","OperationID":"patch_ai_preferences","Summary":"Preferences","Description":"","Method":"PATCH","Path":"/v1/ai/preferences","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"preferences-update","OperationID":"put_ai_preferences","Summary":"Preferences","Description":"","Method":"PUT","Path":"/v1/ai/preferences","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"prometheus-get","OperationID":"get_ai_prometheus","Summary":"Prometheus","Description":"","Method":"GET","Path":"/v1/ai/prometheus","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"providers-create","OperationID":"post_ai_providers","Summary":"Create a provider","Description":"Create one provider.","Method":"POST","Path":"/v1/ai/providers","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"providers-delete","OperationID":"delete_ai_providers_by_owner_by_name","Summary":"Delete a provider","Description":"Delete one provider.","Method":"DELETE","Path":"/v1/ai/providers/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"providers-get","OperationID":"get_ai_providers_by_owner_by_name","Summary":"Retrieve a provider","Description":"Read one provider by its (owner, name) key.","Method":"GET","Path":"/v1/ai/providers/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"providers-global-get","OperationID":"get_ai_providers_global","Summary":"List providers across tenants","Description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","Method":"GET","Path":"/v1/ai/providers/global","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"providers-list","OperationID":"get_ai_providers","Summary":"List providers","Description":"List the caller's providers.","Method":"GET","Path":"/v1/ai/providers","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"providers-mcp-tools-create","OperationID":"post_ai_providers_mcp-tools","Summary":"Mcp Tools (provider)","Description":"","Method":"POST","Path":"/v1/ai/providers/mcp-tools","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"providers-update","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.","Method":"PATCH","Path":"/v1/ai/providers/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"providers-update","OperationID":"put_ai_providers_by_owner_by_name","Summary":"Replace a provider","Description":"Identical to PATCH — the handler takes a whole object either way.","Method":"PUT","Path":"/v1/ai/providers/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"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.","Method":"GET","Path":"/v1/ai/rag/context","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"rag-delete-create","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.","Method":"POST","Path":"/v1/ai/rag/delete","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"rag-embed-create","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.","Method":"POST","Path":"/v1/ai/rag/embed","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"rag-ingest-create","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.","Method":"POST","Path":"/v1/ai/rag/ingest","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"rag-query-create","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.","Method":"POST","Path":"/v1/ai/rag/query","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"rag-query-multiple-create","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.","Method":"POST","Path":"/v1/ai/rag/query-multiple","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"records-batch-create","OperationID":"post_ai_records_batch","Summary":"Batch (record)","Description":"","Method":"POST","Path":"/v1/ai/records/batch","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"records-commit-create","OperationID":"post_ai_records_commit","Summary":"Commit (record)","Description":"","Method":"POST","Path":"/v1/ai/records/commit","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"records-commit-second-create","OperationID":"post_ai_records_commit-second","Summary":"Commit Second (record)","Description":"","Method":"POST","Path":"/v1/ai/records/commit-second","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"records-create","OperationID":"post_ai_records","Summary":"Create a record","Description":"Create one record.","Method":"POST","Path":"/v1/ai/records","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"records-delete","OperationID":"delete_ai_records_by_owner_by_name","Summary":"Delete a record","Description":"Delete one record.","Method":"DELETE","Path":"/v1/ai/records/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"records-get","OperationID":"get_ai_records_by_owner_by_name","Summary":"Retrieve a record","Description":"Read one record by its (owner, name) key.","Method":"GET","Path":"/v1/ai/records/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"records-list","OperationID":"get_ai_records","Summary":"List records","Description":"List the caller's records.","Method":"GET","Path":"/v1/ai/records","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"records-query-get","OperationID":"get_ai_records_query","Summary":"Query (record)","Description":"","Method":"GET","Path":"/v1/ai/records/query","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"records-query-second-get","OperationID":"get_ai_records_query-second","Summary":"Query Second (record)","Description":"","Method":"GET","Path":"/v1/ai/records/query-second","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"records-update","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.","Method":"PATCH","Path":"/v1/ai/records/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"records-update","OperationID":"put_ai_records_by_owner_by_name","Summary":"Replace a record","Description":"Identical to PATCH — the handler takes a whole object either way.","Method":"PUT","Path":"/v1/ai/records/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"remote-connections-create","OperationID":"post_ai_remote-connections","Summary":"Create a connection","Description":"Create one connection.","Method":"POST","Path":"/v1/ai/remote-connections","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"remote-connections-delete","OperationID":"delete_ai_remote-connections_by_owner_by_name","Summary":"Delete a connection","Description":"Delete one connection.","Method":"DELETE","Path":"/v1/ai/remote-connections/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"remote-connections-get","OperationID":"get_ai_remote-connections_by_owner_by_name","Summary":"Retrieve a connection","Description":"Read one connection by its (owner, name) key.","Method":"GET","Path":"/v1/ai/remote-connections/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"remote-connections-list","OperationID":"get_ai_remote-connections","Summary":"List remote-connections","Description":"List the caller's remote-connections.","Method":"GET","Path":"/v1/ai/remote-connections","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"remote-connections-start","OperationID":"post_ai_remote-connections_by_owner_by_name_start","Summary":"Start (connection)","Description":"","Method":"POST","Path":"/v1/ai/remote-connections/:owner/:name/start","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"remote-connections-stop","OperationID":"post_ai_remote-connections_by_owner_by_name_stop","Summary":"Stop (connection)","Description":"","Method":"POST","Path":"/v1/ai/remote-connections/:owner/:name/stop","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"remote-connections-update","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.","Method":"PATCH","Path":"/v1/ai/remote-connections/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"remote-connections-update","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.","Method":"PUT","Path":"/v1/ai/remote-connections/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"router-artifact-meta-create","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.","Method":"POST","Path":"/v1/ai/router/artifact-meta","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"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.","Method":"DELETE","Path":"/v1/ai/router/artifact-meta","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-artifact-meta-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.","Method":"GET","Path":"/v1/ai/router/artifact-meta","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-artifact-meta-update","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.","Method":"PATCH","Path":"/v1/ai/router/artifact-meta","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-artifact-meta-update","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.","Method":"PUT","Path":"/v1/ai/router/artifact-meta","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"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.","Method":"GET","Path":"/v1/ai/router/catalog","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-catalog-propose-create","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.","Method":"POST","Path":"/v1/ai/router/catalog/propose","Args":[],"Flags":[{"Name":"base","Field":"base","Type":"integer","Help":"","Required":false},{"Name":"catalog","Field":"catalog","Type":"json","Help":"","Required":false},{"Name":"family","Field":"family","Type":"string","Help":"","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"","Required":false},{"Name":"note","Field":"note","Type":"string","Help":"","Required":false},{"Name":"version","Field":"version","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"ai","Name":"router-catalog-rollback-create","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.","Method":"POST","Path":"/v1/ai/router/catalog/rollback","Args":[],"Flags":[{"Name":"base","Field":"base","Type":"integer","Help":"","Required":false},{"Name":"catalog","Field":"catalog","Type":"json","Help":"","Required":false},{"Name":"family","Field":"family","Type":"string","Help":"","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"","Required":false},{"Name":"note","Field":"note","Type":"string","Help":"","Required":false},{"Name":"version","Field":"version","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"ai","Name":"router-catalog-test-create","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.","Method":"POST","Path":"/v1/ai/router/catalog/test","Args":[],"Flags":[{"Name":"base","Field":"base","Type":"integer","Help":"","Required":false},{"Name":"catalog","Field":"catalog","Type":"json","Help":"","Required":false},{"Name":"family","Field":"family","Type":"string","Help":"","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"","Required":false},{"Name":"note","Field":"note","Type":"string","Help":"","Required":false},{"Name":"version","Field":"version","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"ai","Name":"router-catalog-update","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.","Method":"PUT","Path":"/v1/ai/router/catalog","Args":[],"Flags":[{"Name":"base","Field":"base","Type":"integer","Help":"","Required":false},{"Name":"catalog","Field":"catalog","Type":"json","Help":"","Required":false},{"Name":"family","Field":"family","Type":"string","Help":"","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"","Required":false},{"Name":"note","Field":"note","Type":"string","Help":"","Required":false},{"Name":"version","Field":"version","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"ai","Name":"router-data-delete","OperationID":"delete_ai_router_data","Summary":"Router Data","Description":"","Method":"DELETE","Path":"/v1/ai/router/data","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-data-get","OperationID":"get_ai_router_data","Summary":"Router Data","Description":"","Method":"GET","Path":"/v1/ai/router/data","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-defaults-create","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.","Method":"POST","Path":"/v1/ai/router/defaults","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"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.","Method":"DELETE","Path":"/v1/ai/router/defaults","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-defaults-list","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.","Method":"GET","Path":"/v1/ai/router/defaults","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-defaults-update","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.","Method":"PATCH","Path":"/v1/ai/router/defaults","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-defaults-update","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.","Method":"PUT","Path":"/v1/ai/router/defaults","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"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.","Method":"GET","Path":"/v1/ai/router/history","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"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.","Method":"GET","Path":"/v1/ai/router/judge-panel","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-ledger-create","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.","Method":"POST","Path":"/v1/ai/router/ledger","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"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.","Method":"DELETE","Path":"/v1/ai/router/ledger","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-ledger-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.","Method":"GET","Path":"/v1/ai/router/ledger","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-ledger-update","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.","Method":"PATCH","Path":"/v1/ai/router/ledger","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-ledger-update","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.","Method":"PUT","Path":"/v1/ai/router/ledger","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-policy-create","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.","Method":"POST","Path":"/v1/ai/router/policy","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"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.","Method":"DELETE","Path":"/v1/ai/router/policy","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-policy-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.","Method":"GET","Path":"/v1/ai/router/policy","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-policy-update","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.","Method":"PATCH","Path":"/v1/ai/router/policy","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-policy-update","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.","Method":"PUT","Path":"/v1/ai/router/policy","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-rewards-create","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.","Method":"POST","Path":"/v1/ai/router/rewards","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"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.","Method":"DELETE","Path":"/v1/ai/router/rewards","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-rewards-list","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.","Method":"GET","Path":"/v1/ai/router/rewards","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-rewards-update","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.","Method":"PATCH","Path":"/v1/ai/router/rewards","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-rewards-update","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.","Method":"PUT","Path":"/v1/ai/router/rewards","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"router-stats-list","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.","Method":"GET","Path":"/v1/ai/router/stats","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"routes-create","OperationID":"post_ai_routes","Summary":"Create a model-route","Description":"Create one model-route.","Method":"POST","Path":"/v1/ai/routes","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"routes-delete","OperationID":"delete_ai_routes_by_owner_by_name","Summary":"Delete a model-route","Description":"Delete one model-route.","Method":"DELETE","Path":"/v1/ai/routes/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"routes-get","OperationID":"get_ai_routes_by_owner_by_name","Summary":"Retrieve a model-route","Description":"Read one model-route by its (owner, name) key.","Method":"GET","Path":"/v1/ai/routes/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"routes-list","OperationID":"get_ai_routes","Summary":"List routes","Description":"List the caller's routes.","Method":"GET","Path":"/v1/ai/routes","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"routes-update","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.","Method":"PATCH","Path":"/v1/ai/routes/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"routes-update","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.","Method":"PUT","Path":"/v1/ai/routes/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"scales-create","OperationID":"post_ai_scales","Summary":"Create a scale","Description":"Create one scale.","Method":"POST","Path":"/v1/ai/scales","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"scales-delete","OperationID":"delete_ai_scales_by_owner_by_name","Summary":"Delete a scale","Description":"Delete one scale.","Method":"DELETE","Path":"/v1/ai/scales/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"scales-get","OperationID":"get_ai_scales_by_owner_by_name","Summary":"Retrieve a scale","Description":"Read one scale by its (owner, name) key.","Method":"GET","Path":"/v1/ai/scales/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"scales-global-get","OperationID":"get_ai_scales_global","Summary":"List scales across tenants","Description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","Method":"GET","Path":"/v1/ai/scales/global","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"scales-list","OperationID":"get_ai_scales","Summary":"List scales","Description":"List the caller's scales.","Method":"GET","Path":"/v1/ai/scales","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"scales-public-get","OperationID":"get_ai_scales_public","Summary":"Public (scale)","Description":"","Method":"GET","Path":"/v1/ai/scales/public","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"scales-update","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.","Method":"PATCH","Path":"/v1/ai/scales/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"scales-update","OperationID":"put_ai_scales_by_owner_by_name","Summary":"Replace a scale","Description":"Identical to PATCH — the handler takes a whole object either way.","Method":"PUT","Path":"/v1/ai/scales/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"scans-create","OperationID":"post_ai_scans","Summary":"Create a scan","Description":"Create one scan.","Method":"POST","Path":"/v1/ai/scans","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"scans-delete","OperationID":"delete_ai_scans_by_owner_by_name","Summary":"Delete a scan","Description":"Delete one scan.","Method":"DELETE","Path":"/v1/ai/scans/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"scans-get","OperationID":"get_ai_scans_by_owner_by_name","Summary":"Retrieve a scan","Description":"Read one scan by its (owner, name) key.","Method":"GET","Path":"/v1/ai/scans/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"scans-list","OperationID":"get_ai_scans","Summary":"List scans","Description":"List the caller's scans.","Method":"GET","Path":"/v1/ai/scans","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"scans-update","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.","Method":"PATCH","Path":"/v1/ai/scans/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"scans-update","OperationID":"put_ai_scans_by_owner_by_name","Summary":"Replace a scan","Description":"Identical to PATCH — the handler takes a whole object either way.","Method":"PUT","Path":"/v1/ai/scans/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"set-limits","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.","Method":"PUT","Path":"/v1/ai/limits","Args":[],"Flags":[{"Name":"credits-after-allowance","Field":"creditsAfterAllowance","Type":"boolean","Help":"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.","Required":false}],"Example":null},{"Service":"ai","Name":"signin-create","OperationID":"post_ai_signin","Summary":"Signin","Description":"","Method":"POST","Path":"/v1/ai/signin","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"signin-sessions-create","OperationID":"post_ai_signin-sessions","Summary":"Create a session","Description":"Create one session.","Method":"POST","Path":"/v1/ai/signin-sessions","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"signin-sessions-delete","OperationID":"delete_ai_signin-sessions_by_owner_by_name","Summary":"Delete a session","Description":"Delete one session.","Method":"DELETE","Path":"/v1/ai/signin-sessions/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"signin-sessions-duplicated-get","OperationID":"get_ai_signin-sessions_duplicated","Summary":"Duplicated (session)","Description":"","Method":"GET","Path":"/v1/ai/signin-sessions/duplicated","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"signin-sessions-get","OperationID":"get_ai_signin-sessions_by_owner_by_name","Summary":"Retrieve a session","Description":"Read one session by its (owner, name) key.","Method":"GET","Path":"/v1/ai/signin-sessions/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"signin-sessions-list","OperationID":"get_ai_signin-sessions","Summary":"List signin-sessions","Description":"List the caller's signin-sessions.","Method":"GET","Path":"/v1/ai/signin-sessions","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"signin-sessions-update","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.","Method":"PATCH","Path":"/v1/ai/signin-sessions/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"signin-sessions-update","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.","Method":"PUT","Path":"/v1/ai/signin-sessions/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"signout-create","OperationID":"post_ai_signout","Summary":"Signout","Description":"","Method":"POST","Path":"/v1/ai/signout","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"stores-create","OperationID":"post_ai_stores","Summary":"Create a store","Description":"Create one store.","Method":"POST","Path":"/v1/ai/stores","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"stores-delete","OperationID":"delete_ai_stores_by_owner_by_name","Summary":"Delete a store","Description":"Delete one store.","Method":"DELETE","Path":"/v1/ai/stores/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"stores-get","OperationID":"get_ai_stores_by_owner_by_name","Summary":"Retrieve a store","Description":"Read one store by its (owner, name) key.","Method":"GET","Path":"/v1/ai/stores/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"stores-global-get","OperationID":"get_ai_stores_global","Summary":"List stores across tenants","Description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","Method":"GET","Path":"/v1/ai/stores/global","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"stores-list","OperationID":"get_ai_stores","Summary":"List stores","Description":"List the caller's stores.","Method":"GET","Path":"/v1/ai/stores","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"stores-names-list","OperationID":"get_ai_stores_names","Summary":"Names (store)","Description":"","Method":"GET","Path":"/v1/ai/stores/names","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"stores-providers-list","OperationID":"get_ai_stores_providers","Summary":"Providers (store)","Description":"","Method":"GET","Path":"/v1/ai/stores/providers","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"stores-update","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.","Method":"PATCH","Path":"/v1/ai/stores/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"stores-update","OperationID":"put_ai_stores_by_owner_by_name","Summary":"Replace a store","Description":"Identical to PATCH — the handler takes a whole object either way.","Method":"PUT","Path":"/v1/ai/stores/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"stores-vectors","OperationID":"post_ai_stores_by_owner_by_name_vectors","Summary":"Vectors (store)","Description":"","Method":"POST","Path":"/v1/ai/stores/:owner/:name/vectors","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"system-get","OperationID":"get_ai_system","Summary":"System","Description":"","Method":"GET","Path":"/v1/ai/system","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"tasks-analyze","OperationID":"post_ai_tasks_by_owner_by_name_analyze","Summary":"Analyze (task)","Description":"","Method":"POST","Path":"/v1/ai/tasks/:owner/:name/analyze","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"tasks-create","OperationID":"post_ai_tasks","Summary":"Create a task","Description":"Create one task.","Method":"POST","Path":"/v1/ai/tasks","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"tasks-delete","OperationID":"delete_ai_tasks_by_owner_by_name","Summary":"Delete a task","Description":"Delete one task.","Method":"DELETE","Path":"/v1/ai/tasks/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"tasks-document","OperationID":"post_ai_tasks_by_owner_by_name_document","Summary":"Document (task)","Description":"","Method":"POST","Path":"/v1/ai/tasks/:owner/:name/document","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"tasks-get","OperationID":"get_ai_tasks_by_owner_by_name","Summary":"Retrieve a task","Description":"Read one task by its (owner, name) key.","Method":"GET","Path":"/v1/ai/tasks/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"tasks-global-get","OperationID":"get_ai_tasks_global","Summary":"List tasks across tenants","Description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","Method":"GET","Path":"/v1/ai/tasks/global","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"tasks-list","OperationID":"get_ai_tasks","Summary":"List tasks","Description":"List the caller's tasks.","Method":"GET","Path":"/v1/ai/tasks","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"tasks-update","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.","Method":"PATCH","Path":"/v1/ai/tasks/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"tasks-update","OperationID":"put_ai_tasks_by_owner_by_name","Summary":"Replace a task","Description":"Identical to PATCH — the handler takes a whole object either way.","Method":"PUT","Path":"/v1/ai/tasks/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"templates-create","OperationID":"post_ai_templates","Summary":"Create a template","Description":"Create one template.","Method":"POST","Path":"/v1/ai/templates","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"templates-delete","OperationID":"delete_ai_templates_by_owner_by_name","Summary":"Delete a template","Description":"Delete one template.","Method":"DELETE","Path":"/v1/ai/templates/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"templates-get","OperationID":"get_ai_templates_by_owner_by_name","Summary":"Retrieve a template","Description":"Read one template by its (owner, name) key.","Method":"GET","Path":"/v1/ai/templates/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"templates-list","OperationID":"get_ai_templates","Summary":"List templates","Description":"List the caller's templates.","Method":"GET","Path":"/v1/ai/templates","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"templates-update","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.","Method":"PATCH","Path":"/v1/ai/templates/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"templates-update","OperationID":"put_ai_templates_by_owner_by_name","Summary":"Replace a template","Description":"Identical to PATCH — the handler takes a whole object either way.","Method":"PUT","Path":"/v1/ai/templates/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"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.","Method":"GET","Path":"/v1/ai/traffic/globe","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"training-contribution-get","OperationID":"get_ai_training-contribution","Summary":"Training Contribution","Description":"","Method":"GET","Path":"/v1/ai/training-contribution","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"training-contribution-update","OperationID":"patch_ai_training-contribution","Summary":"Training Contribution","Description":"","Method":"PATCH","Path":"/v1/ai/training-contribution","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"training-contribution-update","OperationID":"put_ai_training-contribution","Summary":"Training Contribution","Description":"","Method":"PUT","Path":"/v1/ai/training-contribution","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"tree-files-create","OperationID":"post_ai_tree-files","Summary":"Create a tree-file","Description":"Create one tree-file.","Method":"POST","Path":"/v1/ai/tree-files","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"tree-files-delete","OperationID":"delete_ai_tree-files_by_owner_by_name","Summary":"Delete a tree-file","Description":"Delete one tree-file.","Method":"DELETE","Path":"/v1/ai/tree-files/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"tree-files-update","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.","Method":"PATCH","Path":"/v1/ai/tree-files/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"tree-files-update","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.","Method":"PUT","Path":"/v1/ai/tree-files/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"usages-by-user-get","OperationID":"get_ai_usages_by-user","Summary":"By User (usage)","Description":"","Method":"GET","Path":"/v1/ai/usages/by-user","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"usages-cloud-get","OperationID":"get_ai_usages_cloud","Summary":"Cloud (usage)","Description":"","Method":"GET","Path":"/v1/ai/usages/cloud","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"usages-list","OperationID":"get_ai_usages","Summary":"List usages","Description":"List the caller's usages.","Method":"GET","Path":"/v1/ai/usages","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"usages-range-get","OperationID":"get_ai_usages_range","Summary":"Range (usage)","Description":"","Method":"GET","Path":"/v1/ai/usages/range","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"usages-user-names-list","OperationID":"get_ai_usages_user-names","Summary":"User Names (usage)","Description":"","Method":"GET","Path":"/v1/ai/usages/user-names","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"vectors-all-delete","OperationID":"delete_ai_vectors_all","Summary":"All (vector)","Description":"","Method":"DELETE","Path":"/v1/ai/vectors/all","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"vectors-create","OperationID":"post_ai_vectors","Summary":"Create a vector","Description":"Create one vector.","Method":"POST","Path":"/v1/ai/vectors","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"vectors-delete","OperationID":"delete_ai_vectors_by_owner_by_name","Summary":"Delete a vector","Description":"Delete one vector.","Method":"DELETE","Path":"/v1/ai/vectors/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"vectors-get","OperationID":"get_ai_vectors_by_owner_by_name","Summary":"Retrieve a vector","Description":"Read one vector by its (owner, name) key.","Method":"GET","Path":"/v1/ai/vectors/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"vectors-global-get","OperationID":"get_ai_vectors_global","Summary":"List vectors across tenants","Description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","Method":"GET","Path":"/v1/ai/vectors/global","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"vectors-list","OperationID":"get_ai_vectors","Summary":"List vectors","Description":"List the caller's vectors.","Method":"GET","Path":"/v1/ai/vectors","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"vectors-update","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.","Method":"PATCH","Path":"/v1/ai/vectors/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"vectors-update","OperationID":"put_ai_vectors_by_owner_by_name","Summary":"Replace a vector","Description":"Identical to PATCH — the handler takes a whole object either way.","Method":"PUT","Path":"/v1/ai/vectors/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"version-get","OperationID":"get_ai_version","Summary":"Version","Description":"","Method":"GET","Path":"/v1/ai/version","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"videos-create","OperationID":"post_ai_videos","Summary":"Create a video","Description":"Create one video.","Method":"POST","Path":"/v1/ai/videos","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"videos-delete","OperationID":"delete_ai_videos_by_owner_by_name","Summary":"Delete a video","Description":"Delete one video.","Method":"DELETE","Path":"/v1/ai/videos/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"videos-get","OperationID":"get_ai_videos_by_owner_by_name","Summary":"Retrieve a video","Description":"Read one video by its (owner, name) key.","Method":"GET","Path":"/v1/ai/videos/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"videos-global-get","OperationID":"get_ai_videos_global","Summary":"List videos across tenants","Description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","Method":"GET","Path":"/v1/ai/videos/global","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"videos-list","OperationID":"get_ai_videos","Summary":"List videos","Description":"List the caller's videos.","Method":"GET","Path":"/v1/ai/videos","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"videos-update","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.","Method":"PATCH","Path":"/v1/ai/videos/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"videos-update","OperationID":"put_ai_videos_by_owner_by_name","Summary":"Replace a video","Description":"Identical to PATCH — the handler takes a whole object either way.","Method":"PUT","Path":"/v1/ai/videos/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"videos-upload-create","OperationID":"post_ai_videos_upload","Summary":"Upload (video)","Description":"","Method":"POST","Path":"/v1/ai/videos/upload","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"workflows-create","OperationID":"post_ai_workflows","Summary":"Create a workflow","Description":"Create one workflow.","Method":"POST","Path":"/v1/ai/workflows","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"workflows-delete","OperationID":"delete_ai_workflows_by_owner_by_name","Summary":"Delete a workflow","Description":"Delete one workflow.","Method":"DELETE","Path":"/v1/ai/workflows/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"workflows-get","OperationID":"get_ai_workflows_by_owner_by_name","Summary":"Retrieve a workflow","Description":"Read one workflow by its (owner, name) key.","Method":"GET","Path":"/v1/ai/workflows/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"workflows-global-get","OperationID":"get_ai_workflows_global","Summary":"List workflows across tenants","Description":"Cross-tenant listing. Admin-only; a tenant caller is refused.","Method":"GET","Path":"/v1/ai/workflows/global","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"workflows-list","OperationID":"get_ai_workflows","Summary":"List workflows","Description":"List the caller's workflows.","Method":"GET","Path":"/v1/ai/workflows","Args":[],"Flags":null,"Example":null},{"Service":"ai","Name":"workflows-update","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.","Method":"PATCH","Path":"/v1/ai/workflows/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ai","Name":"workflows-update","OperationID":"put_ai_workflows_by_owner_by_name","Summary":"Replace a workflow","Description":"Identical to PATCH — the handler takes a whole object either way.","Method":"PUT","Path":"/v1/ai/workflows/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"allowance","Name":"list","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.","Method":"GET","Path":"/v1/allowance","Args":[],"Flags":null,"Example":null},{"Service":"ask","Name":"create","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.","Method":"POST","Path":"/v1/ask","Args":[],"Flags":[{"Name":"follow-ups","Field":"followUps","Type":"boolean","Help":"","Required":false},{"Name":"language","Field":"language","Type":"string","Help":"","Required":false},{"Name":"max-queries","Field":"maxQueries","Type":"integer","Help":"","Required":false},{"Name":"max-sources","Field":"maxSources","Type":"integer","Help":"","Required":false},{"Name":"mode","Field":"mode","Type":"string","Help":"","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"","Required":false},{"Name":"q","Field":"q","Type":"string","Help":"","Required":false},{"Name":"question","Field":"question","Type":"string","Help":"","Required":false},{"Name":"sources","Field":"sources","Type":"json","Help":"","Required":false},{"Name":"stream","Field":"stream","Type":"boolean","Help":"","Required":false},{"Name":"system","Field":"system","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"ask","Name":"research-web","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.","Method":"POST","Path":"/v1/ask/web","Args":[],"Flags":[{"Name":"language","Field":"language","Type":"string","Help":"Language narrows the search to a locale, BCP-47-ish (\"en\", \"ja\"). Empty\nmeans no narrowing.","Required":false},{"Name":"max-sources","Field":"max_sources","Type":"integer","Help":"MaxSources caps how many pages are read. Empty means the mode's own budget.","Required":false},{"Name":"mode","Field":"mode","Type":"string","Help":"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.","Required":false},{"Name":"q","Field":"q","Type":"string","Help":"Q is the question, in plain language. Required.","Required":false},{"Name":"sources","Field":"sources","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"audio","Name":"foley-create","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.","Method":"POST","Path":"/v1/audio/foley","Args":[],"Flags":null,"Example":null},{"Service":"audio","Name":"music-create","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.","Method":"POST","Path":"/v1/audio/music","Args":[],"Flags":null,"Example":null},{"Service":"audio","Name":"speech-create","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.","Method":"POST","Path":"/v1/audio/speech","Args":[],"Flags":null,"Example":null},{"Service":"audio","Name":"transcript-create","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.","Method":"POST","Path":"/v1/audio/transcript","Args":[],"Flags":null,"Example":null},{"Service":"audio","Name":"transcript-create","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.","Method":"POST","Path":"/v1/audio/transcript/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"audio","Name":"transcript-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.","Method":"DELETE","Path":"/v1/audio/transcript/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"audio","Name":"transcriptions-create","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.","Method":"POST","Path":"/v1/audio/transcriptions","Args":[],"Flags":null,"Example":null},{"Service":"audio","Name":"transcriptions-public-create","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.","Method":"POST","Path":"/v1/audio/transcriptions/public","Args":[],"Flags":null,"Example":null},{"Service":"audio","Name":"voice-create","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.","Method":"POST","Path":"/v1/audio/voice","Args":[],"Flags":null,"Example":null},{"Service":"audit","Name":"list","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.","Method":"GET","Path":"/v1/audit","Args":[],"Flags":[{"Name":"sub","Field":"sub","Type":"string","Help":"Sub narrows the trail to one actor — the validated subject that made the\nrequest. Blank means every actor in the org.","Required":false},{"Name":"action","Field":"action","Type":"string","Help":"Action narrows it to one action name, e.g. \"machine.create\".","Required":false},{"Name":"resource","Field":"resource","Type":"string","Help":"Resource narrows it to one resource TYPE, e.g. \"apikey\".","Required":false},{"Name":"resource-id","Field":"resourceId","Type":"string","Help":"ResourceID narrows it to one resource instance.","Required":false},{"Name":"result","Field":"result","Type":"string","Help":"Result narrows it to one outcome: \"success\", \"deny\" or \"error\".","Required":false},{"Name":"since","Field":"since","Type":"string","Help":"Since is the inclusive lower time bound, RFC3339. An unparseable value is\nignored rather than refused — one malformed filter must not hide the trail.","Required":false},{"Name":"until","Field":"until","Type":"string","Help":"Until is the upper time bound, RFC3339, with the same tolerance.","Required":false},{"Name":"page-size","Field":"pageSize","Type":"string","Help":"PageSize is rows per page, default 100. A value that is not a positive\ninteger falls back to the default.","Required":false},{"Name":"p","Field":"p","Type":"string","Help":"Page is the 1-based page number, driving the offset. Anything below 2 reads\nthe first page.","Required":false}],"Example":{"action":"machine.create","pageSize":"50","result":"success","since":"2026-07-01T00:00:00Z"}},{"Service":"author","Name":"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.","Method":"GET","Path":"/v1/author/basis","Args":[],"Flags":[{"Name":"period","Field":"period","Type":"string","Help":"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.","Required":false}],"Example":{"period":"2026-07"}},{"Service":"author","Name":"connect-create","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.","Method":"POST","Path":"/v1/author/connect","Args":[],"Flags":[{"Name":"github-login","Field":"githubLogin","Type":"string","Help":"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.","Required":false},{"Name":"login","Field":"login","Type":"string","Help":"Login is the provider-neutral alias for GithubLogin, preferred when both are\nsent.","Required":false},{"Name":"provider","Field":"provider","Type":"string","Help":"Provider is the forge to enrol with: github (the default) or gitlab.","Required":false}],"Example":{"login":"octocat","provider":"github"}},{"Service":"author","Name":"deploys-record-create","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.","Method":"POST","Path":"/v1/author/deploys/record","Args":[],"Flags":[{"Name":"project","Field":"project","Type":"string","Help":"Project is the deployed project's id. Required.","Required":false},{"Name":"repo-url","Field":"repoUrl","Type":"string","Help":"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.","Required":false}],"Example":{"project":"prj_1f…","repoUrl":"github.com/octocat/hello-world"}},{"Service":"author","Name":"list","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.","Method":"GET","Path":"/v1/author","Args":[],"Flags":null,"Example":null},{"Service":"author","Name":"repos-verify-create","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.","Method":"POST","Path":"/v1/author/repos/verify","Args":[],"Flags":[{"Name":"repo-url","Field":"repoUrl","Type":"string","Help":"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.","Required":false}],"Example":{"repoUrl":"github.com/octocat/hello-world"}},{"Service":"authz","Name":"check-create","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.","Method":"POST","Path":"/v1/authz/check","Args":[],"Flags":null,"Example":null},{"Service":"authz","Name":"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.","Method":"GET","Path":"/v1/authz/health","Args":[],"Flags":null,"Example":null},{"Service":"authz","Name":"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.","Method":"GET","Path":"/v1/authz/readyz","Args":[],"Flags":null,"Example":null},{"Service":"auto","Name":"automations-create","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.","Method":"POST","Path":"/v1/auto/automations","Args":[],"Flags":[{"Name":"enabled","Field":"enabled","Type":"boolean","Help":"Enabled arms its schedule. Absent is true.","Required":false},{"Name":"event","Field":"event","Type":"json","Help":"Event arms a product-outcome trigger; it is mutually exclusive with a timed schedule.","Required":false},{"Name":"instructions","Field":"instructions","Type":"string","Help":"Instructions are what the agent is asked to do each run. Required.","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"Model is the model id to think with. Optional; absent is the default.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is what it is called. Required.","Required":false},{"Name":"notify","Field":"notify","Type":"boolean","Help":"Notify sends a one-line summary when a run ends.","Required":false},{"Name":"permissions","Field":"permissions","Type":"string","Help":"Permissions is auto (works without stopping) or ask (proposes, changes\nnothing). Absent is ask.","Required":false},{"Name":"post-to","Field":"postTo","Type":"json","Help":"PostTo are the connected accounts each run's answer is posted to: x,\nlinkedin, facebook. Absent posts nothing.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project is a Dev project's slug to work in. Optional.","Required":false},{"Name":"schedule","Field":"schedule","Type":"json","Help":"Schedule is when it runs. Absent runs it only on demand.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source is the product it is made in: chat, dev, studio or workflow. Absent\nis dev.","Required":false},{"Name":"target","Field":"target","Type":"string","Help":"Target selects a registered execution target for the coding run.","Required":false}],"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"}}},{"Service":"auto","Name":"automations-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.","Method":"DELETE","Path":"/v1/auto/automations/:id","Args":[{"Name":"id","Help":"ID is the automation, from the path."}],"Flags":null,"Example":{"id":"flow_1"}},{"Service":"auto","Name":"automations-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.","Method":"GET","Path":"/v1/auto/automations/:id","Args":[{"Name":"id","Help":"ID is the automation, from the path."}],"Flags":null,"Example":{"id":"flow_1"}},{"Service":"auto","Name":"automations-list","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).","Method":"GET","Path":"/v1/auto/automations","Args":[],"Flags":[{"Name":"q","Field":"q","Type":"string","Help":"Q keeps the automations whose name or instructions contain it, ignoring case.","Required":false},{"Name":"sort","Field":"sort","Type":"string","Help":"Sort is name, next or updated (the default, newest first).","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source keeps the automations made in one product: chat, dev, studio or workflow.","Required":false}],"Example":null},{"Service":"auto","Name":"automations-review","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.","Method":"POST","Path":"/v1/auto/automations/:id/runs/:run/review","Args":[{"Name":"id","Help":"ID is the automation, and Run its run in review, from the path."},{"Name":"run","Help":""}],"Flags":[{"Name":"post","Field":"post","Type":"boolean","Help":"Post posts it when true and discards it when false.","Required":false}],"Example":{"id":"flow_1","post":true,"run":"run_1"}},{"Service":"auto","Name":"automations-run","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.","Method":"POST","Path":"/v1/auto/automations/:id/run","Args":[{"Name":"id","Help":"ID is the automation, from the path."}],"Flags":null,"Example":{"id":"flow_1"}},{"Service":"auto","Name":"automations-runs-list","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.","Method":"GET","Path":"/v1/auto/automations/:id/runs","Args":[{"Name":"id","Help":"ID is the automation, from the path."}],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit bounds the page (default 200, maximum 1000).","Required":false}],"Example":{"id":"flow_1"}},{"Service":"auto","Name":"automations-update","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.","Method":"PATCH","Path":"/v1/auto/automations/:id","Args":[{"Name":"id","Help":"ID is the automation, from the path."}],"Flags":[{"Name":"enabled","Field":"enabled","Type":"boolean","Help":"Enabled arms or disarms its schedule.","Required":false},{"Name":"event","Field":"event","Type":"json","Help":"Event replaces the trigger with a product outcome; null clears it.","Required":false},{"Name":"instructions","Field":"instructions","Type":"string","Help":"","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"notify","Field":"notify","Type":"boolean","Help":"","Required":false},{"Name":"permissions","Field":"permissions","Type":"string","Help":"","Required":false},{"Name":"post-to","Field":"postTo","Type":"json","Help":"","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"","Required":false},{"Name":"schedule","Field":"schedule","Type":"json","Help":"","Required":false},{"Name":"target","Field":"target","Type":"string","Help":"Target replaces the registered execution target; null clears it.","Required":false}],"Example":{"id":"flow_1","schedule":{"at":"16:00","day":"fri","kind":"weekly","tz":"Europe/London"}}},{"Service":"auto","Name":"cron-create","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.","Method":"POST","Path":"/v1/auto/cron","Args":[],"Flags":[{"Name":"text","Field":"text","Type":"string","Help":"Text is when it runs, as a person says it: \"every monday at 9am\".","Required":false},{"Name":"tz","Field":"tz","Type":"string","Help":"TZ is the IANA zone the words are read in. Empty is UTC.","Required":false}],"Example":{"text":"every monday at 9am","tz":"America/Los_Angeles"}},{"Service":"auto","Name":"events-list","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.","Method":"GET","Path":"/v1/auto/events","Args":[],"Flags":null,"Example":null,"Stream":"sse"},{"Service":"auto","Name":"flows-create","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.","Method":"POST","Path":"/v1/auto/flows","Args":[],"Flags":[{"Name":"display-name","Field":"displayName","Type":"string","Help":"DisplayName names the flow's initial draft version.","Required":false},{"Name":"external-id","Field":"externalId","Type":"string","Help":"ExternalID is the caller's own id for this flow. Optional.","Required":false},{"Name":"folder-id","Field":"folderId","Type":"string","Help":"FolderID groups the flow in the builder's tree. Optional.","Required":false},{"Name":"trigger","Field":"trigger","Type":"json","Help":"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.","Required":false}],"Example":{"displayName":"Nightly Sync","trigger":{"displayName":"Start","name":"trigger","settings":{"pieceName":"core","triggerName":"manual"},"strategy":"MANUAL","type":"PIECE_TRIGGER"}}},{"Service":"auto","Name":"flows-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.","Method":"DELETE","Path":"/v1/auto/flows/:id","Args":[{"Name":"id","Help":"ID is the flow to act on, from the path."}],"Flags":null,"Example":{"id":"flow_1"}},{"Service":"auto","Name":"flows-disable","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.","Method":"POST","Path":"/v1/auto/flows/:id/disable","Args":[{"Name":"id","Help":"ID is the flow to act on, from the path."}],"Flags":null,"Example":{"id":"flow_1"}},{"Service":"auto","Name":"flows-enable","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.","Method":"POST","Path":"/v1/auto/flows/:id/enable","Args":[{"Name":"id","Help":"ID is the flow to act on, from the path."}],"Flags":null,"Example":{"id":"flow_1"}},{"Service":"auto","Name":"flows-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.","Method":"GET","Path":"/v1/auto/flows/:id","Args":[{"Name":"id","Help":"ID is the flow to act on, from the path."}],"Flags":null,"Example":{"id":"flow_1"}},{"Service":"auto","Name":"flows-list","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.","Method":"GET","Path":"/v1/auto/flows","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit bounds the page (default 200, maximum 1000).","Required":false}],"Example":null},{"Service":"auto","Name":"flows-operations","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.","Method":"POST","Path":"/v1/auto/flows/:id/operations","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"auto","Name":"flows-run","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.","Method":"POST","Path":"/v1/auto/flows/:id/run","Args":[{"Name":"id","Help":"ID is the flow to act on, from the path."}],"Flags":null,"Example":{"id":"flow_1"}},{"Service":"auto","Name":"flows-update","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.","Method":"PATCH","Path":"/v1/auto/flows/:id","Args":[{"Name":"id","Help":"ID is the flow to update, from the path."}],"Flags":[{"Name":"external-id","Field":"externalId","Type":"string","Help":"ExternalID sets the caller's own id for this flow.","Required":false},{"Name":"folder-id","Field":"folderId","Type":"string","Help":"FolderID moves the flow in the builder's tree.","Required":false},{"Name":"metadata","Field":"metadata","Type":"json","Help":"Metadata replaces the caller's opaque JSON.","Required":false},{"Name":"published-version-id","Field":"publishedVersionId","Type":"string","Help":"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.","Required":false}],"Example":{"folderId":"ops","id":"flow_1"}},{"Service":"auto","Name":"flows-versions","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.","Method":"POST","Path":"/v1/auto/flows/:id/versions","Args":[{"Name":"id","Help":"ID is the flow to add a version to, from the path."}],"Flags":[{"Name":"display-name","Field":"displayName","Type":"string","Help":"DisplayName names the new version.","Required":false},{"Name":"trigger","Field":"trigger","Type":"json","Help":"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.","Required":false}],"Example":{"displayName":"v2","id":"flow_1"}},{"Service":"auto","Name":"flows-versions-list","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.","Method":"GET","Path":"/v1/auto/flows/:id/versions","Args":[{"Name":"id","Help":"ID is the flow whose versions to list, from the path."}],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit bounds the page (default 200, maximum 1000).","Required":false}],"Example":{"id":"flow_1"}},{"Service":"auto","Name":"hooks-create","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.","Method":"POST","Path":"/v1/auto/hooks/:source/:event","Args":[{"Name":"source","Help":""},{"Name":"event","Help":""}],"Flags":null,"Example":null},{"Service":"auto","Name":"jobs-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.","Method":"GET","Path":"/v1/auto/jobs/:id","Args":[{"Name":"id","Help":"ID is the job, from the path: a run_ or a job_ id."}],"Flags":null,"Example":{"id":"run_3f7a…"}},{"Service":"auto","Name":"jobs-list","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.","Method":"GET","Path":"/v1/auto/jobs","Args":[],"Flags":[{"Name":"product","Field":"product","Type":"string","Help":"Product keeps one product's jobs: chat, dev, studio or workflow.","Required":false},{"Name":"state","Field":"state","Type":"string","Help":"State keeps one state: scheduled, running, succeeded, failed or cancelled.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit bounds the page (default 100, at most 500).","Required":false}],"Example":{"product":"studio","state":"running"}},{"Service":"auto","Name":"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.","Method":"GET","Path":"/v1/auto/provider","Args":[],"Flags":null,"Example":null},{"Service":"auto","Name":"provider-run","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.","Method":"POST","Path":"/v1/auto/provider/:id/run","Args":[{"Name":"id","Help":"ID is the provider to run, from the path."}],"Flags":[{"Name":"action","Field":"action","Type":"string","Help":"Action is the name of the provider action to invoke.","Required":false},{"Name":"auth","Field":"auth","Type":"json","Help":"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.","Required":false},{"Name":"props","Field":"props","Type":"json","Help":"Props are the action's input properties, keyed by property name.","Required":false}],"Example":{"action":"create_page","auth":"secret-token","id":"notion","props":{"title":"Hello"}}},{"Service":"auto","Name":"runs-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.","Method":"GET","Path":"/v1/auto/runs/:id","Args":[{"Name":"id","Help":"ID is the run to read, from the path."}],"Flags":null,"Example":{"id":"run_1"}},{"Service":"auto","Name":"runs-list","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.","Method":"GET","Path":"/v1/auto/runs","Args":[],"Flags":[{"Name":"flow-id","Field":"flowId","Type":"string","Help":"FlowID narrows the history to one flow. Omit it for the whole org's runs.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit bounds the page (default 200, maximum 1000).","Required":false}],"Example":null},{"Service":"auto","Name":"runs-resume","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`.","Method":"POST","Path":"/v1/auto/runs/:id/resume","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"auto","Name":"templates-list","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.","Method":"GET","Path":"/v1/auto/templates","Args":[],"Flags":null,"Example":null},{"Service":"base","Name":"bases-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.","Method":"GET","Path":"/v1/base/bases/:org","Args":[{"Name":"org","Help":"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."}],"Flags":null,"Example":null},{"Service":"base","Name":"bases-list","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.","Method":"GET","Path":"/v1/base/bases","Args":[],"Flags":null,"Example":null},{"Service":"base","Name":"graphql-create","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.","Method":"POST","Path":"/v1/base/graphql","Args":[],"Flags":null,"Example":null},{"Service":"base","Name":"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`.","Method":"GET","Path":"/v1/base/graphql","Args":[],"Flags":null,"Example":null},{"Service":"base","Name":"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.","Method":"GET","Path":"/v1/base/health","Args":[],"Flags":null,"Example":null},{"Service":"benchmark","Name":"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.","Method":"GET","Path":"/v1/benchmark/catalog","Args":[],"Flags":null,"Example":null},{"Service":"benchmark","Name":"claims-create","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.","Method":"POST","Path":"/v1/benchmark/claims","Args":[],"Flags":[{"Name":"data","Field":"data","Type":"json","Help":"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.","Required":false},{"Name":"visibility","Field":"visibility","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"benchmark","Name":"claims-list","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.","Method":"GET","Path":"/v1/benchmark/claims","Args":[],"Flags":[{"Name":"benchmark","Field":"Benchmark","Type":"string","Help":"Benchmark filters to one benchmark id. Empty returns every benchmark.","Required":false},{"Name":"model","Field":"Model","Type":"string","Help":"Model filters to one model. Empty returns every model.","Required":false},{"Name":"provider","Field":"Provider","Type":"string","Help":"Provider filters to one lab or leaderboard — the way to read what a single\nsource claims across every model it covers.","Required":false},{"Name":"source","Field":"Source","Type":"string","Help":"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.","Required":false},{"Name":"protocol","Field":"Protocol","Type":"string","Help":"Protocol filters by HOW a claim was scored, so provider cards can be read\napart from third parties running their own harness.","Required":false},{"Name":"org","Field":"Org","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"benchmark","Name":"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.","Method":"GET","Path":"/v1/benchmark/compare","Args":[],"Flags":[{"Name":"benchmark","Field":"benchmark","Type":"string","Help":"Benchmark is the catalog id to compare on, defaulting to gpqa_diamond.","Required":false},{"Name":"a","Field":"a","Type":"string","Help":"A is the first model id. It is required.","Required":true},{"Name":"b","Field":"b","Type":"string","Help":"B is the second model id. It is required.","Required":true}],"Example":null},{"Service":"benchmark","Name":"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.","Method":"GET","Path":"/v1/benchmark/history","Args":[],"Flags":[{"Name":"benchmark","Field":"Benchmark","Type":"string","Help":"Benchmark is the catalog id to read, defaulting to gpqa_diamond.","Required":false},{"Name":"model","Field":"Model","Type":"string","Help":"Model filters to one model. Empty returns every model measured.","Required":false}],"Example":null},{"Service":"benchmark","Name":"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.","Method":"GET","Path":"/v1/benchmark/leaderboard","Args":[],"Flags":[{"Name":"benchmark","Field":"benchmark","Type":"string","Help":"Benchmark is the catalog id to read, defaulting to gpqa_diamond.","Required":false}],"Example":null},{"Service":"benchmark","Name":"presets-create","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.","Method":"POST","Path":"/v1/benchmark/presets","Args":[],"Flags":[{"Name":"arms","Field":"arms","Type":"json","Help":"the blend — model ids from the arena","Required":false},{"Name":"at","Field":"at","Type":"string","Help":"At is when this version was stored. Set by the server; a value sent is not\nread. Zero on the reference blend.","Required":false},{"Name":"by","Field":"by","Type":"string","Help":"By is the verified user who stored it. Set by the server; a value sent is\nnot read.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"the part after enso-: lowercase letters, digits and inner hyphens, at most 64","Required":false},{"Name":"note","Field":"note","Type":"string","Help":"why this blend (audit)","Required":false},{"Name":"owner","Field":"owner","Type":"string","Help":"the org the blend belongs to: the writer's verified org, never a value sent","Required":false},{"Name":"panel","Field":"panel","Type":"integer","Help":"fan-out width (\u003e=1)","Required":false},{"Name":"rank","Field":"rank","Type":"json","Help":"escalation order over arms","Required":false}],"Example":{"arms":["enso-ultra","zen5-pro"],"name":"research","panel":2}},{"Service":"benchmark","Name":"presets-list","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.","Method":"GET","Path":"/v1/benchmark/presets","Args":[],"Flags":null,"Example":null},{"Service":"benchmark","Name":"runs-create","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.","Method":"POST","Path":"/v1/benchmark/runs","Args":[],"Flags":[{"Name":"benchmarks","Field":"benchmarks","Type":"json","Help":"Benchmarks are the catalog ids to ask about. At least one is required, and\nevery id must be in the catalog.","Required":true},{"Name":"model","Field":"model","Type":"string","Help":"Model is the model to ask about, by the id its attempts are stored under.\nRequired.","Required":false}],"Example":{"benchmarks":["gpqa_diamond"],"model":"grok-4.5"}},{"Service":"billing","Name":"accounts-list","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.","Method":"GET","Path":"/v1/billing/accounts","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"accounts-members-list","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.","Method":"GET","Path":"/v1/billing/accounts/:id/members","Args":[{"Name":"id","Help":"ID is the billing account id, which for this store is the org's own id."}],"Flags":null,"Example":null},{"Service":"billing","Name":"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.","Method":"GET","Path":"/v1/billing/alerts/authorize","Args":[],"Flags":[{"Name":"project","Field":"project","Type":"string","Help":"Project narrows the verdict to one project's caps. Empty is the org-wide row.","Required":false},{"Name":"service","Field":"service","Type":"string","Help":"Service narrows it to one service's caps. Empty is every service.","Required":false},{"Name":"amount","Field":"amount","Type":"string","Help":"Amount is the proposed spend in cents.","Required":false},{"Name":"pv","Field":"pv","Type":"string","Help":"PV is \"1\" when the caller ESTABLISHED the project rather than merely\ncarrying a claim of one. An unproven project may not deny traffic.","Required":false}],"Example":null},{"Service":"billing","Name":"alerts-create","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.","Method":"POST","Path":"/v1/billing/alerts","Args":[],"Flags":[{"Name":"currency","Field":"currency","Type":"string","Help":"","Required":false},{"Name":"enforce","Field":"enforce","Type":"boolean","Help":"","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"","Required":false},{"Name":"rate-limit-rpm","Field":"rateLimitRpm","Type":"integer","Help":"","Required":false},{"Name":"service","Field":"service","Type":"string","Help":"","Required":false},{"Name":"soft-pct","Field":"softPct","Type":"integer","Help":"","Required":false},{"Name":"subject","Field":"subject","Type":"string","Help":"","Required":false},{"Name":"threshold","Field":"threshold","Type":"integer","Help":"","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"billing","Name":"alerts-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.","Method":"DELETE","Path":"/v1/billing/alerts/:id","Args":[{"Name":"id","Help":"ID is the cap to remove, from the path."}],"Flags":null,"Example":null},{"Service":"billing","Name":"alerts-list","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.","Method":"GET","Path":"/v1/billing/alerts","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"alerts-update","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.","Method":"PATCH","Path":"/v1/billing/alerts/:id","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"enforce","Field":"enforce","Type":"boolean","Help":"","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"","Required":false},{"Name":"rate-limit-rpm","Field":"rateLimitRpm","Type":"integer","Help":"","Required":false},{"Name":"service","Field":"service","Type":"string","Help":"","Required":false},{"Name":"soft-pct","Field":"softPct","Type":"integer","Help":"","Required":false},{"Name":"subject","Field":"subject","Type":"string","Help":"","Required":false},{"Name":"threshold","Field":"threshold","Type":"integer","Help":"","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"billing","Name":"assign-seats","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.","Method":"PUT","Path":"/v1/billing/subscriptions/:id/seats","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"assigned","Field":"assigned","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"billing","Name":"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.","Method":"GET","Path":"/v1/billing/balance","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"cancel-subscription","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.","Method":"POST","Path":"/v1/billing/subscriptions/:id/cancel","Args":[{"Name":"id","Help":"ID is the subscription, from the path."}],"Flags":[{"Name":"at-period-end","Field":"atPeriodEnd","Type":"boolean","Help":"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.","Required":false}],"Example":null},{"Service":"billing","Name":"collect-invoice","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.","Method":"POST","Path":"/v1/billing/invoices/:id/collect","Args":[{"Name":"id","Help":"ID is the invoice id."}],"Flags":[{"Name":"brand","Field":"brand","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"billing","Name":"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.","Method":"GET","Path":"/v1/billing/credit-balance/breakdown","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"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.","Method":"GET","Path":"/v1/billing/credit-balance","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"credits-list","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.","Method":"GET","Path":"/v1/billing/credits","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"crypto-deposit-create","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.","Method":"POST","Path":"/v1/billing/crypto/deposit","Args":[],"Flags":[{"Name":"amount-cents","Field":"amountCents","Type":"integer","Help":"AmountCents is what the payer intends to send, for the record. Optional —\nthe credit is what actually arrives, never what was announced.","Required":false},{"Name":"chain","Field":"chain","Type":"string","Help":"Chain is the network to receive on. Empty takes the rail's default.","Required":false},{"Name":"token","Field":"token","Type":"string","Help":"Token is the asset on that chain. Empty takes the chain's native one.","Required":false}],"Example":null},{"Service":"billing","Name":"crypto-deposit-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.","Method":"GET","Path":"/v1/billing/crypto/deposit/:id","Args":[{"Name":"id","Help":"ID is the deposit intent id."}],"Flags":null,"Example":null},{"Service":"billing","Name":"crypto-gateway-create","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.","Method":"POST","Path":"/v1/billing/crypto/gateway","Args":[],"Flags":[{"Name":"authorization","Field":"authorization","Type":"json","Help":"Authorization is the EIP-3009 TransferWithAuthorization as signed: every\nfield a string, addresses and nonce 0x hex, value in USDC base units.","Required":false},{"Name":"network","Field":"network","Type":"string","Help":"Network is the CAIP-2 network the payment was signed for, one of the\nterms' accepts, e.g. \"eip155:8453\".","Required":false},{"Name":"salt","Field":"salt","Type":"string","Help":"Salt is the salt the terms issued with the nonce.","Required":false},{"Name":"signature","Field":"signature","Type":"string","Help":"Signature is the 65-byte EIP-712 signature, 0x hex.","Required":false}],"Example":null},{"Service":"billing","Name":"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.","Method":"GET","Path":"/v1/billing/crypto/gateway","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"crypto-gateway-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.","Method":"GET","Path":"/v1/billing/crypto/gateway/:id","Args":[{"Name":"id","Help":"ID is the top-up's id, from the path."}],"Flags":null,"Example":null},{"Service":"billing","Name":"crypto-options-list","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.","Method":"GET","Path":"/v1/billing/crypto/options","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"get-invoice","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.","Method":"GET","Path":"/v1/billing/invoices/:id","Args":[{"Name":"id","Help":"ID is the invoice id."}],"Flags":[{"Name":"brand","Field":"brand","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"billing","Name":"invoices-list","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.","Method":"GET","Path":"/v1/billing/invoices","Args":[],"Flags":[{"Name":"subject","Field":"subject","Type":"string","Help":"","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"","Required":false},{"Name":"subscription-id","Field":"subscriptionId","Type":"string","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"cursor","Field":"cursor","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"billing","Name":"invoices-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.","Method":"GET","Path":"/v1/billing/invoices/:id/pdf","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"billing","Name":"issue-invoice","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.","Method":"POST","Path":"/v1/billing/invoices/:id/issue","Args":[{"Name":"id","Help":"ID is the invoice id."}],"Flags":[{"Name":"brand","Field":"brand","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"billing","Name":"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.","Method":"GET","Path":"/v1/billing/ledger","Args":[],"Flags":[{"Name":"range","Field":"range","Type":"string","Help":"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.","Required":false}],"Example":{"range":"30d"}},{"Service":"billing","Name":"methods-create","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.","Method":"POST","Path":"/v1/billing/methods","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"methods-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.","Method":"DELETE","Path":"/v1/billing/methods/:id","Args":[{"Name":"id","Help":"ID is the saved method to detach, from the path."}],"Flags":null,"Example":null},{"Service":"billing","Name":"methods-list","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.","Method":"GET","Path":"/v1/billing/methods","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"mode-create","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.","Method":"POST","Path":"/v1/billing/mode","Args":[],"Flags":[{"Name":"test-mode","Field":"testMode","Type":"boolean","Help":"","Required":false}],"Example":null},{"Service":"billing","Name":"payouts-list","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.","Method":"GET","Path":"/v1/billing/payouts","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"plans-list","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.","Method":"GET","Path":"/v1/billing/plans","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"portal-methods-create","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.","Method":"POST","Path":"/v1/billing/portal/methods","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"portal-methods-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.","Method":"DELETE","Path":"/v1/billing/portal/methods/:id","Args":[{"Name":"id","Help":"ID is the saved method to detach, from the path."}],"Flags":null,"Example":null},{"Service":"billing","Name":"portal-methods-list","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.","Method":"GET","Path":"/v1/billing/portal/methods","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"raise-invoice","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.","Method":"POST","Path":"/v1/billing/invoices","Args":[],"Flags":[{"Name":"currency","Field":"currency","Type":"string","Help":"Currency is the ISO 4217 code, lower-cased. Empty means usd.","Required":false},{"Name":"customer-email","Field":"customerEmail","Type":"string","Help":"CustomerEmail is where the invoice is sent. Optional.","Required":false},{"Name":"lines","Field":"lines","Type":"json","Help":"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.","Required":false},{"Name":"user-id","Field":"userId","Type":"string","Help":"UserID identifies the customer being billed, within the caller's own org.\nRequired — an invoice with no addressee is not an invoice.","Required":false}],"Example":null},{"Service":"billing","Name":"reactivate-subscription","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.","Method":"POST","Path":"/v1/billing/subscriptions/:id/reactivate","Args":[{"Name":"id","Help":"ID is the subscription, from the path."}],"Flags":[{"Name":"at-period-end","Field":"atPeriodEnd","Type":"boolean","Help":"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.","Required":false}],"Example":null},{"Service":"billing","Name":"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.","Method":"GET","Path":"/v1/billing/recharge","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"recharge-run-all-create","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.","Method":"POST","Path":"/v1/billing/recharge/run-all","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"recharge-update","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.","Method":"PUT","Path":"/v1/billing/recharge","Args":[],"Flags":[{"Name":"amount-cents","Field":"amountCents","Type":"integer","Help":"","Required":false},{"Name":"currency","Field":"currency","Type":"string","Help":"","Required":false},{"Name":"enabled","Field":"enabled","Type":"boolean","Help":"","Required":false},{"Name":"threshold-cents","Field":"thresholdCents","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"billing","Name":"resize-subscription","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.","Method":"POST","Path":"/v1/billing/subscriptions/:id/resize","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"lines","Field":"lines","Type":"json","Help":"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.","Required":false},{"Name":"quantity","Field":"quantity","Type":"integer","Help":"Quantity is the seats of the subscription's own seat type; 0 keeps them.","Required":false}],"Example":null},{"Service":"billing","Name":"settings-list","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.","Method":"GET","Path":"/v1/billing/settings","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"subscribe-card-create","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.","Method":"POST","Path":"/v1/billing/subscribe/card","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"subscriptions-list","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.","Method":"GET","Path":"/v1/billing/subscriptions","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"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.","Method":"GET","Path":"/v1/billing/tier","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"topup-create","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.","Method":"POST","Path":"/v1/billing/topup","Args":[],"Flags":[{"Name":"amount-cents","Field":"amountCents","Type":"integer","Help":"AmountCents is how much to charge, in cents of Currency. Required.","Required":false},{"Name":"currency","Field":"currency","Type":"string","Help":"Currency is the ISO-4217 code to charge in. Empty takes the deployment's\nown default.","Required":false},{"Name":"payment-method-id","Field":"paymentMethodId","Type":"string","Help":"MethodID names a card the subject already saved, for the saved-card endpoint.","Required":false},{"Name":"source-id","Field":"sourceId","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"billing","Name":"topup-token-create","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.","Method":"POST","Path":"/v1/billing/topup/token","Args":[],"Flags":[{"Name":"amount-cents","Field":"amountCents","Type":"integer","Help":"AmountCents is how much to charge, in cents of Currency. Required.","Required":false},{"Name":"currency","Field":"currency","Type":"string","Help":"Currency is the ISO-4217 code to charge in. Empty takes the deployment's\nown default.","Required":false},{"Name":"payment-method-id","Field":"paymentMethodId","Type":"string","Help":"MethodID names a card the subject already saved, for the saved-card endpoint.","Required":false},{"Name":"source-id","Field":"sourceId","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"billing","Name":"transactions-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.","Method":"GET","Path":"/v1/billing/transactions/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"billing","Name":"transactions-list","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.","Method":"GET","Path":"/v1/billing/transactions","Args":[],"Flags":[{"Name":"currency","Field":"currency","Type":"string","Help":"Currency filters to one currency. Empty reads every currency.","Required":false},{"Name":"limit","Field":"limit","Type":"string","Help":"Limit is the page size; absent or non-positive takes the default 100.","Required":false},{"Name":"offset","Field":"offset","Type":"string","Help":"Offset is how far into the history the page starts.","Required":false}],"Example":null},{"Service":"billing","Name":"usage-accounts-list","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.","Method":"GET","Path":"/v1/billing/usage/accounts","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"usage-create","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.","Method":"POST","Path":"/v1/billing/usage","Args":[],"Flags":[{"Name":"amount","Field":"amount","Type":"json","Help":"Amount is what the act costs, as an exact decimal in USD. It must be\ngreater than zero.","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"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.","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"Model names the unit the amount prices (a machine size, a model id), and is\nrecorded with the debit.","Required":false},{"Name":"org","Field":"org","Type":"string","Help":"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.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project attributes the debit to one project of the org. Empty is the org's\ndefault project.","Required":false},{"Name":"service","Field":"service","Type":"string","Help":"Service scopes the debit for spend caps and attributes it to a product, as\na lowercase slug. Empty takes the reporting application's name.","Required":false}],"Example":null},{"Service":"billing","Name":"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.","Method":"GET","Path":"/v1/billing/usage","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"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.","Method":"GET","Path":"/v1/billing/usage/rollup","Args":[],"Flags":null,"Example":null},{"Service":"billing","Name":"void-invoice","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.","Method":"POST","Path":"/v1/billing/invoices/:id/void","Args":[{"Name":"id","Help":"ID is the invoice id."}],"Flags":[{"Name":"brand","Field":"brand","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"billing","Name":"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.","Method":"GET","Path":"/v1/billing/wire","Args":[],"Flags":null,"Example":null},{"Service":"blueprint","Name":"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.","Method":"GET","Path":"/v1/blueprint/health","Args":[],"Flags":null,"Example":null},{"Service":"blueprint","Name":"list","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).","Method":"GET","Path":"/v1/blueprint","Args":[],"Flags":null,"Example":null},{"Service":"blueprint","Name":"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.","Method":"GET","Path":"/v1/blueprint/sbom","Args":[],"Flags":null,"Example":null},{"Service":"books","Name":"accounts-list","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.","Method":"GET","Path":"/v1/books/accounts","Args":[],"Flags":[{"Name":"sandbox","Field":"sandbox","Type":"string","Help":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\"; anything else\nreads the live one.","Required":false}],"Example":{"sandbox":"false"}},{"Service":"books","Name":"ask-create","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.","Method":"POST","Path":"/v1/books/ask","Args":[],"Flags":[{"Name":"from","Field":"from","Type":"string","Help":"From is the RFC3339 start of the metric window. Empty means all time, treated as a\nsingle reporting period (see monthsBetween).","Required":false},{"Name":"question","Field":"question","Type":"string","Help":"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.","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"To is the RFC3339 end of the metric window. Empty means up to now.","Required":false}],"Example":{"question":"how long is my runway?"}},{"Service":"books","Name":"bank-import-create","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.","Method":"POST","Path":"/v1/books/bank/import","Args":[],"Flags":[{"Name":"body","Field":"body","Type":"file","Help":"","Required":false,"In":"body"}],"Example":null,"Consumes":["application/octet-stream"]},{"Service":"books","Name":"bank-sync-create","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.","Method":"POST","Path":"/v1/books/bank/sync","Args":[],"Flags":null,"Example":null},{"Service":"books","Name":"bank-transactions-list","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.","Method":"GET","Path":"/v1/books/bank/transactions","Args":[],"Flags":[{"Name":"sandbox","Field":"sandbox","Type":"string","Help":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\".","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many rows come back; 500 when absent or not positive.","Required":false}],"Example":{"limit":100}},{"Service":"books","Name":"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.","Method":"GET","Path":"/v1/books/bank/unreconciled","Args":[],"Flags":[{"Name":"sandbox","Field":"sandbox","Type":"string","Help":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\"; anything else\nreads the live one.","Required":false}],"Example":{"sandbox":"false"}},{"Service":"books","Name":"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.","Method":"GET","Path":"/v1/books/export","Args":[],"Flags":[{"Name":"sandbox","Field":"sandbox","Type":"string","Help":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\".","Required":false},{"Name":"from","Field":"from","Type":"string","Help":"From is the RFC3339 start of the window, exclusive. Empty means all time.","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"To is the RFC3339 end of the window, inclusive. Empty means up to now.","Required":false},{"Name":"format","Field":"format","Type":"string","Help":"Format is the export encoding. Only \"json\" is supported; empty means json.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the GL detail rows included as the audit trail; 5000 when absent\nor not positive.","Required":false}],"Example":{"format":"json","from":"2026-01-01T00:00:00Z","to":"2026-12-31T23:59:59Z"}},{"Service":"books","Name":"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.","Method":"GET","Path":"/v1/books/gl","Args":[],"Flags":[{"Name":"sandbox","Field":"sandbox","Type":"string","Help":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\".","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many rows come back; 500 when absent or not positive.","Required":false}],"Example":{"limit":100}},{"Service":"books","Name":"inbox-create","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.","Method":"POST","Path":"/v1/books/inbox","Args":[],"Flags":[{"Name":"body","Field":"body","Type":"file","Help":"","Required":false,"In":"body"}],"Example":null,"Consumes":["application/octet-stream"]},{"Service":"books","Name":"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.","Method":"GET","Path":"/v1/books/inbox","Args":[],"Flags":[{"Name":"sandbox","Field":"sandbox","Type":"string","Help":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\"; anything else\nreads the live one.","Required":false}],"Example":{"sandbox":"false"}},{"Service":"books","Name":"metrics-list","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.","Method":"GET","Path":"/v1/books/metrics","Args":[],"Flags":[{"Name":"sandbox","Field":"sandbox","Type":"string","Help":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\".","Required":false},{"Name":"from","Field":"from","Type":"string","Help":"From is the RFC3339 start of the window, exclusive. Empty means all time.","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"To is the RFC3339 end of the window, inclusive. Empty means up to now.","Required":false}],"Example":{"from":"2026-01-01T00:00:00Z","to":"2026-06-30T23:59:59Z"}},{"Service":"books","Name":"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.","Method":"GET","Path":"/v1/books/pnl","Args":[],"Flags":[{"Name":"sandbox","Field":"sandbox","Type":"string","Help":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\".","Required":false},{"Name":"from","Field":"from","Type":"string","Help":"From is the RFC3339 start of the window, exclusive. Empty means all time.","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"To is the RFC3339 end of the window, inclusive. Empty means up to now.","Required":false}],"Example":{"from":"2026-01-01T00:00:00Z","to":"2026-03-31T23:59:59Z"}},{"Service":"books","Name":"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.","Method":"GET","Path":"/v1/books/position","Args":[],"Flags":[{"Name":"sandbox","Field":"sandbox","Type":"string","Help":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\".","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"To is the RFC3339 instant the statement is struck as of. Empty means all time.","Required":false}],"Example":{"to":"2026-03-31T23:59:59Z"}},{"Service":"books","Name":"questions-list","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.","Method":"GET","Path":"/v1/books/questions","Args":[],"Flags":[{"Name":"sandbox","Field":"sandbox","Type":"string","Help":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\"; anything else\nreads the live one.","Required":false}],"Example":{"sandbox":"false"}},{"Service":"books","Name":"rules-create","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.","Method":"POST","Path":"/v1/books/rules","Args":[],"Flags":[{"Name":"category","Field":"category","Type":"string","Help":"Category is the COA expense account a matching bill books to. An upsert normalizes\na slug (\"cloud\") to its account number.","Required":false},{"Name":"pattern","Field":"pattern","Type":"string","Help":"Pattern is the merchant substring the rule matches on, case-insensitively. It is\nalso the key an upsert writes by.","Required":false},{"Name":"priority","Field":"priority","Type":"integer","Help":"Priority breaks ties: when several patterns match, the highest wins.","Required":false}],"Example":{"category":"cloud","pattern":"aws","priority":5}},{"Service":"books","Name":"rules-list","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.","Method":"GET","Path":"/v1/books/rules","Args":[],"Flags":[{"Name":"sandbox","Field":"sandbox","Type":"string","Help":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\"; anything else\nreads the live one.","Required":false}],"Example":{"sandbox":"false"}},{"Service":"books","Name":"scan-book-create","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.","Method":"POST","Path":"/v1/books/scan/book","Args":[],"Flags":[{"Name":"override","Field":"override","Type":"boolean","Help":"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.","Required":false},{"Name":"scan-id","Field":"scanId","Type":"string","Help":"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.","Required":false},{"Name":"voucher","Field":"voucher","Type":"json","Help":"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.","Required":false}],"Example":{"scanId":"a5f3c1","voucher":{"description":"GitHub","legs":[{"account":"5300","debit":1234},{"account":"2001","credit":1234}]}}},{"Service":"books","Name":"scan-create","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.","Method":"POST","Path":"/v1/books/scan","Args":[],"Flags":[{"Name":"body","Field":"body","Type":"file","Help":"","Required":false,"In":"body"}],"Example":null,"Consumes":["application/octet-stream"]},{"Service":"books","Name":"sync-create","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.","Method":"POST","Path":"/v1/books/sync","Args":[],"Flags":null,"Example":null},{"Service":"books","Name":"transactions-list","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.","Method":"GET","Path":"/v1/books/transactions","Args":[],"Flags":[{"Name":"sandbox","Field":"sandbox","Type":"string","Help":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\".","Required":false},{"Name":"from","Field":"from","Type":"string","Help":"From is the RFC3339 start of the posting-time window, inclusive.","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"To is the RFC3339 end of the posting-time window, inclusive.","Required":false},{"Name":"category","Field":"category","Type":"string","Help":"Category filters to one COA account, named by number (\"5300\") or by category\nslug (\"software\").","Required":false},{"Name":"vendor","Field":"vendor","Type":"string","Help":"Vendor filters to rows whose vendor or description contains this text,\ncase-insensitively.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many rows come back; 200 when absent or not positive.","Required":false}],"Example":{"category":"software","limit":50}},{"Service":"books","Name":"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.","Method":"GET","Path":"/v1/books/trial","Args":[],"Flags":[{"Name":"sandbox","Field":"sandbox","Type":"string","Help":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\".","Required":false},{"Name":"from","Field":"from","Type":"string","Help":"From is the RFC3339 start of the window, exclusive. Empty means all time.","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"To is the RFC3339 end of the window, inclusive. Empty means up to now.","Required":false}],"Example":{"from":"2026-01-01T00:00:00Z","to":"2026-03-31T23:59:59Z"}},{"Service":"books","Name":"vendors-create","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.","Method":"POST","Path":"/v1/books/vendors","Args":[],"Flags":[{"Name":"aliases","Field":"aliases","Type":"json","Help":"Aliases are the other spellings a receipt may print the vendor under; a scan\nmatching any of them resolves to this vendor.","Required":false},{"Name":"canonical","Field":"canonical","Type":"string","Help":"Canonical is the vendor's one true name, and the key an upsert writes by.","Required":false},{"Name":"default-category","Field":"defaultCategory","Type":"string","Help":"DefaultCategory is the COA expense account new bills from this vendor book to.\nAn upsert normalizes a slug (\"software\") to its account number.","Required":false}],"Example":{"aliases":["github.com"],"canonical":"GitHub","defaultCategory":"software"}},{"Service":"books","Name":"vendors-list","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.","Method":"GET","Path":"/v1/books/vendors","Args":[],"Flags":[{"Name":"sandbox","Field":"sandbox","Type":"string","Help":"Sandbox reads the org's SANDBOX ledger when it is exactly \"true\"; anything else\nreads the live one.","Required":false}],"Example":{"sandbox":"false"}},{"Service":"bot","Name":"members-list","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.","Method":"GET","Path":"/v1/bot/members","Args":[],"Flags":null,"Example":null},{"Service":"bot","Name":"members-sync-create","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.","Method":"POST","Path":"/v1/bot/members/sync","Args":[],"Flags":null,"Example":null},{"Service":"bot","Name":"runs-list","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.","Method":"GET","Path":"/v1/bot/runs","Args":[],"Flags":null,"Example":null},{"Service":"bot","Name":"runs-stop","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.","Method":"POST","Path":"/v1/bot/runs/:runId/stop","Args":[{"Name":"runId","Help":"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."}],"Flags":null,"Example":null},{"Service":"build","Name":"create","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.","Method":"POST","Path":"/v1/build","Args":[],"Flags":[{"Name":"arch","Field":"arch","Type":"string","Help":"Arch is the target architecture for the artifact lane.","Required":false},{"Name":"args","Field":"args","Type":"json","Help":"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.","Required":false},{"Name":"binaries","Field":"binaries","Type":"json","Help":"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.","Required":false},{"Name":"branch","Field":"branch","Type":"string","Help":"Branch is the branch to build when no SHA or Ref is given.","Required":false},{"Name":"bucket","Field":"bucket","Type":"string","Help":"Bucket mirrors hanzo.yml's `bucket:` — where the artifact lane publishes.","Required":false},{"Name":"context","Field":"context","Type":"string","Help":"Context is the build context path within the repo.","Required":false},{"Name":"docker-target","Field":"dockerTarget","Type":"string","Help":"DockerTarget is the multi-stage build target to stop at.","Required":false},{"Name":"dockerfile","Field":"dockerfile","Type":"string","Help":"Dockerfile is the path to build from; empty uses the zero-config frontend.","Required":false},{"Name":"image","Field":"image","Type":"string","Help":"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.","Required":false},{"Name":"os","Field":"os","Type":"string","Help":"OS is the target operating system for the artifact lane.","Required":false},{"Name":"platforms","Field":"platforms","Type":"json","Help":"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.","Required":false},{"Name":"ref","Field":"ref","Type":"string","Help":"Ref is the git ref to build when no SHA is given.","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"Repo is the repository clone URL to build. Required on the image lane.","Required":false},{"Name":"sha","Field":"sha","Type":"string","Help":"SHA is the commit to pin; it wins over Ref and Branch.","Required":false},{"Name":"tag","Field":"tag","Type":"string","Help":"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.","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"build","Name":"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.","Method":"GET","Path":"/v1/build/:id","Args":[{"Name":"id","Help":"ID is the build's id, from the path."}],"Flags":null,"Example":null},{"Service":"campaign","Name":"channels","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.","Method":"POST","Path":"/v1/campaign/:id/channels","Args":[{"Name":"id","Help":"ID is the campaign to add the channel to, from the path."}],"Flags":[{"Name":"account","Field":"account","Type":"string","Help":"Account is the provider account this channel runs under: an ad-account, a\npage, or a mailing-list id.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind is the channel kind and the identity a campaign holds at most one of:\npaid, organic or email.","Required":false},{"Name":"platform","Field":"platform","Type":"string","Help":"Platform is the provider within the kind — meta, google, x, instagram, or\nthe email provider.","Required":false}],"Example":{"account":"list_42","id":"cmp_1f…","kind":"email","platform":"sendgrid"}},{"Service":"campaign","Name":"create","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.","Method":"POST","Path":"/v1/campaign","Args":[],"Flags":[{"Name":"audience","Field":"audience","Type":"string","Help":"Audience is the segment or audience selector this campaign targets.","Required":false},{"Name":"budget","Field":"budget","Type":"integer","Help":"Budget is the campaign's total budget in CENTS. Negative reads as 0.","Required":false},{"Name":"channels","Field":"channels","Type":"json","Help":"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\".","Required":false},{"Name":"content","Field":"content","Type":"json","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the campaign's display name. Required; trimmed and capped at 2048\ncharacters.","Required":false},{"Name":"schedule-at","Field":"scheduleAt","Type":"integer","Help":"ScheduleAt is when the campaign should run, in unix seconds. Negative reads\nas 0 (immediately).","Required":false}],"Example":{"budget":250000,"channels":[{"kind":"paid","platform":"meta"}],"content":["Ship faster"],"name":"Spring launch"}},{"Service":"campaign","Name":"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.","Method":"DELETE","Path":"/v1/campaign/:id","Args":[{"Name":"id","Help":"ID is the campaign's server-minted handle, \"cmp_\"-prefixed."}],"Flags":null,"Example":null},{"Service":"campaign","Name":"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.","Method":"DELETE","Path":"/v1/campaign/:id/channels/:kind","Args":[{"Name":"id","Help":"ID is the campaign, from the path."},{"Name":"kind","Help":"Kind is the channel to remove: paid, organic or email."}],"Flags":null,"Example":null},{"Service":"campaign","Name":"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.","Method":"GET","Path":"/v1/campaign/:id","Args":[{"Name":"id","Help":"ID is the campaign's server-minted handle, \"cmp_\"-prefixed."}],"Flags":null,"Example":null},{"Service":"campaign","Name":"launch","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.","Method":"POST","Path":"/v1/campaign/:id/launch","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"campaign","Name":"list","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.","Method":"GET","Path":"/v1/campaign","Args":[],"Flags":[{"Name":"status","Field":"status","Type":"string","Help":"Status keeps only campaigns in that state: draft, live, paused or failed.\nEmpty means any.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit bounds the page. 0 or less means the default of 200; anything above\n1000 is clamped to 1000.","Required":false}],"Example":{"limit":50,"status":"live"}},{"Service":"campaign","Name":"metrics-list","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.","Method":"GET","Path":"/v1/campaign/:id/metrics","Args":[{"Name":"id","Help":"ID is the campaign to report on, from the path."}],"Flags":[{"Name":"range","Field":"range","Type":"string","Help":"Range is the lookback window: 24h, 7d, 30d or 90d. Anything else, including\nempty, reads as 30d.","Required":false},{"Name":"start","Field":"start","Type":"string","Help":"Start is an explicit RFC3339 window start. Honored only together with End,\nand only when End is after it.","Required":false},{"Name":"end","Field":"end","Type":"string","Help":"End is an explicit RFC3339 window end.","Required":false}],"Example":{"id":"cmp_1f…","range":"7d"}},{"Service":"campaign","Name":"pause","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.","Method":"POST","Path":"/v1/campaign/:id/pause","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"campaign","Name":"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.","Method":"GET","Path":"/v1/campaign/summary","Args":[],"Flags":null,"Example":null},{"Service":"campaign","Name":"update","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.","Method":"PUT","Path":"/v1/campaign/:id","Args":[{"Name":"id","Help":"ID is the campaign to update, from the path."}],"Flags":[{"Name":"audience","Field":"audience","Type":"string","Help":"Audience is the segment or audience selector this campaign targets.","Required":false},{"Name":"budget","Field":"budget","Type":"integer","Help":"Budget is the campaign's total budget in CENTS. Negative reads as 0.","Required":false},{"Name":"channels","Field":"channels","Type":"json","Help":"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\".","Required":false},{"Name":"content","Field":"content","Type":"json","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the campaign's display name. Required; trimmed and capped at 2048\ncharacters.","Required":false},{"Name":"schedule-at","Field":"scheduleAt","Type":"integer","Help":"ScheduleAt is when the campaign should run, in unix seconds. Negative reads\nas 0 (immediately).","Required":false}],"Example":{"budget":500000,"name":"Spring launch"}},{"Service":"capabilities","Name":"capture","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.","Method":"GET","Path":"/v1/capabilities/capture","Args":[],"Flags":null,"Example":null},{"Service":"capabilities","Name":"corrections","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.","Method":"GET","Path":"/v1/capabilities/corrections","Args":[],"Flags":[{"Name":"question","Field":"question","Type":"string","Help":"Question keeps one question's corrections.","Required":false}],"Example":null},{"Service":"capabilities","Name":"create","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).","Method":"POST","Path":"/v1/capabilities","Args":[],"Flags":[{"Name":"corrections","Field":"corrections","Type":"json","Help":"Corrections are the corrections it is taught from: captured corrections of\none question, which becomes its route.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is its name: lowercase words joined by hyphens, at most 64.","Required":false}],"Example":{"corrections":["cor_0123456789abcdef"],"name":"refund-intent"}},{"Service":"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.","Method":"DELETE","Path":"/v1/capabilities/:name","Args":[{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"capabilities","Name":"disable","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.","Method":"POST","Path":"/v1/capabilities/:name/disable","Args":[{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"capabilities","Name":"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.","Method":"GET","Path":"/v1/capabilities/:name","Args":[{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"capabilities","Name":"list","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.","Method":"GET","Path":"/v1/capabilities","Args":[],"Flags":null,"Example":null},{"Service":"capabilities","Name":"publish","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).","Method":"POST","Path":"/v1/capabilities/:name/publish","Args":[{"Name":"name","Help":""}],"Flags":[{"Name":"version","Field":"version","Type":"integer","Help":"Version is the version to install; the newest that passed when absent.","Required":false}],"Example":null},{"Service":"capabilities","Name":"rollback","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.","Method":"POST","Path":"/v1/capabilities/:name/rollback","Args":[{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"capabilities","Name":"set-capture","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.","Method":"PUT","Path":"/v1/capabilities/capture","Args":[],"Flags":[{"Name":"on","Field":"on","Type":"boolean","Help":"","Required":false}],"Example":null},{"Service":"capabilities","Name":"train","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.","Method":"POST","Path":"/v1/capabilities/:name/train","Args":[{"Name":"name","Help":""}],"Flags":[{"Name":"corrections","Field":"corrections","Type":"json","Help":"Corrections, when given, replace the corrections it is taught from: captured\ncorrections of its question.","Required":false}],"Example":{"corrections":["cor_0123456789abcdef","cor_fedcba9876543210"]}},{"Service":"captable","Name":"classes-create","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.","Method":"POST","Path":"/v1/captable/classes","Args":[],"Flags":[{"Name":"board-approval-date","Field":"boardApprovalDate","Type":"json","Help":"BoardApprovalDate is when the board approved the class, YYYY-MM-DD.","Required":false},{"Name":"class-type","Field":"classType","Type":"json","Help":"ClassType is COMMON or PREFERRED.","Required":false},{"Name":"conversion-rights","Field":"conversionRights","Type":"json","Help":"ConversionRights is CONVERTS_TO_FUTURE_ROUND or CONVERTS_TO_SHARE_CLASS_ID. The second requires convertsToShareClassId.","Required":false},{"Name":"converts-to-share-class-id","Field":"convertsToShareClassId","Type":"json","Help":"ConvertsToShareClassID names the class this one converts into. Required when conversionRights is CONVERTS_TO_SHARE_CLASS_ID, ignored otherwise.","Required":false},{"Name":"initial-shares-authorized","Field":"initialSharesAuthorized","Type":"json","Help":"InitialSharesAuthorized is how many shares this class may issue. A whole number.","Required":false},{"Name":"liquidation-preference-multiple","Field":"liquidationPreferenceMultiple","Type":"json","Help":"LiquidationPreferenceMultiple is the multiple of invested capital paid out before junior classes — 1 for a 1x preference.","Required":false},{"Name":"name","Field":"name","Type":"json","Help":"Name is the share class's name, e.g. \"Series A Preferred\".","Required":false},{"Name":"par-value","Field":"parValue","Type":"json","Help":"ParValue is the nominal per-share value on the certificate, in the company's currency.","Required":false},{"Name":"participation-cap-multiple","Field":"participationCapMultiple","Type":"json","Help":"ParticipationCapMultiple caps participation after the preference is paid, as a multiple of invested capital. 0 for no cap.","Required":false},{"Name":"price-per-share","Field":"pricePerShare","Type":"json","Help":"PricePerShare is the issue price for this class, in the company's currency.","Required":false},{"Name":"seniority","Field":"seniority","Type":"json","Help":"Seniority orders liquidation preference: LOWER is more senior, so 1 is paid before 2.","Required":false},{"Name":"stockholder-approval-date","Field":"stockholderApprovalDate","Type":"json","Help":"StockholderApprovalDate is when the stockholders approved it, YYYY-MM-DD.","Required":false},{"Name":"votes-per-share","Field":"votesPerShare","Type":"json","Help":"VotesPerShare is how many votes one share of this class carries. A whole number; 0 for non-voting.","Required":false}],"Example":null},{"Service":"captable","Name":"classes-list","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.","Method":"GET","Path":"/v1/captable/classes","Args":[],"Flags":null,"Example":null},{"Service":"captable","Name":"classes-update","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.","Method":"PATCH","Path":"/v1/captable/classes/:id","Args":[{"Name":"id","Help":"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."}],"Flags":[{"Name":"board-approval-date","Field":"boardApprovalDate","Type":"json","Help":"BoardApprovalDate is when the board approved the class, YYYY-MM-DD.","Required":false},{"Name":"class-type","Field":"classType","Type":"json","Help":"ClassType is COMMON or PREFERRED.","Required":false},{"Name":"conversion-rights","Field":"conversionRights","Type":"json","Help":"ConversionRights is CONVERTS_TO_FUTURE_ROUND or CONVERTS_TO_SHARE_CLASS_ID. The second requires convertsToShareClassId.","Required":false},{"Name":"converts-to-share-class-id","Field":"convertsToShareClassId","Type":"json","Help":"ConvertsToShareClassID names the class this one converts into. Required when conversionRights is CONVERTS_TO_SHARE_CLASS_ID, ignored otherwise.","Required":false},{"Name":"initial-shares-authorized","Field":"initialSharesAuthorized","Type":"json","Help":"InitialSharesAuthorized is how many shares this class may issue. A whole number.","Required":false},{"Name":"liquidation-preference-multiple","Field":"liquidationPreferenceMultiple","Type":"json","Help":"LiquidationPreferenceMultiple is the multiple of invested capital paid out before junior classes — 1 for a 1x preference.","Required":false},{"Name":"name","Field":"name","Type":"json","Help":"Name is the share class's name, e.g. \"Series A Preferred\".","Required":false},{"Name":"par-value","Field":"parValue","Type":"json","Help":"ParValue is the nominal per-share value on the certificate, in the company's currency.","Required":false},{"Name":"participation-cap-multiple","Field":"participationCapMultiple","Type":"json","Help":"ParticipationCapMultiple caps participation after the preference is paid, as a multiple of invested capital. 0 for no cap.","Required":false},{"Name":"price-per-share","Field":"pricePerShare","Type":"json","Help":"PricePerShare is the issue price for this class, in the company's currency.","Required":false},{"Name":"seniority","Field":"seniority","Type":"json","Help":"Seniority orders liquidation preference: LOWER is more senior, so 1 is paid before 2.","Required":false},{"Name":"stockholder-approval-date","Field":"stockholderApprovalDate","Type":"json","Help":"StockholderApprovalDate is when the stockholders approved it, YYYY-MM-DD.","Required":false},{"Name":"votes-per-share","Field":"votesPerShare","Type":"json","Help":"VotesPerShare is how many votes one share of this class carries. A whole number; 0 for non-voting.","Required":false}],"Example":null},{"Service":"captable","Name":"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.","Method":"GET","Path":"/v1/captable/company","Args":[],"Flags":null,"Example":null},{"Service":"captable","Name":"company-update","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.","Method":"PUT","Path":"/v1/captable/company","Args":[],"Flags":[{"Name":"incorporation-country","Field":"incorporationCountry","Type":"json","Help":"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.","Required":false},{"Name":"incorporation-state","Field":"incorporationState","Type":"json","Help":"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.","Required":false},{"Name":"incorporation-type","Field":"incorporationType","Type":"json","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"captable","Name":"convertibles-create","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.","Method":"POST","Path":"/v1/captable/convertibles","Args":[],"Flags":[{"Name":"additional-terms","Field":"additionalTerms","Type":"json","Help":"AdditionalTerms is free text for anything the fields above do not carry. Optional.","Required":false},{"Name":"board-approval-date","Field":"boardApprovalDate","Type":"json","Help":"BoardApprovalDate is when the board approved it, YYYY-MM-DD.","Required":false},{"Name":"capital","Field":"capital","Type":"json","Help":"Capital is the principal lent, in the company's currency.","Required":false},{"Name":"conversion-cap","Field":"conversionCap","Type":"json","Help":"ConversionCap is the valuation the note converts at, at most. Optional.","Required":false},{"Name":"discount-rate","Field":"discountRate","Type":"json","Help":"DiscountRate is the discount to the next round's price, as a percentage. Optional.","Required":false},{"Name":"interest-rate","Field":"interestRate","Type":"json","Help":"InterestRate is the annual interest the principal accrues, as a percentage. Optional.","Required":false},{"Name":"issue-date","Field":"issueDate","Type":"json","Help":"IssueDate is when the note was issued, YYYY-MM-DD.","Required":false},{"Name":"public-id","Field":"publicId","Type":"json","Help":"PublicID is the note's identifier. It must be UNIQUE within the company; reusing one is refused 409.","Required":false},{"Name":"stakeholder-id","Field":"stakeholderId","Type":"json","Help":"StakeholderID is the lender. It must name a stakeholder of THIS company.","Required":false},{"Name":"status","Field":"status","Type":"json","Help":"Status is DRAFT, ACTIVE, PENDING, EXPIRED or CANCELLED.","Required":false},{"Name":"type","Field":"type","Type":"json","Help":"Type is CCD, OCD or NOTE.","Required":false}],"Example":null},{"Service":"captable","Name":"convertibles-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.","Method":"DELETE","Path":"/v1/captable/convertibles/:id","Args":[{"Name":"id","Help":"ID is the convertible note to delete."}],"Flags":null,"Example":null},{"Service":"captable","Name":"convertibles-list","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.","Method":"GET","Path":"/v1/captable/convertibles","Args":[],"Flags":null,"Example":null},{"Service":"captable","Name":"investments-list","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.","Method":"GET","Path":"/v1/captable/investments","Args":[],"Flags":null,"Example":null},{"Service":"captable","Name":"options-create","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.","Method":"POST","Path":"/v1/captable/options","Args":[],"Flags":[{"Name":"board-approval-date","Field":"boardApprovalDate","Type":"json","Help":"BoardApprovalDate is when the board approved the grant, YYYY-MM-DD.","Required":false},{"Name":"cliff-years","Field":"cliffYears","Type":"json","Help":"CliffYears is how long before ANY of the grant vests. A whole number; 0 for no cliff.","Required":false},{"Name":"equity-plan-id","Field":"equityPlanId","Type":"json","Help":"EquityPlanID is the plan the options come from. It must name a plan of THIS company.","Required":false},{"Name":"exercise-price","Field":"exercisePrice","Type":"json","Help":"ExercisePrice is the strike price per share, in the company's currency.","Required":false},{"Name":"expiration-date","Field":"expirationDate","Type":"json","Help":"ExpirationDate is when unexercised options lapse, YYYY-MM-DD.","Required":false},{"Name":"grant-id","Field":"grantId","Type":"json","Help":"GrantID is the grant's identifier. It must be UNIQUE within the company; reusing one is refused 409.","Required":false},{"Name":"issue-date","Field":"issueDate","Type":"json","Help":"IssueDate is when the grant was made, YYYY-MM-DD.","Required":false},{"Name":"notes","Field":"notes","Type":"json","Help":"Notes is a free-text note kept with the grant. Optional.","Required":false},{"Name":"quantity","Field":"quantity","Type":"json","Help":"Quantity is how many options to grant. A whole number above 0.","Required":false},{"Name":"rule144-date","Field":"rule144Date","Type":"json","Help":"Rule144Date is when the Rule 144 holding period starts, YYYY-MM-DD.","Required":false},{"Name":"stakeholder-id","Field":"stakeholderId","Type":"json","Help":"StakeholderID is who receives the grant. It must name a stakeholder of THIS company.","Required":false},{"Name":"status","Field":"status","Type":"json","Help":"Status is DRAFT, ACTIVE, EXERCISED, EXPIRED or CANCELLED.","Required":false},{"Name":"type","Field":"type","Type":"json","Help":"Type is ISO, NSO or RSU.","Required":false},{"Name":"vesting-start-date","Field":"vestingStartDate","Type":"json","Help":"VestingStartDate is when vesting begins, YYYY-MM-DD.","Required":false},{"Name":"vesting-years","Field":"vestingYears","Type":"json","Help":"VestingYears is the total vesting period. A whole number.","Required":false}],"Example":null},{"Service":"captable","Name":"options-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.","Method":"DELETE","Path":"/v1/captable/options/:id","Args":[{"Name":"id","Help":"ID is the option grant to delete."}],"Flags":null,"Example":null},{"Service":"captable","Name":"options-list","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.","Method":"GET","Path":"/v1/captable/options","Args":[],"Flags":null,"Example":null},{"Service":"captable","Name":"plans-create","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.","Method":"POST","Path":"/v1/captable/plans","Args":[],"Flags":[{"Name":"board-approval-date","Field":"boardApprovalDate","Type":"json","Help":"BoardApprovalDate is when the board adopted the plan, YYYY-MM-DD.","Required":false},{"Name":"comments","Field":"comments","Type":"json","Help":"Comments is a free-text note kept with the plan. Optional.","Required":false},{"Name":"default-cancellaton-behavior","Field":"defaultCancellatonBehavior","Type":"json","Help":"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.","Required":false},{"Name":"initial-shares-reserved","Field":"initialSharesReserved","Type":"json","Help":"InitialSharesReserved is how many shares the plan may grant. A whole number.","Required":false},{"Name":"name","Field":"name","Type":"json","Help":"Name is the plan's name, e.g. \"2026 Stock Option Plan\".","Required":false},{"Name":"plan-effective-date","Field":"planEffectiveDate","Type":"json","Help":"PlanEffectiveDate is when the plan takes effect, YYYY-MM-DD. Optional.","Required":false},{"Name":"share-class-id","Field":"shareClassId","Type":"json","Help":"ShareClassID is the class the plan grants from. It must name a class of THIS company.","Required":false}],"Example":null},{"Service":"captable","Name":"plans-list","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.","Method":"GET","Path":"/v1/captable/plans","Args":[],"Flags":null,"Example":null},{"Service":"captable","Name":"rounds-close","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.","Method":"POST","Path":"/v1/captable/rounds/:id/close","Args":[{"Name":"id","Help":"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."}],"Flags":[{"Name":"close-date","Field":"closeDate","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"captable","Name":"rounds-create","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.","Method":"POST","Path":"/v1/captable/rounds","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"json","Help":"Name is the round's name, e.g. \"Series A\".","Required":false},{"Name":"pre-money-valuation","Field":"preMoneyValuation","Type":"json","Help":"PreMoneyValuation is the company's valuation before the new money. Optional.","Required":false},{"Name":"price-per-share","Field":"pricePerShare","Type":"json","Help":"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.","Required":false},{"Name":"round-type","Field":"roundType","Type":"json","Help":"RoundType is PRICED, SAFE or CONVERTIBLE.","Required":false},{"Name":"share-class-id","Field":"shareClassId","Type":"json","Help":"ShareClassID is the class investors receive. It must name a class of THIS company.","Required":false},{"Name":"target-amount","Field":"targetAmount","Type":"json","Help":"TargetAmount is how much the round aims to raise, in the company's currency.","Required":false}],"Example":null},{"Service":"captable","Name":"rounds-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.","Method":"GET","Path":"/v1/captable/rounds/:id","Args":[{"Name":"id","Help":"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."}],"Flags":null,"Example":null},{"Service":"captable","Name":"rounds-investments","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.","Method":"POST","Path":"/v1/captable/rounds/:id/investments","Args":[{"Name":"id","Help":"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."}],"Flags":[{"Name":"amount","Field":"amount","Type":"json","Help":"Amount is the money invested, in the round's own currency. Required and must\nbe positive.","Required":false},{"Name":"comments","Field":"comments","Type":"json","Help":"Comments is a free-text note kept with the investment. Optional.","Required":false},{"Name":"date","Field":"date","Type":"json","Help":"Date is when the investment was made, YYYY-MM-DD. Optional: omitted, it is\nrecorded as today.","Required":false},{"Name":"stakeholder-id","Field":"stakeholderId","Type":"json","Help":"StakeholderID is the investor. Required, and it must reference a stakeholder\nof the same company.","Required":false}],"Example":null},{"Service":"captable","Name":"rounds-list","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.","Method":"GET","Path":"/v1/captable/rounds","Args":[],"Flags":null,"Example":null},{"Service":"captable","Name":"safes-create","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.","Method":"POST","Path":"/v1/captable/safes","Args":[],"Flags":[{"Name":"additional-terms","Field":"additionalTerms","Type":"json","Help":"AdditionalTerms is free text for anything the fields above do not carry. Optional.","Required":false},{"Name":"board-approval-date","Field":"boardApprovalDate","Type":"json","Help":"BoardApprovalDate is when the board approved it, YYYY-MM-DD.","Required":false},{"Name":"capital","Field":"capital","Type":"json","Help":"Capital is the money invested, in the company's currency.","Required":false},{"Name":"discount-rate","Field":"discountRate","Type":"json","Help":"DiscountRate is the discount to the next round's price, as a percentage. Optional.","Required":false},{"Name":"issue-date","Field":"issueDate","Type":"json","Help":"IssueDate is when the SAFE was signed, YYYY-MM-DD.","Required":false},{"Name":"public-id","Field":"publicId","Type":"json","Help":"PublicID is the SAFE's identifier. It must be UNIQUE within the company; reusing one is refused 409.","Required":false},{"Name":"stakeholder-id","Field":"stakeholderId","Type":"json","Help":"StakeholderID is the investor. It must name a stakeholder of THIS company.","Required":false},{"Name":"status","Field":"status","Type":"json","Help":"Status is DRAFT, ACTIVE, PENDING, EXPIRED or CANCELLED.","Required":false},{"Name":"type","Field":"type","Type":"json","Help":"Type is PRE_MONEY or POST_MONEY — which side of the new money the cap is measured on.","Required":false},{"Name":"valuation-cap","Field":"valuationCap","Type":"json","Help":"ValuationCap is the valuation the SAFE converts at, at most. Optional; omit for an uncapped SAFE.","Required":false}],"Example":null},{"Service":"captable","Name":"safes-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.","Method":"DELETE","Path":"/v1/captable/safes/:id","Args":[{"Name":"id","Help":"ID is the SAFE to delete."}],"Flags":null,"Example":null},{"Service":"captable","Name":"safes-list","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.","Method":"GET","Path":"/v1/captable/safes","Args":[],"Flags":null,"Example":null},{"Service":"captable","Name":"shares-create","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.","Method":"POST","Path":"/v1/captable/shares","Args":[],"Flags":[{"Name":"board-approval-date","Field":"boardApprovalDate","Type":"json","Help":"BoardApprovalDate is when the board approved the issuance, YYYY-MM-DD.","Required":false},{"Name":"capital-contribution","Field":"capitalContribution","Type":"json","Help":"CapitalContribution is cash paid for the shares. Optional.","Required":false},{"Name":"certificate-id","Field":"certificateId","Type":"json","Help":"CertificateID is the certificate number. It must be UNIQUE within the company; reusing one is refused 409.","Required":false},{"Name":"cliff-years","Field":"cliffYears","Type":"json","Help":"CliffYears is how long before ANY of the grant vests. A whole number; 0 for no cliff.","Required":false},{"Name":"company-legends","Field":"companyLegends","Type":"json","Help":"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.","Required":false},{"Name":"debt-cancelled","Field":"debtCancelled","Type":"json","Help":"DebtCancelled is debt forgiven as consideration. Optional.","Required":false},{"Name":"ip-contribution","Field":"ipContribution","Type":"json","Help":"IPContribution is intellectual property assigned as consideration, valued in the company's currency. Optional.","Required":false},{"Name":"issue-date","Field":"issueDate","Type":"json","Help":"IssueDate is when the shares were issued, YYYY-MM-DD.","Required":false},{"Name":"other-contributions","Field":"otherContributions","Type":"json","Help":"OtherContributions is any other consideration, valued in the company's currency. Optional.","Required":false},{"Name":"price-per-share","Field":"pricePerShare","Type":"json","Help":"PricePerShare is what was paid per share. Optional.","Required":false},{"Name":"quantity","Field":"quantity","Type":"json","Help":"Quantity is how many shares to issue. A whole number above 0.","Required":false},{"Name":"rule144-date","Field":"rule144Date","Type":"json","Help":"Rule144Date is when the Rule 144 holding period starts, YYYY-MM-DD. Optional.","Required":false},{"Name":"share-class-id","Field":"shareClassId","Type":"json","Help":"ShareClassID is the class being issued. It must name a class of THIS company.","Required":false},{"Name":"stakeholder-id","Field":"stakeholderId","Type":"json","Help":"StakeholderID is who receives the shares. It must name a stakeholder of THIS company.","Required":false},{"Name":"status","Field":"status","Type":"json","Help":"Status is ACTIVE, DRAFT, SIGNED or PENDING.","Required":false},{"Name":"vesting-start-date","Field":"vestingStartDate","Type":"json","Help":"VestingStartDate is when vesting begins, YYYY-MM-DD. Optional; defaults to the issue date.","Required":false},{"Name":"vesting-years","Field":"vestingYears","Type":"json","Help":"VestingYears is the total vesting period. A whole number; 0 for fully vested at issue.","Required":false}],"Example":null},{"Service":"captable","Name":"shares-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.","Method":"DELETE","Path":"/v1/captable/shares/:id","Args":[{"Name":"id","Help":"ID is the share certificate to delete."}],"Flags":null,"Example":null},{"Service":"captable","Name":"shares-list","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.","Method":"GET","Path":"/v1/captable/shares","Args":[],"Flags":null,"Example":null},{"Service":"captable","Name":"shares-transfer-create","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.","Method":"POST","Path":"/v1/captable/shares/transfer","Args":[],"Flags":[{"Name":"certificate-id","Field":"certificateId","Type":"json","Help":"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.","Required":false},{"Name":"quantity","Field":"quantity","Type":"json","Help":"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.","Required":false},{"Name":"share-id","Field":"shareId","Type":"json","Help":"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.","Required":false},{"Name":"to-stakeholder-id","Field":"toStakeholderId","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"captable","Name":"stakeholders-create","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.","Method":"POST","Path":"/v1/captable/stakeholders","Args":[],"Flags":null,"Example":null},{"Service":"captable","Name":"stakeholders-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.","Method":"DELETE","Path":"/v1/captable/stakeholders/:id","Args":[{"Name":"id","Help":"ID is the stakeholder to delete."}],"Flags":null,"Example":null},{"Service":"captable","Name":"stakeholders-list","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.","Method":"GET","Path":"/v1/captable/stakeholders","Args":[],"Flags":null,"Example":null},{"Service":"captable","Name":"stakeholders-update","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.","Method":"PATCH","Path":"/v1/captable/stakeholders/:id","Args":[{"Name":"id","Help":"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."}],"Flags":[{"Name":"city","Field":"city","Type":"json","Help":"City is the stakeholder's city.","Required":false},{"Name":"current-relationship","Field":"currentRelationship","Type":"json","Help":"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.","Required":false},{"Name":"email","Field":"email","Type":"json","Help":"Email is the stakeholder's email. This route stores it as sent — unlike\nadding a stakeholder, it is not checked for shape or uniqueness.","Required":false},{"Name":"institution-name","Field":"institutionName","Type":"json","Help":"InstitutionName names the institution, when the stakeholder is one.","Required":false},{"Name":"name","Field":"name","Type":"json","Help":"Name is the stakeholder's full name.","Required":false},{"Name":"stakeholder-type","Field":"stakeholderType","Type":"json","Help":"StakeholderType is INDIVIDUAL or INSTITUTION. This route stores it as\nsent — unlike adding a stakeholder, it is not checked against the\nvocabulary.","Required":false},{"Name":"state","Field":"state","Type":"json","Help":"State is the stakeholder's state or province.","Required":false},{"Name":"street-address","Field":"streetAddress","Type":"json","Help":"StreetAddress is the stakeholder's street address.","Required":false},{"Name":"tax-id","Field":"taxId","Type":"json","Help":"TaxID is the stakeholder's tax identifier.","Required":false},{"Name":"zipcode","Field":"zipcode","Type":"json","Help":"Zipcode is the stakeholder's postal code.","Required":false}],"Example":null},{"Service":"captable","Name":"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.","Method":"GET","Path":"/v1/captable/summary","Args":[],"Flags":null,"Example":null},{"Service":"catalog","Name":"list","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.","Method":"GET","Path":"/v1/catalog","Args":[],"Flags":[{"Name":"q","Field":"q","Type":"string","Help":"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.","Required":false},{"Name":"org","Field":"org","Type":"string","Help":"Org narrows to one builder org: hanzo | lux | zoo. Case-insensitive.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind narrows to repo | site. Case-insensitive.","Required":false},{"Name":"origin","Field":"origin","Type":"string","Help":"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.","Required":false},{"Name":"archetype","Field":"archetype","Type":"string","Help":"Archetype narrows to one project archetype. Case-insensitive.","Required":false},{"Name":"language","Field":"language","Type":"string","Help":"Language narrows to one implementation language. Case-insensitive.","Required":false},{"Name":"template","Field":"template","Type":"string","Help":"Template narrows a lane to ONE lineage: the id of the parent everything\nreturned was forked from.","Required":false},{"Name":"forkable","Field":"forkable","Type":"string","Help":"Forkable is tri-state: \"true\" selects the forkable rows, \"false\" selects the\nrest, and anything else — including absent — applies no filter at all.","Required":false},{"Name":"limit","Field":"limit","Type":"string","Help":"Limit caps the page at 200, default 50. A value that is not a non-negative\ninteger falls back to the default.","Required":false},{"Name":"offset","Field":"offset","Type":"string","Help":"Offset is where the page starts, default 0, with the same tolerance.","Required":false}],"Example":{"forkable":"true","language":"typescript","limit":"20","origin":"template"}},{"Service":"channel","Name":"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.","Method":"GET","Path":"/v1/channel/agent","Args":[],"Flags":[{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is the transport: discord, github, linear, slack, teams, telegram or whatsapp.\nRequired; an unknown value is a 404.","Required":false}],"Example":null},{"Service":"channel","Name":"agent-update","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.","Method":"PUT","Path":"/v1/channel/agent","Args":[],"Flags":[{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is the transport to edit. Required; an unknown value is a 404.","Required":false},{"Name":"default","Field":"default","Type":"string","Help":"Default sets the agent for rooms with no binding of their own; \"hanzo\"\nrestores the built-in. Empty or absent leaves it unchanged.","Required":false},{"Name":"rooms","Field":"rooms","Type":"json","Help":"Rooms binds platform room ids to agents; rooms not named are left alone.","Required":false},{"Name":"unbind","Field":"unbind","Type":"json","Help":"Unbind removes the bindings of these rooms, so they fall back to Default.","Required":false}],"Example":{"channel":"slack","default":"eng","rooms":{"C024BE91L":"des"},"unbind":["C0OLD"]}},{"Service":"channel","Name":"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.","Method":"GET","Path":"/v1/channel/allowlist","Args":[],"Flags":[{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is the transport to read: discord, github, linear, slack, teams, telegram or whatsapp.\nRequired; an unknown value is a 404.","Required":false}],"Example":{"channel":"slack"}},{"Service":"channel","Name":"allowlist-update","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.","Method":"PUT","Path":"/v1/channel/allowlist","Args":[],"Flags":[{"Name":"access-groups","Field":"accessGroups","Type":"json","Help":"AccessGroups REPLACES the org's named access groups, as\ngroup name -\u003e channel -\u003e entries. Absent or null leaves them alone.","Required":false},{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is the transport to edit: discord, github, linear, slack, teams, telegram or whatsapp.\nRequired; an unknown value is a 404.","Required":false},{"Name":"dm","Field":"dm","Type":"json","Help":"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.","Required":false},{"Name":"dm-policy","Field":"dmPolicy","Type":"string","Help":"DMPolicy sets how direct messages are admitted: \"pairing\" (a person must be\napproved first), \"allowlist\" (only listed senders) or \"open\". Empty leaves\nit unchanged.","Required":false},{"Name":"group","Field":"group","Type":"json","Help":"Group REPLACES the config-managed group allow entries. Absent or null\nleaves them alone; an empty list clears them.","Required":false},{"Name":"group-policy","Field":"groupPolicy","Type":"string","Help":"GroupPolicy sets how group and thread rooms are admitted: \"open\",\n\"allowlist\" or \"disabled\". Empty leaves it unchanged.","Required":false}],"Example":{"channel":"slack","dm":["U024BE7LH"],"dmPolicy":"allowlist"}},{"Service":"channel","Name":"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.","Method":"GET","Path":"/v1/channel/inbox","Args":[],"Flags":[{"Name":"since","Field":"since","Type":"string","Help":"Since is the exclusive cursor: only messages with a higher row id come\nback. Empty starts at the beginning. Must parse as an integer.","Required":false},{"Name":"limit","Field":"limit","Type":"string","Help":"Limit caps how many messages come back. Empty or 0 uses the store's\ndefault page size. Must parse as an integer.","Required":false}],"Example":{"limit":"100","since":"1042"}},{"Service":"channel","Name":"list","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.","Method":"GET","Path":"/v1/channel","Args":[],"Flags":null,"Example":null},{"Service":"channel","Name":"pairing-approve-create","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.","Method":"POST","Path":"/v1/channel/pairing/approve","Args":[],"Flags":[{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is the transport the request came in on: discord, slack, teams,\ntelegram or whatsapp.","Required":false},{"Name":"code","Field":"code","Type":"string","Help":"Code is the pairing code from GET /v1/channel/pairing. It is a capability:\nholding it is what authorises the approval, alongside org admin.","Required":false}],"Example":{"channel":"telegram","code":"PAIR-7Q2M"}},{"Service":"channel","Name":"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.","Method":"GET","Path":"/v1/channel/pairing","Args":[],"Flags":null,"Example":null},{"Service":"channel","Name":"send","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.","Method":"POST","Path":"/v1/channel/:channel/send","Args":[{"Name":"channel","Help":""}],"Flags":null,"Example":null},{"Service":"chat","Name":"completions-create","OperationID":"post_chat_completions","Summary":"Implements the OpenAI-compatible chat completions API","Description":"Implements the OpenAI-compatible chat completions API","Method":"POST","Path":"/v1/chat/completions","Args":[],"Flags":[{"Name":"frequency-penalty","Field":"frequency_penalty","Type":"number","Help":"","Required":false},{"Name":"function-call","Field":"function_call","Type":"json","Help":"","Required":false},{"Name":"functions","Field":"functions","Type":"json","Help":"","Required":false},{"Name":"logit-bias","Field":"logit_bias","Type":"json","Help":"","Required":false},{"Name":"logprobs","Field":"logprobs","Type":"boolean","Help":"","Required":false},{"Name":"max-completion-tokens","Field":"max_completion_tokens","Type":"integer","Help":"","Required":false},{"Name":"max-tokens","Field":"max_tokens","Type":"integer","Help":"","Required":false},{"Name":"messages","Field":"messages","Type":"json","Help":"","Required":false},{"Name":"metadata","Field":"metadata","Type":"json","Help":"","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"","Required":false},{"Name":"n","Field":"n","Type":"integer","Help":"","Required":false},{"Name":"parallel-tool-calls","Field":"parallel_tool_calls","Type":"json","Help":"","Required":false},{"Name":"presence-penalty","Field":"presence_penalty","Type":"number","Help":"","Required":false},{"Name":"reasoning-effort","Field":"reasoning_effort","Type":"string","Help":"","Required":false},{"Name":"response-format","Field":"response_format","Type":"json","Help":"","Required":false},{"Name":"seed","Field":"seed","Type":"integer","Help":"","Required":false},{"Name":"stop","Field":"stop","Type":"json","Help":"","Required":false},{"Name":"store","Field":"store","Type":"boolean","Help":"","Required":false},{"Name":"stream","Field":"stream","Type":"boolean","Help":"","Required":false},{"Name":"stream-options","Field":"stream_options","Type":"json","Help":"","Required":false},{"Name":"temperature","Field":"temperature","Type":"number","Help":"","Required":false},{"Name":"tool-choice","Field":"tool_choice","Type":"json","Help":"","Required":false},{"Name":"tools","Field":"tools","Type":"json","Help":"","Required":false},{"Name":"top-logprobs","Field":"top_logprobs","Type":"integer","Help":"","Required":false},{"Name":"top-p","Field":"top_p","Type":"number","Help":"","Required":false},{"Name":"user","Field":"user","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"chat","Name":"create","OperationID":"post_chat","Summary":"Implements the OpenAI-compatible chat completions API","Description":"Implements the OpenAI-compatible chat completions API","Method":"POST","Path":"/v1/chat","Args":[],"Flags":[{"Name":"frequency-penalty","Field":"frequency_penalty","Type":"number","Help":"","Required":false},{"Name":"function-call","Field":"function_call","Type":"json","Help":"","Required":false},{"Name":"functions","Field":"functions","Type":"json","Help":"","Required":false},{"Name":"logit-bias","Field":"logit_bias","Type":"json","Help":"","Required":false},{"Name":"logprobs","Field":"logprobs","Type":"boolean","Help":"","Required":false},{"Name":"max-completion-tokens","Field":"max_completion_tokens","Type":"integer","Help":"","Required":false},{"Name":"max-tokens","Field":"max_tokens","Type":"integer","Help":"","Required":false},{"Name":"messages","Field":"messages","Type":"json","Help":"","Required":false},{"Name":"metadata","Field":"metadata","Type":"json","Help":"","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"","Required":false},{"Name":"n","Field":"n","Type":"integer","Help":"","Required":false},{"Name":"parallel-tool-calls","Field":"parallel_tool_calls","Type":"json","Help":"","Required":false},{"Name":"presence-penalty","Field":"presence_penalty","Type":"number","Help":"","Required":false},{"Name":"reasoning-effort","Field":"reasoning_effort","Type":"string","Help":"","Required":false},{"Name":"response-format","Field":"response_format","Type":"json","Help":"","Required":false},{"Name":"seed","Field":"seed","Type":"integer","Help":"","Required":false},{"Name":"stop","Field":"stop","Type":"json","Help":"","Required":false},{"Name":"store","Field":"store","Type":"boolean","Help":"","Required":false},{"Name":"stream","Field":"stream","Type":"boolean","Help":"","Required":false},{"Name":"stream-options","Field":"stream_options","Type":"json","Help":"","Required":false},{"Name":"temperature","Field":"temperature","Type":"number","Help":"","Required":false},{"Name":"tool-choice","Field":"tool_choice","Type":"json","Help":"","Required":false},{"Name":"tools","Field":"tools","Type":"json","Help":"","Required":false},{"Name":"top-logprobs","Field":"top_logprobs","Type":"integer","Help":"","Required":false},{"Name":"top-p","Field":"top_p","Type":"number","Help":"","Required":false},{"Name":"user","Field":"user","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"chat","Name":"public-create","OperationID":"post_chat_public","Summary":"Serves one completion to a caller with no account.","Description":"Serves one completion to a caller with no account.","Method":"POST","Path":"/v1/chat/public","Args":[],"Flags":[{"Name":"frequency-penalty","Field":"frequency_penalty","Type":"number","Help":"","Required":false},{"Name":"function-call","Field":"function_call","Type":"json","Help":"","Required":false},{"Name":"functions","Field":"functions","Type":"json","Help":"","Required":false},{"Name":"logit-bias","Field":"logit_bias","Type":"json","Help":"","Required":false},{"Name":"logprobs","Field":"logprobs","Type":"boolean","Help":"","Required":false},{"Name":"max-completion-tokens","Field":"max_completion_tokens","Type":"integer","Help":"","Required":false},{"Name":"max-tokens","Field":"max_tokens","Type":"integer","Help":"","Required":false},{"Name":"messages","Field":"messages","Type":"json","Help":"","Required":false},{"Name":"metadata","Field":"metadata","Type":"json","Help":"","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"","Required":false},{"Name":"n","Field":"n","Type":"integer","Help":"","Required":false},{"Name":"parallel-tool-calls","Field":"parallel_tool_calls","Type":"json","Help":"","Required":false},{"Name":"presence-penalty","Field":"presence_penalty","Type":"number","Help":"","Required":false},{"Name":"reasoning-effort","Field":"reasoning_effort","Type":"string","Help":"","Required":false},{"Name":"response-format","Field":"response_format","Type":"json","Help":"","Required":false},{"Name":"seed","Field":"seed","Type":"integer","Help":"","Required":false},{"Name":"stop","Field":"stop","Type":"json","Help":"","Required":false},{"Name":"store","Field":"store","Type":"boolean","Help":"","Required":false},{"Name":"stream","Field":"stream","Type":"boolean","Help":"","Required":false},{"Name":"stream-options","Field":"stream_options","Type":"json","Help":"","Required":false},{"Name":"temperature","Field":"temperature","Type":"number","Help":"","Required":false},{"Name":"tool-choice","Field":"tool_choice","Type":"json","Help":"","Required":false},{"Name":"tools","Field":"tools","Type":"json","Help":"","Required":false},{"Name":"top-logprobs","Field":"top_logprobs","Type":"integer","Help":"","Required":false},{"Name":"top-p","Field":"top_p","Type":"number","Help":"","Required":false},{"Name":"user","Field":"user","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"ci","Name":"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.","Method":"GET","Path":"/v1/ci/fleet","Args":[],"Flags":null,"Example":null},{"Service":"ci","Name":"runs-list","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.","Method":"GET","Path":"/v1/ci/runs","Args":[],"Flags":null,"Example":null},{"Service":"cloudflare","Name":"d1-databases-create","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.","Method":"POST","Path":"/v1/cloudflare/d1/databases","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"Name is the database name to create.","Required":false}],"Example":{"name":"orders"}},{"Service":"cloudflare","Name":"d1-databases-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.","Method":"DELETE","Path":"/v1/cloudflare/d1/databases/:database","Args":[{"Name":"database","Help":"Database is the Cloudflare D1 database id or name."}],"Flags":null,"Example":{"database":"orders"}},{"Service":"cloudflare","Name":"d1-databases-list","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.","Method":"GET","Path":"/v1/cloudflare/d1/databases","Args":[],"Flags":[{"Name":"page","Field":"page","Type":"string","Help":"Page is the 1-based page of databases to return.","Required":false},{"Name":"per-page","Field":"per_page","Type":"string","Help":"PerPage is how many databases one page holds.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name filters to the database with this name.","Required":false}],"Example":null},{"Service":"cloudflare","Name":"d1-databases-query","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.","Method":"POST","Path":"/v1/cloudflare/d1/databases/:database/query","Args":[{"Name":"database","Help":""}],"Flags":[{"Name":"params","Field":"params","Type":"json","Help":"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.","Required":false},{"Name":"sql","Field":"sql","Type":"string","Help":"SQL is the statement to run. Blank (or absent) is refused before anything\nreaches D1.","Required":false}],"Example":{"params":[42],"sql":"SELECT * FROM orders WHERE id = ?"}},{"Service":"cloudflare","Name":"kv-namespaces-create","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.","Method":"POST","Path":"/v1/cloudflare/kv/namespaces","Args":[],"Flags":[{"Name":"title","Field":"title","Type":"string","Help":"Title is the namespace's display title. Cloudflare mints the id.","Required":false}],"Example":{"title":"sessions"}},{"Service":"cloudflare","Name":"kv-namespaces-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.","Method":"DELETE","Path":"/v1/cloudflare/kv/namespaces/:namespace","Args":[{"Name":"namespace","Help":"Namespace is the Cloudflare KV namespace id."}],"Flags":null,"Example":{"namespace":"0123456789abcdef0123456789abcdef"}},{"Service":"cloudflare","Name":"kv-namespaces-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.","Method":"DELETE","Path":"/v1/cloudflare/kv/namespaces/:namespace/values/:key","Args":[{"Name":"namespace","Help":"Namespace is the Cloudflare KV namespace id."},{"Name":"key","Help":"Key is the key within that namespace. KV keys are broad (up to 512 bytes),\nso this one is escaped rather than charset-restricted."}],"Flags":null,"Example":{"key":"session/abc","namespace":"0123456789abcdef0123456789abcdef"}},{"Service":"cloudflare","Name":"kv-namespaces-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.","Method":"GET","Path":"/v1/cloudflare/kv/namespaces/:namespace/values/:key","Args":[{"Name":"namespace","Help":""},{"Name":"key","Help":""}],"Flags":null,"Example":null},{"Service":"cloudflare","Name":"kv-namespaces-list","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.","Method":"GET","Path":"/v1/cloudflare/kv/namespaces","Args":[],"Flags":[{"Name":"page","Field":"page","Type":"string","Help":"Page is the 1-based page of namespaces to return.","Required":false},{"Name":"per-page","Field":"per_page","Type":"string","Help":"PerPage is how many namespaces one page holds.","Required":false},{"Name":"order","Field":"order","Type":"string","Help":"Order names the field to sort by, and Direction sorts asc or desc.","Required":false},{"Name":"direction","Field":"direction","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"cloudflare","Name":"kv-namespaces-update","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.","Method":"PUT","Path":"/v1/cloudflare/kv/namespaces/:namespace/values/:key","Args":[{"Name":"namespace","Help":""},{"Name":"key","Help":""}],"Flags":null,"Example":null},{"Service":"cloudflare","Name":"pages-projects-create","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.","Method":"POST","Path":"/v1/cloudflare/pages/projects","Args":[],"Flags":[{"Name":"build-config","Field":"build_config","Type":"json","Help":"BuildConfig says how to build the site. Omitted means no build step.","Required":false},{"Name":"deployment-configs","Field":"deployment_configs","Type":"json","Help":"DeploymentConfigs carries the preview and production runtime configs — the\nbindings and variables the built site's functions run with.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false},{"Name":"production-branch","Field":"production_branch","Type":"string","Help":"ProductionBranch is which git branch builds to production; every other branch\nbuilds a preview. Omitted leaves Cloudflare's own default.","Required":false}],"Example":{"name":"marketing-site","production_branch":"main"}},{"Service":"cloudflare","Name":"pages-projects-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.","Method":"DELETE","Path":"/v1/cloudflare/pages/projects/:project","Args":[{"Name":"project","Help":"Project is the Pages project name."}],"Flags":null,"Example":{"project":"marketing-site"}},{"Service":"cloudflare","Name":"pages-projects-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.","Method":"DELETE","Path":"/v1/cloudflare/pages/projects/:project/domains/:domain","Args":[{"Name":"project","Help":"Project is the Pages project name."},{"Name":"domain","Help":"Domain is the attached custom domain to detach."}],"Flags":null,"Example":{"domain":"www.acme.com","project":"marketing-site"}},{"Service":"cloudflare","Name":"pages-projects-deployments","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.","Method":"POST","Path":"/v1/cloudflare/pages/projects/:project/deployments","Args":[{"Name":"project","Help":""}],"Flags":[{"Name":"branch","Field":"branch","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"cloudflare","Name":"pages-projects-domains","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.","Method":"POST","Path":"/v1/cloudflare/pages/projects/:project/domains","Args":[{"Name":"project","Help":"Project is the Pages project name, from the path."}],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"Name is the custom domain to attach, e.g. \"www.acme.com\".","Required":false}],"Example":{"name":"www.acme.com","project":"marketing-site"}},{"Service":"cloudflare","Name":"pages-projects-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.","Method":"GET","Path":"/v1/cloudflare/pages/projects/:project","Args":[{"Name":"project","Help":"Project is the Pages project name."}],"Flags":null,"Example":{"project":"marketing-site"}},{"Service":"cloudflare","Name":"pages-projects-list","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.","Method":"GET","Path":"/v1/cloudflare/pages/projects","Args":[],"Flags":null,"Example":null},{"Service":"cloudflare","Name":"r2-buckets-create","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.","Method":"POST","Path":"/v1/cloudflare/r2/buckets","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"Name is the bucket name to create.","Required":false}],"Example":{"name":"assets"}},{"Service":"cloudflare","Name":"r2-buckets-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.","Method":"DELETE","Path":"/v1/cloudflare/r2/buckets/:bucket","Args":[{"Name":"bucket","Help":"Bucket is the R2 bucket name."}],"Flags":null,"Example":{"bucket":"assets"}},{"Service":"cloudflare","Name":"r2-buckets-list","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.","Method":"GET","Path":"/v1/cloudflare/r2/buckets","Args":[],"Flags":[{"Name":"per-page","Field":"per_page","Type":"string","Help":"PerPage is how many buckets one page holds.","Required":false},{"Name":"cursor","Field":"cursor","Type":"string","Help":"Cursor continues from the position a previous page returned.","Required":false},{"Name":"name-contains","Field":"name_contains","Type":"string","Help":"NameContains filters to buckets whose name contains this substring.","Required":false},{"Name":"order","Field":"order","Type":"string","Help":"Order names the field to sort by, and Direction sorts asc or desc.","Required":false},{"Name":"direction","Field":"direction","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"cloudflare","Name":"workers-scripts-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.","Method":"DELETE","Path":"/v1/cloudflare/workers/scripts/:script","Args":[{"Name":"script","Help":"Script is the Worker script name."}],"Flags":null,"Example":{"script":"edge-router"}},{"Service":"cloudflare","Name":"workers-scripts-list","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.","Method":"GET","Path":"/v1/cloudflare/workers/scripts","Args":[],"Flags":null,"Example":null},{"Service":"cloudflare","Name":"workers-scripts-subdomain","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.","Method":"POST","Path":"/v1/cloudflare/workers/scripts/:script/subdomain","Args":[{"Name":"script","Help":"Script is the Worker script name, from the path."}],"Flags":[{"Name":"enabled","Field":"enabled","Type":"boolean","Help":"Enabled publishes the script on \u003cscript\u003e.\u003csubdomain\u003e.workers.dev when true,\nand withdraws it when false.","Required":false}],"Example":{"enabled":true,"script":"edge-router"}},{"Service":"cloudflare","Name":"workers-scripts-update","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.","Method":"PUT","Path":"/v1/cloudflare/workers/scripts/:script","Args":[{"Name":"script","Help":"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."}],"Flags":[{"Name":"bindings","Field":"bindings","Type":"json","Help":"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.","Required":false},{"Name":"compatibility-date","Field":"compatibilityDate","Type":"string","Help":"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.","Required":false},{"Name":"compatibility-flags","Field":"compatibilityFlags","Type":"json","Help":"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.","Required":false},{"Name":"main-module","Field":"mainModule","Type":"string","Help":"MainModule is the module file the runtime starts at. Absent means \"worker.js\".","Required":false}],"Example":null},{"Service":"cloudflare","Name":"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.","Method":"GET","Path":"/v1/cloudflare/workers/subdomain","Args":[],"Flags":null,"Example":null},{"Service":"cloudflare","Name":"workers-zones-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.","Method":"DELETE","Path":"/v1/cloudflare/workers/zones/:zone/routes/:route","Args":[{"Name":"zone","Help":"Zone is the 32-hex Cloudflare zone id."},{"Name":"route","Help":"Route is the 32-hex Cloudflare route id."}],"Flags":null,"Example":{"route":"fedcba9876543210fedcba9876543210","zone":"0123456789abcdef0123456789abcdef"}},{"Service":"cloudflare","Name":"workers-zones-routes","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.","Method":"POST","Path":"/v1/cloudflare/workers/zones/:zone/routes","Args":[{"Name":"zone","Help":"Zone is the 32-hex Cloudflare zone id, from the path."}],"Flags":[{"Name":"pattern","Field":"pattern","Type":"string","Help":"Pattern is the URL pattern to bind, e.g. \"acme.com/api/*\".","Required":false},{"Name":"script","Field":"script","Type":"string","Help":"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\".","Required":false}],"Example":{"pattern":"acme.com/api/*","script":"edge-router","zone":"0123456789abcdef0123456789abcdef"}},{"Service":"cloudflare","Name":"workers-zones-routes-list","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.","Method":"GET","Path":"/v1/cloudflare/workers/zones/:zone/routes","Args":[{"Name":"zone","Help":"Zone is the 32-hex Cloudflare zone id."}],"Flags":null,"Example":{"zone":"0123456789abcdef0123456789abcdef"}},{"Service":"cloudflare","Name":"zones-analytics-list","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.","Method":"GET","Path":"/v1/cloudflare/zones/:zone/analytics","Args":[{"Name":"zone","Help":"Zone is the 32-hex Cloudflare zone id."}],"Flags":[{"Name":"since","Field":"since","Type":"string","Help":"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).","Required":false},{"Name":"until","Field":"until","Type":"string","Help":"","Required":false},{"Name":"continuous","Field":"continuous","Type":"string","Help":"Continuous asks Cloudflare for only fully-aggregated buckets.","Required":false}],"Example":{"since":"-1440","until":"0","zone":"0123456789abcdef0123456789abcdef"}},{"Service":"cloudflare","Name":"zones-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.","Method":"GET","Path":"/v1/cloudflare/zones/:zone","Args":[{"Name":"zone","Help":"Zone is the 32-hex Cloudflare zone id."}],"Flags":null,"Example":{"zone":"0123456789abcdef0123456789abcdef"}},{"Service":"cloudflare","Name":"zones-list","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.","Method":"GET","Path":"/v1/cloudflare/zones","Args":[],"Flags":[{"Name":"page","Field":"page","Type":"string","Help":"Page is the 1-based page of zones to return.","Required":false},{"Name":"per-page","Field":"per_page","Type":"string","Help":"PerPage is how many zones one page holds.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name filters to the zone with this domain name.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status filters by zone status (active, pending, initializing, …).","Required":false},{"Name":"order","Field":"order","Type":"string","Help":"Order names the field to sort by, and Direction sorts asc or desc.","Required":false},{"Name":"direction","Field":"direction","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"cloudflare","Name":"zones-purge","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.","Method":"POST","Path":"/v1/cloudflare/zones/:zone/purge","Args":[{"Name":"zone","Help":"Zone is the 32-hex Cloudflare zone id, from the path."}],"Flags":[{"Name":"files","Field":"files","Type":"json","Help":"Files purges exactly the listed URLs — at most 30, Cloudflare's per-request cap.","Required":false},{"Name":"purge-everything","Field":"purge_everything","Type":"boolean","Help":"Everything drops the zone's entire edge cache.","Required":false}],"Example":{"purge_everything":true,"zone":"0123456789abcdef0123456789abcdef"}},{"Service":"code","Name":"ask-create","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.","Method":"POST","Path":"/v1/code/ask","Args":[],"Flags":[{"Name":"query","Field":"query","Type":"string","Help":"Query is the question, from the BODY. Takes precedence over `?q=`.","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"Repo is the repository narrowing, from the BODY. Takes precedence over `?repo=`.","Required":false}],"Example":{"query":"where is the per-org SQLite file opened","repo":"cloud"}},{"Service":"code","Name":"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.","Method":"GET","Path":"/v1/code/ask","Args":[],"Flags":[{"Name":"q","Field":"q","Type":"string","Help":"Q is the question to answer. Required, max 4000 bytes.","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"Repo narrows retrieval to one repository. Empty searches every repo the org\nhas indexed.","Required":false}],"Example":{"q":"where is the per-org SQLite file opened","repo":"cloud"}},{"Service":"code","Name":"context-create","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.","Method":"POST","Path":"/v1/code/context","Args":[],"Flags":[{"Name":"budget-tokens","Field":"budgetTokens","Type":"integer","Help":"BudgetTokens caps the bundle's size. Clamped to [256, 32000]; 0 or absent\nuses 4000.","Required":false},{"Name":"query","Field":"query","Type":"string","Help":"Query is what to retrieve context for. Required, max 4000 bytes.","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"Repo narrows retrieval to one repository. Empty searches every repo the org\nhas indexed.","Required":false}],"Example":{"budgetTokens":4000,"query":"how does the store open a per-org database","repo":"cloud"}},{"Service":"code","Name":"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\".","Method":"GET","Path":"/v1/code/file","Args":[],"Flags":[{"Name":"path","Field":"path","Type":"string","Help":"Path is the file's repo-relative path. Required.","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"Repo is the repository the file belongs to. REQUIRED.","Required":false}],"Example":{"path":"apps/code/store.go","repo":"cloud"}},{"Service":"code","Name":"index-create","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.","Method":"POST","Path":"/v1/code/index","Args":[],"Flags":[{"Name":"files","Field":"files","Type":"json","Help":"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.","Required":false},{"Name":"prune","Field":"prune","Type":"boolean","Help":"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.","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"Repo is the repository label to index under. Required, max 200 bytes. It is\na stored column value, not a filesystem path.","Required":false}],"Example":{"files":[{"content":"package main\n","path":"main.go"}],"prune":true,"repo":"cloud"}},{"Service":"code","Name":"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.","Method":"GET","Path":"/v1/code/search","Args":[],"Flags":[{"Name":"q","Field":"q","Type":"string","Help":"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.","Required":false},{"Name":"type","Field":"type","Type":"string","Help":"Type selects the retrieval tier: \"text\" (FTS5 trigram), \"regex\",\n\"symbol\" (definitions), \"semantic\" (embeddings) or \"hybrid\". Anything\nelse — including empty — reads as hybrid.","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"Repo narrows to one repository. Empty searches every repo the org has indexed.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many spans come back: default 20, maximum 100. A value that\nis not a positive integer reads as the default.","Required":false}],"Example":{"limit":20,"q":"func openStore","repo":"cloud","type":"hybrid"}},{"Service":"code","Name":"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.","Method":"GET","Path":"/v1/code/tree","Args":[],"Flags":[{"Name":"repo","Field":"repo","Type":"string","Help":"Repo is the repository to walk. REQUIRED — a tree is repo-scoped.","Required":false}],"Example":{"repo":"cloud"}},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/catalog","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"catalog-models-create","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.","Method":"POST","Path":"/v1/commerce/catalog/models","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"catalog-models-refresh-create","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.","Method":"POST","Path":"/v1/commerce/catalog/models/refresh","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"collection-create","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.","Method":"POST","Path":"/v1/commerce/collection","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"collection-create","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.","Method":"POST","Path":"/v1/commerce/collection/:collectionid","Args":[{"Name":"collectionid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"collection-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.","Method":"DELETE","Path":"/v1/commerce/collection/:collectionid","Args":[{"Name":"collectionid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/collection","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"collection-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.","Method":"GET","Path":"/v1/commerce/collection/:collectionid","Args":[{"Name":"collectionid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"collection-update","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.","Method":"PATCH","Path":"/v1/commerce/collection/:collectionid","Args":[{"Name":"collectionid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"collection-update","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.","Method":"PUT","Path":"/v1/commerce/collection/:collectionid","Args":[{"Name":"collectionid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"currencies-list","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.","Method":"GET","Path":"/v1/commerce/currencies","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"discard-cart","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.","Method":"POST","Path":"/v1/commerce/cart/:id/discard","Args":[{"Name":"id","Help":"ID is the cart's id, as the open call answered it."}],"Flags":null,"Example":null},{"Service":"commerce","Name":"disclosure-create","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.","Method":"POST","Path":"/v1/commerce/disclosure","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"disclosure-create","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.","Method":"POST","Path":"/v1/commerce/disclosure/:disclosureid","Args":[{"Name":"disclosureid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"disclosure-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.","Method":"DELETE","Path":"/v1/commerce/disclosure/:disclosureid","Args":[{"Name":"disclosureid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/disclosure","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"disclosure-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.","Method":"GET","Path":"/v1/commerce/disclosure/:disclosureid","Args":[{"Name":"disclosureid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"disclosure-update","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.","Method":"PATCH","Path":"/v1/commerce/disclosure/:disclosureid","Args":[{"Name":"disclosureid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"disclosure-update","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.","Method":"PUT","Path":"/v1/commerce/disclosure/:disclosureid","Args":[{"Name":"disclosureid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"discount-create","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.","Method":"POST","Path":"/v1/commerce/discount","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"discount-create","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.","Method":"POST","Path":"/v1/commerce/discount/:discountid","Args":[{"Name":"discountid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"discount-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.","Method":"DELETE","Path":"/v1/commerce/discount/:discountid","Args":[{"Name":"discountid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/discount","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"discount-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.","Method":"GET","Path":"/v1/commerce/discount/:discountid","Args":[{"Name":"discountid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"discount-update","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.","Method":"PATCH","Path":"/v1/commerce/discount/:discountid","Args":[{"Name":"discountid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"discount-update","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.","Method":"PUT","Path":"/v1/commerce/discount/:discountid","Args":[{"Name":"discountid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"get-cart","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.","Method":"GET","Path":"/v1/commerce/cart/:id","Args":[{"Name":"id","Help":"ID is the cart's id, as the open call answered it."}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/health","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"movie-create","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.","Method":"POST","Path":"/v1/commerce/movie","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"movie-create","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.","Method":"POST","Path":"/v1/commerce/movie/:movieid","Args":[{"Name":"movieid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"movie-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.","Method":"DELETE","Path":"/v1/commerce/movie/:movieid","Args":[{"Name":"movieid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/movie","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"movie-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.","Method":"GET","Path":"/v1/commerce/movie/:movieid","Args":[{"Name":"movieid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"movie-update","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.","Method":"PATCH","Path":"/v1/commerce/movie/:movieid","Args":[{"Name":"movieid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"movie-update","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.","Method":"PUT","Path":"/v1/commerce/movie/:movieid","Args":[{"Name":"movieid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"note-create","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.","Method":"POST","Path":"/v1/commerce/note","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"note-create","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.","Method":"POST","Path":"/v1/commerce/note/:noteid","Args":[{"Name":"noteid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"note-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.","Method":"DELETE","Path":"/v1/commerce/note/:noteid","Args":[{"Name":"noteid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/note","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"note-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.","Method":"GET","Path":"/v1/commerce/note/:noteid","Args":[{"Name":"noteid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"note-update","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.","Method":"PATCH","Path":"/v1/commerce/note/:noteid","Args":[{"Name":"noteid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"note-update","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.","Method":"PUT","Path":"/v1/commerce/note/:noteid","Args":[{"Name":"noteid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"open-cart","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.","Method":"POST","Path":"/v1/commerce/cart","Args":[],"Flags":[{"Name":"currency","Field":"currency","Type":"string","Help":"Currency is the ISO 4217 code the cart is priced in, lower-cased. Empty\nmeans usd.","Required":false},{"Name":"email","Field":"email","Type":"string","Help":"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.","Required":false},{"Name":"store","Field":"store","Type":"string","Help":"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.","Required":false},{"Name":"user","Field":"user","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/org","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"product-create","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.","Method":"POST","Path":"/v1/commerce/product","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"product-create","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.","Method":"POST","Path":"/v1/commerce/product/:productid","Args":[{"Name":"productid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"product-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.","Method":"DELETE","Path":"/v1/commerce/product/:productid","Args":[{"Name":"productid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/product","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"product-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.","Method":"GET","Path":"/v1/commerce/product/:productid","Args":[{"Name":"productid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"product-update","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.","Method":"PATCH","Path":"/v1/commerce/product/:productid","Args":[{"Name":"productid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"product-update","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.","Method":"PUT","Path":"/v1/commerce/product/:productid","Args":[{"Name":"productid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"return-create","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.","Method":"POST","Path":"/v1/commerce/return","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"return-create","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.","Method":"POST","Path":"/v1/commerce/return/:returnid","Args":[{"Name":"returnid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"return-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.","Method":"DELETE","Path":"/v1/commerce/return/:returnid","Args":[{"Name":"returnid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/return","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"return-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.","Method":"GET","Path":"/v1/commerce/return/:returnid","Args":[{"Name":"returnid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"return-update","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.","Method":"PATCH","Path":"/v1/commerce/return/:returnid","Args":[{"Name":"returnid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"return-update","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.","Method":"PUT","Path":"/v1/commerce/return/:returnid","Args":[{"Name":"returnid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"saleschannel-create","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.","Method":"POST","Path":"/v1/commerce/saleschannel","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"saleschannel-create","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.","Method":"POST","Path":"/v1/commerce/saleschannel/:saleschannelid","Args":[{"Name":"saleschannelid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"saleschannel-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.","Method":"DELETE","Path":"/v1/commerce/saleschannel/:saleschannelid","Args":[{"Name":"saleschannelid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/saleschannel","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"saleschannel-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.","Method":"GET","Path":"/v1/commerce/saleschannel/:saleschannelid","Args":[{"Name":"saleschannelid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"saleschannel-update","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.","Method":"PATCH","Path":"/v1/commerce/saleschannel/:saleschannelid","Args":[{"Name":"saleschannelid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"saleschannel-update","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.","Method":"PUT","Path":"/v1/commerce/saleschannel/:saleschannelid","Args":[{"Name":"saleschannelid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"set-cart-item","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.","Method":"POST","Path":"/v1/commerce/cart/:id/item","Args":[{"Name":"id","Help":"ID is the cart to amend, from the path."}],"Flags":[{"Name":"product","Field":"product","Type":"string","Help":"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.","Required":false},{"Name":"quantity","Field":"quantity","Type":"integer","Help":"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.","Required":false},{"Name":"variant","Field":"variant","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"commerce","Name":"stocklocation-create","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.","Method":"POST","Path":"/v1/commerce/stocklocation","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"stocklocation-create","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.","Method":"POST","Path":"/v1/commerce/stocklocation/:stocklocationid","Args":[{"Name":"stocklocationid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"stocklocation-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.","Method":"DELETE","Path":"/v1/commerce/stocklocation/:stocklocationid","Args":[{"Name":"stocklocationid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/stocklocation","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"stocklocation-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.","Method":"GET","Path":"/v1/commerce/stocklocation/:stocklocationid","Args":[{"Name":"stocklocationid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"stocklocation-update","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.","Method":"PATCH","Path":"/v1/commerce/stocklocation/:stocklocationid","Args":[{"Name":"stocklocationid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"stocklocation-update","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.","Method":"PUT","Path":"/v1/commerce/stocklocation/:stocklocationid","Args":[{"Name":"stocklocationid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/store/access","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-authorize","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.","Method":"POST","Path":"/v1/commerce/store/:storeid/authorize","Args":[{"Name":"storeid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-charge","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.","Method":"POST","Path":"/v1/commerce/store/:storeid/charge","Args":[{"Name":"storeid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-checkout-authorize","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.","Method":"POST","Path":"/v1/commerce/store/:storeid/checkout/authorize","Args":[{"Name":"storeid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-checkout-charge","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.","Method":"POST","Path":"/v1/commerce/store/:storeid/checkout/charge","Args":[{"Name":"storeid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-checkout-paypal-pay","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.","Method":"POST","Path":"/v1/commerce/store/:storeid/checkout/paypal/pay","Args":[{"Name":"storeid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-create","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.","Method":"POST","Path":"/v1/commerce/store","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-create","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.","Method":"POST","Path":"/v1/commerce/store/:storeid","Args":[{"Name":"storeid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-create","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.","Method":"POST","Path":"/v1/commerce/store/:storeid/authorize/:orderid","Args":[{"Name":"storeid","Help":""},{"Name":"orderid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-create","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.","Method":"POST","Path":"/v1/commerce/store/:storeid/capture/:orderid","Args":[{"Name":"storeid","Help":""},{"Name":"orderid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-create","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.","Method":"POST","Path":"/v1/commerce/store/:storeid/checkout/authorize/:orderid","Args":[{"Name":"storeid","Help":""},{"Name":"orderid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-create","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.","Method":"POST","Path":"/v1/commerce/store/:storeid/checkout/capture/:orderid","Args":[{"Name":"storeid","Help":""},{"Name":"orderid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-create","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.","Method":"POST","Path":"/v1/commerce/store/:storeid/checkout/paypal/cancel/:payKey","Args":[{"Name":"storeid","Help":""},{"Name":"payKey","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-create","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.","Method":"POST","Path":"/v1/commerce/store/:storeid/checkout/paypal/confirm/:payKey","Args":[{"Name":"storeid","Help":""},{"Name":"payKey","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-create","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.","Method":"POST","Path":"/v1/commerce/store/:storeid/listing/:key","Args":[{"Name":"storeid","Help":""},{"Name":"key","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-create","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.","Method":"POST","Path":"/v1/commerce/store/:storeid/paypal/cancel/:payKey","Args":[{"Name":"storeid","Help":""},{"Name":"payKey","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-create","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.","Method":"POST","Path":"/v1/commerce/store/:storeid/paypal/confirm/:payKey","Args":[{"Name":"storeid","Help":""},{"Name":"payKey","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/store/current","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-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.","Method":"DELETE","Path":"/v1/commerce/store/:storeid","Args":[{"Name":"storeid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-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.","Method":"DELETE","Path":"/v1/commerce/store/:storeid/listing/:key","Args":[{"Name":"storeid","Help":""},{"Name":"key","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/store","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-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.","Method":"GET","Path":"/v1/commerce/store/:storeid","Args":[{"Name":"storeid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-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.","Method":"GET","Path":"/v1/commerce/store/:storeid/bundle/:key","Args":[{"Name":"storeid","Help":""},{"Name":"key","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-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.","Method":"GET","Path":"/v1/commerce/store/:storeid/listing/:key","Args":[{"Name":"storeid","Help":""},{"Name":"key","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-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.","Method":"GET","Path":"/v1/commerce/store/:storeid/product/:key","Args":[{"Name":"storeid","Help":""},{"Name":"key","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-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.","Method":"GET","Path":"/v1/commerce/store/:storeid/variant/:key","Args":[{"Name":"storeid","Help":""},{"Name":"key","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-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.","Method":"GET","Path":"/v1/commerce/store/:storeid/listing","Args":[{"Name":"storeid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-paypal-pay","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.","Method":"POST","Path":"/v1/commerce/store/:storeid/paypal/pay","Args":[{"Name":"storeid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-token-create","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.","Method":"POST","Path":"/v1/commerce/store/token","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-trial","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.","Method":"POST","Path":"/v1/commerce/store/:storeid/trial","Args":[{"Name":"storeid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-update","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.","Method":"PATCH","Path":"/v1/commerce/store/:storeid","Args":[{"Name":"storeid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-update","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.","Method":"PATCH","Path":"/v1/commerce/store/:storeid/listing/:key","Args":[{"Name":"storeid","Help":""},{"Name":"key","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-update","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.","Method":"PUT","Path":"/v1/commerce/store/:storeid","Args":[{"Name":"storeid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"store-update","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.","Method":"PUT","Path":"/v1/commerce/store/:storeid/listing/:key","Args":[{"Name":"storeid","Help":""},{"Name":"key","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"submission-create","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.","Method":"POST","Path":"/v1/commerce/submission","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"submission-create","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.","Method":"POST","Path":"/v1/commerce/submission/:submissionid","Args":[{"Name":"submissionid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"submission-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.","Method":"DELETE","Path":"/v1/commerce/submission/:submissionid","Args":[{"Name":"submissionid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/submission","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"submission-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.","Method":"GET","Path":"/v1/commerce/submission/:submissionid","Args":[{"Name":"submissionid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"submission-update","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.","Method":"PATCH","Path":"/v1/commerce/submission/:submissionid","Args":[{"Name":"submissionid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"submission-update","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.","Method":"PUT","Path":"/v1/commerce/submission/:submissionid","Args":[{"Name":"submissionid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"subscriber-create","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.","Method":"POST","Path":"/v1/commerce/subscriber","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"subscriber-create","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.","Method":"POST","Path":"/v1/commerce/subscriber/:subscriberid","Args":[{"Name":"subscriberid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"subscriber-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.","Method":"DELETE","Path":"/v1/commerce/subscriber/:subscriberid","Args":[{"Name":"subscriberid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/subscriber","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"subscriber-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.","Method":"GET","Path":"/v1/commerce/subscriber/:subscriberid","Args":[{"Name":"subscriberid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"subscriber-update","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.","Method":"PATCH","Path":"/v1/commerce/subscriber/:subscriberid","Args":[{"Name":"subscriberid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"subscriber-update","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.","Method":"PUT","Path":"/v1/commerce/subscriber/:subscriberid","Args":[{"Name":"subscriberid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"tokentransaction-create","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.","Method":"POST","Path":"/v1/commerce/tokentransaction","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"tokentransaction-create","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.","Method":"POST","Path":"/v1/commerce/tokentransaction/:tokentransactionid","Args":[{"Name":"tokentransactionid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"tokentransaction-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.","Method":"DELETE","Path":"/v1/commerce/tokentransaction/:tokentransactionid","Args":[{"Name":"tokentransactionid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/tokentransaction","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"tokentransaction-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.","Method":"GET","Path":"/v1/commerce/tokentransaction/:tokentransactionid","Args":[{"Name":"tokentransactionid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"tokentransaction-update","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.","Method":"PATCH","Path":"/v1/commerce/tokentransaction/:tokentransactionid","Args":[{"Name":"tokentransactionid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"tokentransaction-update","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.","Method":"PUT","Path":"/v1/commerce/tokentransaction/:tokentransactionid","Args":[{"Name":"tokentransactionid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"transfer-create","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.","Method":"POST","Path":"/v1/commerce/transfer","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"transfer-create","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.","Method":"POST","Path":"/v1/commerce/transfer/:transferid","Args":[{"Name":"transferid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"transfer-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.","Method":"DELETE","Path":"/v1/commerce/transfer/:transferid","Args":[{"Name":"transferid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/transfer","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"transfer-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.","Method":"GET","Path":"/v1/commerce/transfer/:transferid","Args":[{"Name":"transferid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"transfer-update","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.","Method":"PATCH","Path":"/v1/commerce/transfer/:transferid","Args":[{"Name":"transferid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"transfer-update","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.","Method":"PUT","Path":"/v1/commerce/transfer/:transferid","Args":[{"Name":"transferid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"variant-create","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.","Method":"POST","Path":"/v1/commerce/variant","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"variant-create","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.","Method":"POST","Path":"/v1/commerce/variant/:variantid","Args":[{"Name":"variantid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"variant-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.","Method":"DELETE","Path":"/v1/commerce/variant/:variantid","Args":[{"Name":"variantid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/variant","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"variant-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.","Method":"GET","Path":"/v1/commerce/variant/:variantid","Args":[{"Name":"variantid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"variant-update","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.","Method":"PATCH","Path":"/v1/commerce/variant/:variantid","Args":[{"Name":"variantid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"variant-update","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.","Method":"PUT","Path":"/v1/commerce/variant/:variantid","Args":[{"Name":"variantid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"wallet-create","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.","Method":"POST","Path":"/v1/commerce/wallet","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"wallet-create","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.","Method":"POST","Path":"/v1/commerce/wallet/:walletid","Args":[{"Name":"walletid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"wallet-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.","Method":"DELETE","Path":"/v1/commerce/wallet/:walletid","Args":[{"Name":"walletid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/wallet","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"wallet-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.","Method":"GET","Path":"/v1/commerce/wallet/:walletid","Args":[{"Name":"walletid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"wallet-update","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.","Method":"PATCH","Path":"/v1/commerce/wallet/:walletid","Args":[{"Name":"walletid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"wallet-update","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.","Method":"PUT","Path":"/v1/commerce/wallet/:walletid","Args":[{"Name":"walletid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"watchlist-create","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.","Method":"POST","Path":"/v1/commerce/watchlist","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"watchlist-create","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.","Method":"POST","Path":"/v1/commerce/watchlist/:watchlistid","Args":[{"Name":"watchlistid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"watchlist-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.","Method":"DELETE","Path":"/v1/commerce/watchlist/:watchlistid","Args":[{"Name":"watchlistid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"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.","Method":"GET","Path":"/v1/commerce/watchlist","Args":[],"Flags":null,"Example":null},{"Service":"commerce","Name":"watchlist-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.","Method":"GET","Path":"/v1/commerce/watchlist/:watchlistid","Args":[{"Name":"watchlistid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"watchlist-update","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.","Method":"PATCH","Path":"/v1/commerce/watchlist/:watchlistid","Args":[{"Name":"watchlistid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"watchlist-update","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.","Method":"PUT","Path":"/v1/commerce/watchlist/:watchlistid","Args":[{"Name":"watchlistid","Help":""}],"Flags":null,"Example":null},{"Service":"commerce","Name":"webhooks-create","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.","Method":"POST","Path":"/v1/commerce/webhooks/:provider","Args":[{"Name":"provider","Help":""}],"Flags":null,"Example":null},{"Service":"company","Name":"advance-create","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.","Method":"POST","Path":"/v1/company/advance","Args":[],"Flags":[{"Name":"to","Field":"to","Type":"string","Help":"To is the target stage: structure, founders, payment, documents, esign,\ngenesis, import or company.","Required":false}],"Example":{"to":"founders"}},{"Service":"company","Name":"create","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.","Method":"POST","Path":"/v1/company","Args":[],"Flags":[{"Name":"already-incorporated","Field":"alreadyIncorporated","Type":"boolean","Help":"AlreadyIncorporated declares an org that already has an entity, which takes\nthe import path (POST /v1/company/skip) instead of the formation path.","Required":false},{"Name":"jurisdiction","Field":"jurisdiction","Type":"string","Help":"Jurisdiction is the state of formation: DE or WY.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the proposed company name.","Required":false},{"Name":"structure","Field":"structure","Type":"string","Help":"Structure is the legal entity to form: c-corp, llc or dao-llc.","Required":false}],"Example":{"jurisdiction":"DE","name":"AgentCo, LLC","structure":"c-corp"}},{"Service":"company","Name":"documents-create","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.","Method":"POST","Path":"/v1/company/documents","Args":[],"Flags":null,"Example":null},{"Service":"company","Name":"ein-create","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.","Method":"POST","Path":"/v1/company/ein","Args":[],"Flags":[{"Name":"expedited","Field":"expedited","Type":"boolean","Help":"Expedited asks for prioritised handling. Only meaningful when the\nresponsible party cannot file online.","Required":false},{"Name":"naics","Field":"naics","Type":"string","Help":"NAICS is the six-digit code for what the business does.","Required":false},{"Name":"responsible","Field":"responsible","Type":"json","Help":"Responsible is the person the IRS holds answerable for the entity.","Required":false}],"Example":null},{"Service":"company","Name":"esign-complete-create","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.","Method":"POST","Path":"/v1/company/esign/complete","Args":[],"Flags":[{"Name":"signed","Field":"signed","Type":"boolean","Help":"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.","Required":false}],"Example":{"signed":true}},{"Service":"company","Name":"esign-create","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.","Method":"POST","Path":"/v1/company/esign","Args":[],"Flags":null,"Example":null},{"Service":"company","Name":"founders-create","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.","Method":"POST","Path":"/v1/company/founders","Args":[],"Flags":[{"Name":"founders","Field":"founders","Type":"json","Help":"Founders is every founding stakeholder. Each needs a name and an email, and\nequityBps between 0 and 10000 (1% == 100 bps).","Required":false}],"Example":{"founders":[{"email":"ada@acme.com","equityBps":10000,"name":"Ada"}]}},{"Service":"company","Name":"fundraise-deck-create","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.","Method":"POST","Path":"/v1/company/fundraise/deck","Args":[],"Flags":[{"Name":"body","Field":"body","Type":"file","Help":"","Required":false,"In":"body"}],"Example":null,"Consumes":["application/octet-stream"]},{"Service":"company","Name":"fundraise-round-create","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.","Method":"POST","Path":"/v1/company/fundraise/round","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"Name is the round's name on the cap table, e.g. \"Seed\". Required.","Required":false},{"Name":"pre-money-valuation","Field":"preMoneyValuation","Type":"number","Help":"PreMoneyValuation is the valuation the round prices off, before the new money.","Required":false},{"Name":"price-per-share","Field":"pricePerShare","Type":"number","Help":"PricePerShare is the per-share price of a priced round.","Required":false},{"Name":"round-type","Field":"roundType","Type":"string","Help":"RoundType is PRICED, SAFE or CONVERTIBLE_NOTE. Defaults to PRICED.","Required":false},{"Name":"share-class-id","Field":"shareClassId","Type":"string","Help":"ShareClassID is the cap table's share class the round issues into.","Required":false},{"Name":"target-amount","Field":"targetAmount","Type":"number","Help":"TargetAmount is the amount the round is raising, recorded verbatim on the\ncanonical cap table's rounds.create contract.","Required":false}],"Example":{"name":"Seed","roundType":"PRICED","targetAmount":2000000}},{"Service":"company","Name":"fundraise-safe-create","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.","Method":"POST","Path":"/v1/company/fundraise/safe","Args":[],"Flags":[{"Name":"document-ids","Field":"documentIds","Type":"json","Help":"DocumentIDs are data room document ids to raise a signature request over. Required.","Required":false},{"Name":"signers","Field":"signers","Type":"json","Help":"Signers are the recipients, each a name and an email. Required.","Required":false}],"Example":{"documentIds":["doc_safe"],"signers":[{"email":"ada@acme.com","name":"Ada"}]}},{"Service":"company","Name":"genesis-create","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.","Method":"POST","Path":"/v1/company/genesis","Args":[],"Flags":null,"Example":null},{"Service":"company","Name":"import-captable-create","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.","Method":"POST","Path":"/v1/company/import/captable","Args":[],"Flags":[{"Name":"range","Field":"range","Type":"string","Help":"Range is an optional A1 range within the sheet; empty reads the default range.","Required":false},{"Name":"spreadsheet-id","Field":"spreadsheetId","Type":"string","Help":"SpreadsheetID is a Google Sheets id. Required.","Required":false}],"Example":{"range":"Cap Table!A1:E100","spreadsheetId":"1AbCdEfGhIjKlMnOpQrStUvWxYz"}},{"Service":"company","Name":"import-documents-create","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.","Method":"POST","Path":"/v1/company/import/documents","Args":[],"Flags":[{"Name":"folder-id","Field":"folderId","Type":"string","Help":"FolderID is a Google Drive folder id. Required.","Required":false}],"Example":{"folderId":"1AbCdEfGhIjKlMnOpQrStUvWxYz"}},{"Service":"company","Name":"kyc-create","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.","Method":"POST","Path":"/v1/company/kyc","Args":[],"Flags":null,"Example":null},{"Service":"company","Name":"kyc-refresh-create","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.","Method":"POST","Path":"/v1/company/kyc/refresh","Args":[],"Flags":null,"Example":null},{"Service":"company","Name":"list","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.","Method":"GET","Path":"/v1/company","Args":[],"Flags":null,"Example":null},{"Service":"company","Name":"payment-create","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.","Method":"POST","Path":"/v1/company/payment","Args":[],"Flags":null,"Example":null},{"Service":"company","Name":"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.","Method":"GET","Path":"/v1/company/register","Args":[],"Flags":[{"Name":"stage","Field":"stage","Type":"string","Help":"Stage keeps only formations at that stage. Empty means any.","Required":false},{"Name":"structure","Field":"structure","Type":"string","Help":"Structure keeps only formations of that entity kind. Empty means any.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit bounds the page; 0 or less means the default of 200.","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset skips that many rows.","Required":false}],"Example":{"limit":50,"stage":"founders"}},{"Service":"company","Name":"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.","Method":"GET","Path":"/v1/company/register/summary","Args":[],"Flags":null,"Example":null},{"Service":"company","Name":"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.","Method":"GET","Path":"/v1/company/review","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit bounds how many formations are scanned; 0 or less means the default of 200.","Required":false}],"Example":{"limit":50}},{"Service":"company","Name":"skip-create","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.","Method":"POST","Path":"/v1/company/skip","Args":[],"Flags":null,"Example":null},{"Service":"company","Name":"structure-update","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.","Method":"PUT","Path":"/v1/company/structure","Args":[],"Flags":[{"Name":"jurisdiction","Field":"jurisdiction","Type":"string","Help":"Jurisdiction is the state of formation: DE or WY.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the proposed company name.","Required":false},{"Name":"structure","Field":"structure","Type":"string","Help":"Structure is the legal entity: c-corp, llc or dao-llc.","Required":false}],"Example":{"jurisdiction":"DE","name":"AgentCo, LLC","structure":"c-corp"}},{"Service":"company","Name":"tariff-create","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.","Method":"POST","Path":"/v1/company/tariff","Args":[],"Flags":[{"Name":"agent-of-record","Field":"agentOfRecord","Type":"boolean","Help":"AgentOfRecord puts us on file as the entity's agent, yearly.","Required":false},{"Name":"expedited-ein","Field":"expeditedEin","Type":"boolean","Help":"ExpeditedEIN prioritises the EIN.","Required":false},{"Name":"jurisdiction","Field":"jurisdiction","Type":"string","Help":"Jurisdiction is the state of formation.","Required":false},{"Name":"structure","Field":"structure","Type":"string","Help":"Structure is the entity being formed: c-corp, llc or dao-llc.","Required":false}],"Example":null},{"Service":"completions","Name":"create","OperationID":"post_completions","Summary":"Implements the OpenAI-compatible chat completions API","Description":"Implements the OpenAI-compatible chat completions API","Method":"POST","Path":"/v1/completions","Args":[],"Flags":[{"Name":"frequency-penalty","Field":"frequency_penalty","Type":"number","Help":"","Required":false},{"Name":"function-call","Field":"function_call","Type":"json","Help":"","Required":false},{"Name":"functions","Field":"functions","Type":"json","Help":"","Required":false},{"Name":"logit-bias","Field":"logit_bias","Type":"json","Help":"","Required":false},{"Name":"logprobs","Field":"logprobs","Type":"boolean","Help":"","Required":false},{"Name":"max-completion-tokens","Field":"max_completion_tokens","Type":"integer","Help":"","Required":false},{"Name":"max-tokens","Field":"max_tokens","Type":"integer","Help":"","Required":false},{"Name":"messages","Field":"messages","Type":"json","Help":"","Required":false},{"Name":"metadata","Field":"metadata","Type":"json","Help":"","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"","Required":false},{"Name":"n","Field":"n","Type":"integer","Help":"","Required":false},{"Name":"parallel-tool-calls","Field":"parallel_tool_calls","Type":"json","Help":"","Required":false},{"Name":"presence-penalty","Field":"presence_penalty","Type":"number","Help":"","Required":false},{"Name":"reasoning-effort","Field":"reasoning_effort","Type":"string","Help":"","Required":false},{"Name":"response-format","Field":"response_format","Type":"json","Help":"","Required":false},{"Name":"seed","Field":"seed","Type":"integer","Help":"","Required":false},{"Name":"stop","Field":"stop","Type":"json","Help":"","Required":false},{"Name":"store","Field":"store","Type":"boolean","Help":"","Required":false},{"Name":"stream","Field":"stream","Type":"boolean","Help":"","Required":false},{"Name":"stream-options","Field":"stream_options","Type":"json","Help":"","Required":false},{"Name":"temperature","Field":"temperature","Type":"number","Help":"","Required":false},{"Name":"tool-choice","Field":"tool_choice","Type":"json","Help":"","Required":false},{"Name":"tools","Field":"tools","Type":"json","Help":"","Required":false},{"Name":"top-logprobs","Field":"top_logprobs","Type":"integer","Help":"","Required":false},{"Name":"top-p","Field":"top_p","Type":"number","Help":"","Required":false},{"Name":"user","Field":"user","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"compliance","Name":"accreditation-create","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.","Method":"POST","Path":"/v1/compliance/accreditation","Args":[],"Flags":[{"Name":"basis","Field":"basis","Type":"string","Help":"Basis is the qualification category: income, net_worth, professional_license,\nor entity.","Required":false},{"Name":"evidence-doc-id","Field":"evidenceDocId","Type":"string","Help":"EvidenceDocID references an evidence document in the org's sealed data room.","Required":false},{"Name":"expires-at","Field":"expiresAt","Type":"integer","Help":"ExpiresAt is the unix second a confirmation ages out; 0 means none.","Required":false},{"Name":"method","Field":"method","Type":"string","Help":"Method is how the state was established: self_attested, third_party_letter,\nor provider_verified.","Required":false},{"Name":"note","Field":"note","Type":"string","Help":"Note is a non-PII operator note.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status may only be \"asserted\" (empty reads as asserted); every confirmed,\nrejected or expired state is recorded via the decision endpoint.","Required":false},{"Name":"subject-id","Field":"subjectId","Type":"string","Help":"SubjectID names the subject this record is about; it must exist within the org.","Required":false}],"Example":{"basis":"income","method":"self_attested","subjectId":"sub_1"}},{"Service":"compliance","Name":"accreditation-decision","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.","Method":"POST","Path":"/v1/compliance/accreditation/:id/decision","Args":[{"Name":"id","Help":"ID is the accreditation record to decide, from the path."}],"Flags":[{"Name":"status","Field":"status","Type":"string","Help":"Status is the decision being recorded: reviewer_confirmed, provider_verified,\nrejected, or expired.","Required":false}],"Example":{"id":"acc_1","status":"reviewer_confirmed"}},{"Service":"compliance","Name":"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.","Method":"GET","Path":"/v1/compliance/accreditation","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the rows returned; non-positive means the server default.","Required":false}],"Example":null},{"Service":"compliance","Name":"accreditation-get","OperationID":"get_compliance_accreditation_by_id","Summary":"Returns one tracked accreditation record.","Description":"Returns one tracked accreditation record.","Method":"GET","Path":"/v1/compliance/accreditation/:id","Args":[{"Name":"id","Help":"ID is the accreditation record to read, from the path."}],"Flags":null,"Example":{"id":"acc_1"}},{"Service":"compliance","Name":"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.","Method":"GET","Path":"/v1/compliance/audit","Args":[],"Flags":[{"Name":"result","Field":"result","Type":"string","Help":"Result filters rows by outcome result: success, deny, or error; empty means all.","Required":false}],"Example":null},{"Service":"compliance","Name":"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.","Method":"GET","Path":"/v1/compliance/health","Args":[],"Flags":null,"Example":null},{"Service":"compliance","Name":"records-list","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.","Method":"GET","Path":"/v1/compliance/records","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the rows returned; non-positive means the server default.","Required":false}],"Example":null},{"Service":"compliance","Name":"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.","Method":"GET","Path":"/v1/compliance/status","Args":[],"Flags":null,"Example":null},{"Service":"compliance","Name":"subjects-create","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.","Method":"POST","Path":"/v1/compliance/subjects","Args":[],"Flags":[{"Name":"email","Field":"email","Type":"string","Help":"Email is the subject's contact email, sealed at rest.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind is the party type: \"individual\" (KYC) or \"business\" (KYB).","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the subject's name, sealed at rest.","Required":false},{"Name":"ref","Field":"ref","Type":"string","Help":"Ref is the org's own opaque external id for this subject.","Required":false}],"Example":{"email":"founder@example.com","kind":"individual","name":"Ada"}},{"Service":"compliance","Name":"subjects-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.","Method":"GET","Path":"/v1/compliance/subjects/:id","Args":[{"Name":"id","Help":"ID is the subject to read, from the path."}],"Flags":null,"Example":{"id":"sub_1"}},{"Service":"compliance","Name":"subjects-list","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.","Method":"GET","Path":"/v1/compliance/subjects","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the rows returned; non-positive means the server default.","Required":false}],"Example":null},{"Service":"compliance","Name":"verifications-create","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.","Method":"POST","Path":"/v1/compliance/verifications","Args":[],"Flags":[{"Name":"email","Field":"email","Type":"string","Help":"Email is an inline subject's contact email, sealed at rest.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind is an inline subject's party type: \"individual\" (KYC) or \"business\" (KYB).","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is an inline subject's name, sealed at rest.","Required":false},{"Name":"ref","Field":"ref","Type":"string","Help":"Ref is the org's own opaque external id for an inline subject.","Required":false},{"Name":"subject-id","Field":"subjectId","Type":"string","Help":"SubjectID names an existing subject to verify; empty creates one inline.","Required":false}],"Example":{"subjectId":"sub_1"}},{"Service":"compliance","Name":"verifications-decision","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.","Method":"POST","Path":"/v1/compliance/verifications/:id/decision","Args":[{"Name":"id","Help":"ID is the verification to decide, from the path."}],"Flags":[{"Name":"status","Field":"status","Type":"string","Help":"Status is the reviewer's decision: \"reviewer_confirmed\" (a pass) or\n\"manual_review\" (withheld for review) — never a provider status.","Required":false}],"Example":{"id":"chk_1","status":"reviewer_confirmed"}},{"Service":"compliance","Name":"verifications-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.","Method":"GET","Path":"/v1/compliance/verifications/:id","Args":[{"Name":"id","Help":"ID is the verification to act on, from the path."}],"Flags":null,"Example":{"id":"chk_1"}},{"Service":"compliance","Name":"verifications-list","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.","Method":"GET","Path":"/v1/compliance/verifications","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the rows returned; non-positive means the server default.","Required":false}],"Example":null},{"Service":"compliance","Name":"verifications-refresh","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.","Method":"POST","Path":"/v1/compliance/verifications/:id/refresh","Args":[{"Name":"id","Help":"ID is the verification to act on, from the path."}],"Flags":null,"Example":{"id":"chk_1"}},{"Service":"compliance","Name":"verifications-webhook-create","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.","Method":"POST","Path":"/v1/compliance/verifications/webhook","Args":[],"Flags":null,"Example":null},{"Service":"compute","Name":"attach-cluster","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.","Method":"POST","Path":"/v1/compute/clusters","Args":[],"Flags":[{"Name":"default","Field":"default","Type":"boolean","Help":"Default marks this the org's default cluster for scheduling.","Required":false},{"Name":"kubeconfig","Field":"kubeconfig","Type":"string","Help":"Kubeconfig is the cluster's kubeconfig, verbatim. Required — a body without\none is not an attach.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the fleet-local name for the cluster; lower-cased, and the key the\ndetach route addresses it by. Required.","Required":false},{"Name":"provider","Field":"provider","Type":"string","Help":"Provider is a free-form label for where the cluster runs (\"gke\", \"on-prem\");\nit is display only, not a routing key.","Required":false}],"Example":{"default":false,"kubeconfig":"apiVersion: v1\nkind: Config\n...","name":"lab","provider":"on-prem"}},{"Service":"compute","Name":"bind-machine-agent","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.","Method":"PUT","Path":"/v1/compute/machines/:id/agent","Args":[{"Name":"id","Help":"ID is the machine to bind, from the URL path."}],"Flags":[{"Name":"agent-name","Field":"agentName","Type":"string","Help":"AgentName is the cloud Agent (/v1/agent) the machine will run. Required.","Required":false},{"Name":"bot-version","Field":"botVersion","Type":"string","Help":"BotVersion pins the @hanzo/bot runtime version; empty takes the default.","Required":false}],"Example":{"agentName":"bot-a","botVersion":"1.4.0"}},{"Service":"compute","Name":"cancel-fleet-job","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.","Method":"POST","Path":"/v1/compute/fleet/jobs/:id/cancel","Args":[{"Name":"id","Help":"ID is the job (activity) id, from the URL path."}],"Flags":[{"Name":"reason","Field":"reason","Type":"string","Help":"Reason is recorded on the cancellation; empty records \"canceled from console\".","Required":false},{"Name":"run","Field":"run","Type":"string","Help":"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.","Required":false}],"Example":{"reason":"superseded"}},{"Service":"compute","Name":"create-kubernetes-cluster","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.","Method":"POST","Path":"/v1/compute/k8s/clusters","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"Name is the cluster's name. Required.","Required":false},{"Name":"node-pool","Field":"nodePool","Type":"json","Help":"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.","Required":false},{"Name":"region","Field":"region","Type":"string","Help":"Region is the provider region slug (e.g. \"nyc3\"). Required.","Required":false},{"Name":"version","Field":"version","Type":"string","Help":"Version is the Kubernetes version slug; empty takes the provider default.","Required":false}],"Example":{"name":"prod","nodePool":{"count":2,"name":"gpu","size":"gpu-h100x8-640gb"},"region":"nyc3"}},{"Service":"compute","Name":"create-node-pool","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.","Method":"POST","Path":"/v1/compute/clusters/:clusterId/pools","Args":[{"Name":"clusterId","Help":"ClusterID is the cluster to add the pool to, from the URL path."}],"Flags":[{"Name":"auto-scale","Field":"autoScale","Type":"boolean","Help":"AutoScale turns the provider's cluster autoscaler on for this pool.","Required":false},{"Name":"count","Field":"count","Type":"integer","Help":"Count is how many nodes the pool starts with.","Required":false},{"Name":"max-nodes","Field":"maxNodes","Type":"integer","Help":"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.","Required":false},{"Name":"min-nodes","Field":"minNodes","Type":"integer","Help":"MinNodes is the floor the autoscaler may not shrink the pool below. Ignored\nunless AutoScale is set.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the pool's name.","Required":false},{"Name":"provider","Field":"provider","Type":"string","Help":"Provider is the cloud the cluster lives on (e.g. \"digitalocean\"). Required —\nVisor routes the create by it. Accepted from the body or ?provider=.","Required":false},{"Name":"size","Field":"size","Type":"string","Help":"Size is the provider size slug for each node (e.g. \"s-4vcpu-8gb\").","Required":false}],"Example":{"autoScale":false,"count":2,"name":"gpu","provider":"digitalocean","size":"gpu-h100x8-640gb"}},{"Service":"compute","Name":"delete-kubernetes-cluster","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.","Method":"DELETE","Path":"/v1/compute/k8s/clusters/:id","Args":[{"Name":"id","Help":"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."}],"Flags":null,"Example":null},{"Service":"compute","Name":"delete-machine","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.","Method":"DELETE","Path":"/v1/compute/machines/:id","Args":[{"Name":"id","Help":"ID is the machine's org-scoped NAME — the stable key Visor addresses a\nmachine by (owner/name), not the ephemeral provider id."}],"Flags":null,"Example":null},{"Service":"compute","Name":"delete-node-pool","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.","Method":"DELETE","Path":"/v1/compute/clusters/:clusterId/pools/:poolId","Args":[{"Name":"clusterId","Help":"ClusterID and PoolID address the pool, from the URL path."},{"Name":"poolId","Help":""}],"Flags":[{"Name":"provider","Field":"provider","Type":"string","Help":"Provider is the cloud the cluster lives on, from ?provider=. Required.","Required":false}],"Example":null},{"Service":"compute","Name":"detach-cluster","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.","Method":"DELETE","Path":"/v1/compute/clusters/:id","Args":[{"Name":"id","Help":"ID is the cluster's fleet name (the `name` it was attached under), matched\nlower-cased."}],"Flags":null,"Example":null},{"Service":"compute","Name":"get-kubernetes-cluster","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.","Method":"GET","Path":"/v1/compute/k8s/clusters/:id","Args":[{"Name":"id","Help":"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."}],"Flags":null,"Example":null},{"Service":"compute","Name":"get-machine","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.","Method":"GET","Path":"/v1/compute/machines/:id","Args":[{"Name":"id","Help":"ID is the machine's org-scoped NAME — the stable key Visor addresses a\nmachine by (owner/name), not the ephemeral provider id."}],"Flags":null,"Example":null},{"Service":"compute","Name":"get-machine-agent","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.","Method":"GET","Path":"/v1/compute/machines/:id/agent","Args":[{"Name":"id","Help":"ID is the machine's org-scoped NAME — the stable key Visor addresses a\nmachine by (owner/name), not the ephemeral provider id."}],"Flags":null,"Example":null},{"Service":"compute","Name":"list-clusters","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.","Method":"GET","Path":"/v1/compute/clusters","Args":[],"Flags":null,"Example":null},{"Service":"compute","Name":"list-fleet","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.","Method":"GET","Path":"/v1/compute/fleet","Args":[],"Flags":null,"Example":null},{"Service":"compute","Name":"list-fleet-jobs","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.","Method":"GET","Path":"/v1/compute/fleet/jobs","Args":[],"Flags":[{"Name":"gpu","Field":"gpu","Type":"string","Help":"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.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status selects one lifecycle state: queued, running, stalled, completed,\nfailed or canceled.","Required":false}],"Example":null},{"Service":"compute","Name":"list-fleet-samples","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\".","Method":"GET","Path":"/v1/compute/fleet/samples","Args":[],"Flags":[{"Name":"unit","Field":"unit","Type":"string","Help":"Unit selects one compute unit's series by its source-local id.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source selects one plane: \"agent\", \"byo\" or \"visor\".","Required":false},{"Name":"range","Field":"range","Type":"string","Help":"Range is the lookback window (e.g. \"1h\", \"24h\", \"7d\"); empty takes the\nwarehouse default.","Required":false}],"Example":null},{"Service":"compute","Name":"list-fleet-workers","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.","Method":"GET","Path":"/v1/compute/fleet/workers","Args":[],"Flags":null,"Example":null},{"Service":"compute","Name":"list-gpu-alerts","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.","Method":"GET","Path":"/v1/compute/gpus/alerts","Args":[],"Flags":null,"Example":null},{"Service":"compute","Name":"list-gpus","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.","Method":"GET","Path":"/v1/compute/gpus","Args":[],"Flags":null,"Example":null},{"Service":"compute","Name":"list-kubernetes-clusters","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.","Method":"GET","Path":"/v1/compute/k8s/clusters","Args":[],"Flags":null,"Example":null},{"Service":"compute","Name":"list-kubernetes-nodes","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.","Method":"GET","Path":"/v1/compute/k8s/nodes","Args":[],"Flags":null,"Example":null},{"Service":"compute","Name":"list-machine-agents","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.","Method":"GET","Path":"/v1/compute/machines/agents","Args":[],"Flags":null,"Example":null},{"Service":"compute","Name":"list-machines","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.","Method":"GET","Path":"/v1/compute/machines","Args":[],"Flags":[{"Name":"kind","Field":"kind","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"compute","Name":"machines-create","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).","Method":"POST","Path":"/v1/compute/machines","Args":[],"Flags":null,"Example":null},{"Service":"compute","Name":"machines-create","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.","Method":"POST","Path":"/v1/compute/machines/:id/:action","Args":[{"Name":"id","Help":""},{"Name":"action","Help":""}],"Flags":null,"Example":null},{"Service":"compute","Name":"record-fleet-sample","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.","Method":"POST","Path":"/v1/compute/fleet/samples","Args":[],"Flags":[{"Name":"gpu-model","Field":"gpuModel","Type":"string","Help":"GPUModel names the representative accelerator (\"GB10\"); GPUs carries how\nmany. A heterogeneous host names its first card rather than inventing a\nsummary.","Required":false},{"Name":"gpu-util","Field":"gpuUtil","Type":"number","Help":"GPUUtil is accelerator utilization as a fraction 0..1; the warehouse clamps\nanything outside that.","Required":false},{"Name":"gpus","Field":"gpus","Type":"integer","Help":"GPUs is how many accelerators this reading covers.","Required":false},{"Name":"host","Field":"host","Type":"string","Help":"Host is the node's hostname, for display.","Required":false},{"Name":"mem-free","Field":"memFree","Type":"integer","Help":"MemFree is host memory still available, in BYTES.","Required":false},{"Name":"mem-used","Field":"memUsed","Type":"integer","Help":"MemUsed is host memory in use, in BYTES.","Required":false},{"Name":"unit","Field":"unit","Type":"string","Help":"Unit is the reporting node's own id — the same id it registered under, and\nthe key the board joins this series onto. Required.","Required":false}],"Example":{"gpuModel":"GB10","gpuUtil":0.42,"gpus":1,"host":"spark","memFree":200,"memUsed":100,"unit":"spark"}},{"Service":"compute","Name":"regions-list","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.","Method":"GET","Path":"/v1/compute/regions","Args":[],"Flags":null,"Example":null},{"Service":"compute","Name":"scale-node-pool","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.","Method":"POST","Path":"/v1/compute/clusters/:clusterId/pools/:poolId/scale","Args":[{"Name":"clusterId","Help":"ClusterID is the cluster holding the pool, from the URL path."},{"Name":"poolId","Help":"PoolID is the pool to resize, from the URL path — the `poolId` a cluster read\nreports for it. Required."}],"Flags":[{"Name":"count","Field":"count","Type":"integer","Help":"Count is the node count to scale TO — an absolute target, not a delta, and\nnever negative.","Required":false},{"Name":"provider","Field":"provider","Type":"string","Help":"Provider is the cloud the cluster lives on. Required; body or ?provider=.","Required":false}],"Example":{"count":4,"provider":"digitalocean"}},{"Service":"compute","Name":"sizes-list","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.","Method":"GET","Path":"/v1/compute/sizes","Args":[],"Flags":null,"Example":null},{"Service":"compute","Name":"unbind-machine-agent","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.","Method":"DELETE","Path":"/v1/compute/machines/:id/agent","Args":[{"Name":"id","Help":"ID is the machine's org-scoped NAME — the stable key Visor addresses a\nmachine by (owner/name), not the ephemeral provider id."}],"Flags":null,"Example":null},{"Service":"connection","Name":"credential","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).","Method":"POST","Path":"/v1/connection/:provider/credential","Args":[{"Name":"provider","Help":"Provider is the user-scoped provider's registry id, from the path."}],"Flags":[{"Name":"account-id","Field":"accountId","Type":"string","Help":"AccountID scopes the credential where the provider's Verify needs one.","Required":false},{"Name":"label","Field":"label","Type":"string","Help":"Label names this connection; empty means \"default\".","Required":false},{"Name":"oauth","Field":"oauth","Type":"json","Help":"OAuth is a bundle the CLI already obtained through its own local PKCE flow.\nPresent ⇒ the Adopt path; absent ⇒ the Token path.","Required":false},{"Name":"token","Field":"token","Type":"string","Help":"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.","Required":false}],"Example":{"label":"work","provider":"openai","token":"sk-user-owned-key"}},{"Service":"connection","Name":"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.","Method":"DELETE","Path":"/v1/connection/:id","Args":[{"Name":"id","Help":"ID is the connector id, provider + \":\" + label (\"openai:default\") — the\nauth-profile-id shape. Another user's id is simply no row, so 404."}],"Flags":null,"Example":{"id":"openai:work"}},{"Service":"connection","Name":"device","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.","Method":"POST","Path":"/v1/connection/:provider/device","Args":[{"Name":"provider","Help":"Provider is the user-scoped provider's registry id, from the path."}],"Flags":[{"Name":"label","Field":"label","Type":"string","Help":"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._-].","Required":false}],"Example":{"label":"work","provider":"openai"}},{"Service":"connection","Name":"list","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.","Method":"GET","Path":"/v1/connection","Args":[],"Flags":null,"Example":null},{"Service":"connection","Name":"poll","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.","Method":"POST","Path":"/v1/connection/:provider/device/:flow/poll","Args":[{"Name":"provider","Help":"Provider is the user-scoped provider's registry id, from the path."},{"Name":"flow","Help":"Flow is the id deviceStartOut returned. Expired or another user's flow is\nindistinguishable from an unknown one: 404."}],"Flags":null,"Example":{"flow":"g_7f2c","provider":"openai"}},{"Service":"connection","Name":"providers-list","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.","Method":"GET","Path":"/v1/connection/providers","Args":[],"Flags":null,"Example":null},{"Service":"connection","Name":"refresh","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.","Method":"POST","Path":"/v1/connection/:id/refresh","Args":[{"Name":"id","Help":"ID is the connector id, provider + \":\" + label (\"openai:default\") — the\nauth-profile-id shape. Another user's id is simply no row, so 404."}],"Flags":null,"Example":{"id":"openai:work"}},{"Service":"connection","Name":"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.","Method":"GET","Path":"/v1/connection/:id/token","Args":[{"Name":"id","Help":"ID is the connector id, provider + \":\" + label (\"openai:default\") — the\nauth-profile-id shape. Another user's id is simply no row, so 404."}],"Flags":null,"Example":{"id":"openai:work"}},{"Service":"content","Name":"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.","Method":"GET","Path":"/v1/content/board","Args":[],"Flags":[{"Name":"status","Field":"status","Type":"string","Help":"Status keeps only items in one lifecycle state (draft, in_review, approved,\nqueued, published, archived). An undefined state is refused.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project keeps only items in one brand/site sub-scope.","Required":false},{"Name":"doctype","Field":"doctype","Type":"string","Help":"DocType keeps only one content type; omitted, the board spans every\npublishable type. An unknown type is refused.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the rows returned, clamped to 1000. Defaults to 200, which is also\nwhat a non-positive or unparseable value takes.","Required":false}],"Example":{"limit":50,"status":"queued"}},{"Service":"content","Name":"channels-list","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\".","Method":"GET","Path":"/v1/content/channels","Args":[],"Flags":null,"Example":null},{"Service":"content","Name":"generate-create","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.","Method":"POST","Path":"/v1/content/generate","Args":[],"Flags":[{"Name":"brief","Field":"brief","Type":"string","Help":"the brief/goal driving copy generation","Required":false},{"Name":"channels","Field":"channels","Type":"string","Help":"target channels (SocialPost)","Required":false},{"Name":"design","Field":"design","Type":"string","Help":"studio design slug (asset source)","Required":false},{"Name":"doctype","Field":"doctype","Type":"string","Help":"marketing.Campaign | marketing.SocialPost | marketing.Asset","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"asset kind: ecom|product|lifestyle|hover|hero","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"optional zen model override (copy)","Required":false},{"Name":"product","Field":"product","Type":"string","Help":"commerce product handle (copy context)","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"brand/site sub-scope (billing + tenancy axis)","Required":false},{"Name":"source-media","Field":"source_media","Type":"string","Help":"asset source image (design CAD/photo)","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"optional explicit title","Required":false},{"Name":"tone","Field":"tone","Type":"string","Help":"tone override for a single draft","Required":false},{"Name":"voice","Field":"voice","Type":"string","Help":"brand-voice guidance for the copy director","Required":false}],"Example":null},{"Service":"content","Name":"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.","Method":"GET","Path":"/v1/content/lifecycle","Args":[],"Flags":null,"Example":null},{"Service":"content","Name":"publish-create","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.","Method":"POST","Path":"/v1/content/publish","Args":[],"Flags":[{"Name":"doctype","Field":"doctype","Type":"string","Help":"DocType is the content type holding the item: Campaign, SocialPost or Asset.\nAny other name is refused as an unknown content type.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false},{"Name":"schedule-at","Field":"scheduleAt","Type":"string","Help":"ScheduleAt hands a future go-live to the channel's own scheduler, as an\nISO-8601 time. Empty posts now.","Required":false}],"Example":{"doctype":"marketing.SocialPost","name":"spring-teaser"}},{"Service":"content","Name":"transition","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.","Method":"POST","Path":"/v1/content/:doctype/:name/transition","Args":[{"Name":"doctype","Help":"DocType is the content type to act on, from the path."},{"Name":"name","Help":"Name is the document to act on, from the path."}],"Flags":[{"Name":"schedule-at","Field":"scheduleAt","Type":"string","Help":"ScheduleAt is an ISO-8601 go-live time handed to the channel's own scheduler;\n\"\" distributes now.","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"To is the lifecycle state to move to. Required, and the move must be a legal\nedge from the item's current state.","Required":false}],"Example":{"doctype":"marketing.SocialPost","name":"spring-teaser","to":"published"}},{"Service":"crawl","Name":"read-page","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.","Method":"POST","Path":"/v1/crawl","Args":[],"Flags":[{"Name":"url","Field":"url","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"dataroom","Name":"analytics-dataroom-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.","Method":"GET","Path":"/v1/dataroom/analytics/dataroom/:dataroomId","Args":[{"Name":"dataroomId","Help":"DataroomID is the room to report on. It is the path segment, resolved in\nthe caller's own tenant store."}],"Flags":null,"Example":null},{"Service":"dataroom","Name":"analytics-link-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.","Method":"GET","Path":"/v1/dataroom/analytics/link/:linkId","Args":[{"Name":"linkId","Help":"LinkID is the link to report on. It is the path segment, resolved in the\ncaller's own tenant store."}],"Flags":null,"Example":null},{"Service":"dataroom","Name":"datarooms-create","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.","Method":"POST","Path":"/v1/dataroom/datarooms","Args":[],"Flags":[{"Name":"description","Field":"description","Type":"json","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"json","Help":"Name is the room's display name. Required, and a room without one is\nrefused with the data room's own validation error.","Required":false}],"Example":null},{"Service":"dataroom","Name":"datarooms-documents","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.","Method":"POST","Path":"/v1/dataroom/datarooms/:id/documents","Args":[{"Name":"id","Help":"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."}],"Flags":[{"Name":"document-id","Field":"documentId","Type":"json","Help":"DocumentId is the document to attach. Required, and it must already exist\nin the caller's own store — this route attaches, it never uploads.","Required":false},{"Name":"order-index","Field":"orderIndex","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"dataroom","Name":"datarooms-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.","Method":"GET","Path":"/v1/dataroom/datarooms/:id","Args":[{"Name":"id","Help":"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."}],"Flags":null,"Example":null},{"Service":"dataroom","Name":"datarooms-list","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.","Method":"GET","Path":"/v1/dataroom/datarooms","Args":[],"Flags":null,"Example":null},{"Service":"dataroom","Name":"documents-create","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.","Method":"POST","Path":"/v1/dataroom/documents","Args":[],"Flags":null,"Example":null},{"Service":"dataroom","Name":"documents-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.","Method":"GET","Path":"/v1/dataroom/documents/:id/file","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"dataroom","Name":"documents-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.","Method":"GET","Path":"/v1/dataroom/documents/:id","Args":[{"Name":"id","Help":"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."}],"Flags":null,"Example":null},{"Service":"dataroom","Name":"documents-list","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.","Method":"GET","Path":"/v1/dataroom/documents","Args":[],"Flags":null,"Example":null},{"Service":"dataroom","Name":"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.","Method":"GET","Path":"/v1/dataroom/health","Args":[],"Flags":null,"Example":null},{"Service":"dataroom","Name":"links-create","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.","Method":"POST","Path":"/v1/dataroom/links","Args":[],"Flags":[{"Name":"allow-download","Field":"allowDownload","Type":"json","Help":"AllowDownload permits downloading rather than viewing only. Optional and\nOFF by default; any truthy JSON value turns it on.","Required":false},{"Name":"allow-list","Field":"allowList","Type":"json","Help":"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.","Required":false},{"Name":"dataroom-id","Field":"dataroomId","Type":"json","Help":"DataroomId is the room to share. One of dataroomId or documentId is\nrequired, and the target must exist in the caller's own store.","Required":false},{"Name":"deny-list","Field":"denyList","Type":"json","Help":"DenyList rejects addresses, in the same three forms as the allow list.\nOptional. It is checked BEFORE the allow list, so deny always wins.","Required":false},{"Name":"document-id","Field":"documentId","Type":"json","Help":"DocumentId shares a SINGLE document instead of a room. One of dataroomId or\ndocumentId is required.","Required":false},{"Name":"email-protected","Field":"emailProtected","Type":"json","Help":"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.","Required":false},{"Name":"expires-at","Field":"expiresAt","Type":"json","Help":"ExpiresAt closes the link, in unix milliseconds. Optional; a number or a\nnumeric string is accepted, and omitting it means the link never expires.","Required":false},{"Name":"name","Field":"name","Type":"json","Help":"Name labels the link. Optional; any JSON scalar is stored as its text.","Required":false},{"Name":"password","Field":"password","Type":"json","Help":"Password gates the link. Optional; it is hashed with bcrypt before storage\nand is never readable back through any route.","Required":false}],"Example":null},{"Service":"dataroom","Name":"links-list","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.","Method":"GET","Path":"/v1/dataroom/links","Args":[],"Flags":null,"Example":null},{"Service":"dataroom","Name":"trust-artifacts-create","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.","Method":"POST","Path":"/v1/dataroom/trust/artifacts","Args":[],"Flags":[{"Name":"attester","Field":"attester","Type":"string","Help":"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.","Required":false},{"Name":"body","Field":"body","Type":"string","Help":"Body is the item's content for the kinds that are text rather than a file: an\narticle, a subprocessor entry, a dated note.","Required":false},{"Name":"document","Field":"document","Type":"string","Help":"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.","Required":false},{"Name":"framework","Field":"framework","Type":"string","Help":"Framework is the standard it speaks to. Optional and free text — the value is\nthe org's own, not a list this API keeps.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind is what the item is: report, letter, policy, questionnaire, subprocessor,\narticle or update. Required.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the item's title. Required.","Required":false},{"Name":"summary","Field":"summary","Type":"string","Help":"Summary is a line about it. Optional.","Required":false},{"Name":"tier","Field":"tier","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"dataroom","Name":"trust-artifacts-update","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.","Method":"PATCH","Path":"/v1/dataroom/trust/artifacts/:id","Args":[{"Name":"id","Help":"ID is the item to change, taken from the path."}],"Flags":[{"Name":"body","Field":"body","Type":"string","Help":"Body replaces the item's content.","Required":false},{"Name":"document","Field":"document","Type":"string","Help":"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.","Required":false},{"Name":"framework","Field":"framework","Type":"string","Help":"Framework replaces the standard it speaks to.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name replaces its title.","Required":false},{"Name":"retired","Field":"retired","Type":"boolean","Help":"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.","Required":false},{"Name":"summary","Field":"summary","Type":"string","Help":"Summary replaces the line about it.","Required":false},{"Name":"tier","Field":"tier","Type":"string","Help":"Tier moves it between public and gated. Moving an auditor-signed item to\npublic is refused.","Required":false}],"Example":null},{"Service":"dataroom","Name":"trust-center-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.","Method":"GET","Path":"/v1/dataroom/trust/center/:slug","Args":[{"Name":"slug","Help":"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."}],"Flags":null,"Example":null},{"Service":"dataroom","Name":"trust-center-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.","Method":"GET","Path":"/v1/dataroom/trust/center/:slug/file/:item","Args":[{"Name":"slug","Help":""},{"Name":"item","Help":""}],"Flags":null,"Example":null},{"Service":"dataroom","Name":"trust-center-requests","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.","Method":"POST","Path":"/v1/dataroom/trust/center/:slug/requests","Args":[{"Name":"slug","Help":"Slug is the centre's public address, taken from the path."}],"Flags":[{"Name":"accept","Field":"accept","Type":"boolean","Help":"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.","Required":false},{"Name":"email","Field":"email","Type":"string","Help":"Email is where the grant will be sent, and the ONLY address the resulting\nlink admits. Required.","Required":false},{"Name":"item","Field":"item","Type":"string","Help":"Item names one published item to ask for. Optional; omitting it asks for\neverything released on request.","Required":false},{"Name":"party","Field":"party","Type":"string","Help":"Party is the company the asker is from. Optional, and recorded as stated.","Required":false},{"Name":"reason","Field":"reason","Type":"string","Help":"Reason is why they want it. Optional, and recorded as stated — it is what the\nperson deciding reads.","Required":false}],"Example":null},{"Service":"dataroom","Name":"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.","Method":"GET","Path":"/v1/dataroom/trust","Args":[],"Flags":null,"Example":null},{"Service":"dataroom","Name":"trust-requests-grant","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.","Method":"POST","Path":"/v1/dataroom/trust/requests/:id/grant","Args":[{"Name":"id","Help":"ID is the request to answer, taken from the path."}],"Flags":[{"Name":"days","Field":"days","Type":"integer","Help":"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.","Required":false},{"Name":"note","Field":"note","Type":"string","Help":"Note is why. Recorded on the request either way, and it is what the record\nshows a year later.","Required":false}],"Example":null},{"Service":"dataroom","Name":"trust-requests-refuse","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.","Method":"POST","Path":"/v1/dataroom/trust/requests/:id/refuse","Args":[{"Name":"id","Help":"ID is the request to answer, taken from the path."}],"Flags":[{"Name":"days","Field":"days","Type":"integer","Help":"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.","Required":false},{"Name":"note","Field":"note","Type":"string","Help":"Note is why. Recorded on the request either way, and it is what the record\nshows a year later.","Required":false}],"Example":null},{"Service":"dataroom","Name":"trust-update","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.","Method":"PUT","Path":"/v1/dataroom/trust","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"Name is the centre's display name. Required to publish.","Required":false},{"Name":"nda","Field":"nda","Type":"string","Help":"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.","Required":false},{"Name":"publish","Field":"publish","Type":"boolean","Help":"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.","Required":false},{"Name":"slug","Field":"slug","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"dataroom","Name":"view-authenticate","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.","Method":"POST","Path":"/v1/dataroom/view/:linkId/authenticate","Args":[{"Name":"linkId","Help":""}],"Flags":null,"Example":null},{"Service":"dataroom","Name":"view-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.","Method":"GET","Path":"/v1/dataroom/view/:linkId/document/:documentId/file","Args":[{"Name":"linkId","Help":""},{"Name":"documentId","Help":""}],"Flags":null,"Example":null},{"Service":"dataroom","Name":"view-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.","Method":"GET","Path":"/v1/dataroom/view/:linkId","Args":[{"Name":"linkId","Help":""}],"Flags":null,"Example":null},{"Service":"dataroom","Name":"view-pageview","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.","Method":"POST","Path":"/v1/dataroom/view/:linkId/pageview","Args":[{"Name":"linkId","Help":""}],"Flags":null,"Example":null},{"Service":"dataset","Name":"risk-create-dataset","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.","Method":"POST","Path":"/v1/dataset","Args":[],"Flags":[{"Name":"cuts","Field":"cuts","Type":"json","Help":"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.","Required":false},{"Name":"dims","Field":"dims","Type":"json","Help":"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.","Required":false},{"Name":"from","Field":"from","Type":"string","Help":"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.","Required":false},{"Name":"horizon","Field":"horizon","Type":"integer","Help":"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.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind narrows to one subject kind — person, session or account. Empty takes\nevery kind.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name identifies the dataset across its versions: lower-case letters, digits\nand hyphens, starting with a letter.","Required":false},{"Name":"rows","Field":"rows","Type":"integer","Help":"Rows caps the materialisation. Zero takes the plane's own bound.","Required":false},{"Name":"seed","Field":"seed","Type":"string","Help":"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.","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"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.","Required":false}],"Example":{"from":"2026-01-01T00:00:00Z","horizon":14,"kind":"person","name":"signups","to":"2026-04-01T00:00:00Z"}},{"Service":"dataset","Name":"risk-dataset","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.","Method":"GET","Path":"/v1/dataset/:name","Args":[{"Name":"name","Help":"Name is the dataset, from the path."}],"Flags":null,"Example":{"name":"signups"}},{"Service":"dataset","Name":"risk-dataset-lineage","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.","Method":"GET","Path":"/v1/dataset/:name/lineage","Args":[{"Name":"name","Help":"Name is the dataset, from the path."}],"Flags":[{"Name":"version","Field":"version","Type":"integer","Help":"Version is the version to trace. Zero takes the newest published one.","Required":false}],"Example":{"name":"signups","version":1}},{"Service":"dataset","Name":"risk-datasets","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.","Method":"GET","Path":"/v1/dataset","Args":[],"Flags":null,"Example":null},{"Service":"dataset","Name":"risk-delete-dataset","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.","Method":"DELETE","Path":"/v1/dataset/:name","Args":[{"Name":"name","Help":"Name is the dataset, from the path."}],"Flags":null,"Example":{"name":"signups"}},{"Service":"dataset","Name":"risk-export-dataset","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.","Method":"GET","Path":"/v1/dataset/:name/export","Args":[{"Name":"name","Help":"Name is the dataset, from the path."}],"Flags":[{"Name":"version","Field":"version","Type":"integer","Help":"Version is the version to read. Zero takes the newest published one.","Required":false},{"Name":"split","Field":"split","Type":"string","Help":"Split narrows to train, val or test. Empty reads every split.","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"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).","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit is how many rows to return. Zero and anything above the plane's bound\ntake the bound.","Required":false}],"Example":{"limit":500,"name":"signups","split":"train","version":1}},{"Service":"dataset","Name":"risk-materialize-dataset","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.","Method":"POST","Path":"/v1/dataset/:name/materialize","Args":[{"Name":"name","Help":"Name is the dataset, from the path."}],"Flags":null,"Example":{"name":"signups"}},{"Service":"decisions","Name":"correct","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.","Method":"POST","Path":"/v1/decisions/:decision/corrections","Args":[{"Name":"decision","Help":"Decision is the decision's id."}],"Flags":[{"Name":"answer","Field":"answer","Type":"string","Help":"Answer is the right option label; a score's level may be named by its\nindex.","Required":false},{"Name":"cohort","Field":"cohort","Type":"string","Help":"Cohort groups corrections the org files together.","Required":false},{"Name":"note","Field":"note","Type":"string","Help":"Note says why, for the person reading it later.","Required":false},{"Name":"question","Field":"question","Type":"string","Help":"Question is the question's key.","Required":false}],"Example":{"answer":"refund","note":"the customer asked for their money back","question":"intent"}},{"Service":"decisions","Name":"corrections","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).","Method":"GET","Path":"/v1/decisions/:decision/corrections","Args":[{"Name":"decision","Help":""}],"Flags":null,"Example":null},{"Service":"decisions","Name":"create","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.","Method":"POST","Path":"/v1/decisions","Args":[],"Flags":[{"Name":"handle","Field":"handle","Type":"string","Help":"","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"","Required":true},{"Name":"observe","Field":"observe","Type":"string","Help":"","Required":false},{"Name":"provider","Field":"provider","Type":"json","Help":"","Required":false},{"Name":"questions","Field":"questions","Type":"json","Help":"","Required":false},{"Name":"session-id","Field":"session_id","Type":"string","Help":"","Required":false},{"Name":"state","Field":"state","Type":"json","Help":"A string, an object or an array, kept as written.","Required":false},{"Name":"trace","Field":"trace","Type":"json","Help":"","Required":false},{"Name":"user","Field":"user","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"decisions","Name":"uncorrect","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.","Method":"DELETE","Path":"/v1/decisions/:decision/corrections/:id","Args":[{"Name":"decision","Help":""},{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"deploy","Name":"applications-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.","Method":"GET","Path":"/v1/deploy/applications/:name","Args":[{"Name":"name","Help":"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."}],"Flags":null,"Example":null},{"Service":"deploy","Name":"applications-list","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.","Method":"GET","Path":"/v1/deploy/applications","Args":[],"Flags":null,"Example":null},{"Service":"deploy","Name":"applications-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.","Method":"GET","Path":"/v1/deploy/applications/:name/revisions/:revision/metadata","Args":[{"Name":"name","Help":"Name is the application to read, from the path. It must be a DNS-1123 label."},{"Name":"revision","Help":"Revision is the revision to describe, from the path. The empty revision and\n\"HEAD\" both mean \"whatever this application currently declares\"."}],"Flags":null,"Example":null},{"Service":"deploy","Name":"applications-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.","Method":"GET","Path":"/v1/deploy/applications/:name/resource-tree","Args":[{"Name":"name","Help":"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."}],"Flags":null,"Example":null},{"Service":"deploy","Name":"applications-rollback","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.","Method":"POST","Path":"/v1/deploy/applications/:name/rollback","Args":[{"Name":"name","Help":"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."}],"Flags":null,"Example":null},{"Service":"deploy","Name":"applications-syncwindows-list","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.","Method":"GET","Path":"/v1/deploy/applications/:name/syncwindows","Args":[{"Name":"name","Help":"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."}],"Flags":null,"Example":null},{"Service":"deploy","Name":"clusters-list","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.","Method":"GET","Path":"/v1/deploy/clusters","Args":[],"Flags":null,"Example":null},{"Service":"deploy","Name":"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.","Method":"GET","Path":"/v1/deploy/health","Args":[],"Flags":null,"Example":null},{"Service":"deploy","Name":"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.","Method":"GET","Path":"/v1/deploy/login","Args":[],"Flags":null,"Example":null},{"Service":"deploy","Name":"logout-create","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.","Method":"POST","Path":"/v1/deploy/logout","Args":[],"Flags":null,"Example":null},{"Service":"deploy","Name":"projects-list","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.","Method":"GET","Path":"/v1/deploy/projects","Args":[],"Flags":null,"Example":null},{"Service":"deploy","Name":"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.","Method":"GET","Path":"/v1/deploy/session/userinfo","Args":[],"Flags":null,"Example":null},{"Service":"deploy","Name":"stream-applications-list","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.","Method":"GET","Path":"/v1/deploy/stream/applications","Args":[],"Flags":null,"Example":null},{"Service":"deploy","Name":"stream-applications-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.","Method":"GET","Path":"/v1/deploy/stream/applications/:name/resource-tree","Args":[{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"destination","Name":"create","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.","Method":"POST","Path":"/v1/destination/:platform","Args":[{"Name":"platform","Help":""}],"Flags":null,"Example":null},{"Service":"destination","Name":"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.","Method":"DELETE","Path":"/v1/destination/:platform","Args":[{"Name":"platform","Help":"Platform is the destination to act on, from the path: ga4 | meta | tiktok |\nlinkedin | x | reddit | insights."}],"Flags":null,"Example":{"platform":"ga4"}},{"Service":"destination","Name":"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.","Method":"GET","Path":"/v1/destination/:platform","Args":[{"Name":"platform","Help":"Platform is the destination to act on, from the path: ga4 | meta | tiktok |\nlinkedin | x | reddit | insights."}],"Flags":null,"Example":{"platform":"ga4"}},{"Service":"destination","Name":"list","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.","Method":"GET","Path":"/v1/destination","Args":[],"Flags":null,"Example":null},{"Service":"destination","Name":"test","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.","Method":"POST","Path":"/v1/destination/:platform/test","Args":[{"Name":"platform","Help":"Platform is the destination to act on, from the path: ga4 | meta | tiktok |\nlinkedin | x | reddit | insights."}],"Flags":null,"Example":{"platform":"ga4"}},{"Service":"dns","Name":"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.","Method":"GET","Path":"/v1/dns/health","Args":[],"Flags":null,"Example":null},{"Service":"dns","Name":"sync-create","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.","Method":"POST","Path":"/v1/dns/sync","Args":[],"Flags":null,"Example":null},{"Service":"dns","Name":"zones-create","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.","Method":"POST","Path":"/v1/dns/zones","Args":[],"Flags":null,"Example":null},{"Service":"dns","Name":"zones-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.","Method":"DELETE","Path":"/v1/dns/zones/:zone","Args":[{"Name":"zone","Help":""}],"Flags":null,"Example":null},{"Service":"dns","Name":"zones-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.","Method":"DELETE","Path":"/v1/dns/zones/:zone/records/:record","Args":[{"Name":"zone","Help":""},{"Name":"record","Help":""}],"Flags":null,"Example":null},{"Service":"dns","Name":"zones-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.","Method":"GET","Path":"/v1/dns/zones/:zone","Args":[{"Name":"zone","Help":""}],"Flags":null,"Example":null},{"Service":"dns","Name":"zones-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.","Method":"GET","Path":"/v1/dns/zones/:zone/records/:record","Args":[{"Name":"zone","Help":""},{"Name":"record","Help":""}],"Flags":null,"Example":null},{"Service":"dns","Name":"zones-list","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.","Method":"GET","Path":"/v1/dns/zones","Args":[],"Flags":null,"Example":null},{"Service":"dns","Name":"zones-records","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.","Method":"POST","Path":"/v1/dns/zones/:zone/records","Args":[{"Name":"zone","Help":""}],"Flags":null,"Example":null},{"Service":"dns","Name":"zones-records-list","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.","Method":"GET","Path":"/v1/dns/zones/:zone/records","Args":[{"Name":"zone","Help":""}],"Flags":null,"Example":null},{"Service":"dns","Name":"zones-update","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.","Method":"PATCH","Path":"/v1/dns/zones/:zone/records/:record","Args":[{"Name":"zone","Help":""},{"Name":"record","Help":""}],"Flags":null,"Example":null},{"Service":"dns","Name":"zones-update","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.","Method":"PUT","Path":"/v1/dns/zones/:zone/records/:record","Args":[{"Name":"zone","Help":""},{"Name":"record","Help":""}],"Flags":null,"Example":null},{"Service":"domain","Name":"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.","Method":"GET","Path":"/v1/domain/availability","Args":[],"Flags":[{"Name":"domain","Field":"domain","Type":"string","Help":"Domain is one name, or several comma-separated, to check in one call. Names\nare lowercased. It is required.","Required":true}],"Example":null},{"Service":"domain","Name":"domains-list","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.","Method":"GET","Path":"/v1/domain/domains","Args":[],"Flags":null,"Example":null},{"Service":"domain","Name":"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.","Method":"GET","Path":"/v1/domain/health","Args":[],"Flags":null,"Example":null},{"Service":"domain","Name":"register-create","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.","Method":"POST","Path":"/v1/domain/register","Args":[],"Flags":[{"Name":"contacts","Field":"contacts","Type":"json","Help":"Contacts is the WHOIS contact set. Omit it and the registrar uses the\nreseller account's default contacts.","Required":false},{"Name":"domain","Field":"domain","Type":"string","Help":"Domain is the name to buy. It is required.","Required":true},{"Name":"years","Field":"years","Type":"integer","Help":"Years is the term to buy, defaulting to 1.","Required":false}],"Example":null},{"Service":"domain","Name":"renew-create","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.","Method":"POST","Path":"/v1/domain/renew","Args":[],"Flags":[{"Name":"domain","Field":"domain","Type":"string","Help":"Domain is the name to extend. It is required, and the caller's org must hold it.","Required":true},{"Name":"years","Field":"years","Type":"integer","Help":"Years is how much longer to hold it, defaulting to 1.","Required":false}],"Example":null},{"Service":"domain","Name":"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.","Method":"GET","Path":"/v1/domain/search","Args":[],"Flags":[{"Name":"q","Field":"q","Type":"string","Help":"Q is the keyword to build names from. It is required.","Required":true},{"Name":"tld","Field":"tld","Type":"string","Help":"TLD narrows the search to a comma-separated set of top-level domains.","Required":false}],"Example":null},{"Service":"domain","Name":"transfer-create","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.","Method":"POST","Path":"/v1/domain/transfer","Args":[],"Flags":[{"Name":"auth-code","Field":"authCode","Type":"string","Help":"AuthCode is the transfer authorization the losing registrar issued. It is\nrequired.","Required":true},{"Name":"domain","Field":"domain","Type":"string","Help":"Domain is the name to move in. It is required.","Required":true},{"Name":"years","Field":"years","Type":"integer","Help":"Years is the term to buy on transfer, defaulting to 1.","Required":false}],"Example":null},{"Service":"email","Name":"create","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","Method":"POST","Path":"/v1/email","Args":[],"Flags":[{"Name":"body","Field":"body","Type":"string","Help":"Body is an alias for Text for backward compatibility.","Required":false},{"Name":"from","Field":"from","Type":"string","Help":"From is the sender address. If empty, the org's provider default is used.","Required":false},{"Name":"headers","Field":"headers","Type":"json","Help":"Headers provides optional custom MIME headers.","Required":false},{"Name":"html","Field":"html","Type":"string","Help":"HTML is the HTML body.","Required":false},{"Name":"idempotency-key","Field":"idempotency_key","Type":"string","Help":"IdempotencyKey prevents duplicate message dispatches on network retries.","Required":false},{"Name":"provider","Field":"provider","Type":"string","Help":"Provider optionally pins a provider (e.g. \"mail\", \"twilio_email\").","Required":false},{"Name":"subject","Field":"subject","Type":"string","Help":"Subject is the message subject.","Required":false},{"Name":"sync","Field":"sync","Type":"string","Help":"Sync is accepted for backwards compatibility with notify sends.","Required":false},{"Name":"template-id","Field":"template_id","Type":"string","Help":"TemplateID optionally references a built-in template.","Required":false},{"Name":"template-vars","Field":"template_vars","Type":"json","Help":"TemplateVars carries variables for template rendering.","Required":false},{"Name":"text","Field":"text","Type":"string","Help":"Text is the plain text body.","Required":false},{"Name":"to","Field":"to","Type":"json","Help":"To lists destination recipient addresses.","Required":false}],"Example":null},{"Service":"email","Name":"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","Method":"GET","Path":"/v1/email/:id","Args":[{"Name":"id","Help":"ID is the unique identifier of the message to retrieve."}],"Flags":null,"Example":null},{"Service":"email","Name":"list","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","Method":"GET","Path":"/v1/email","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit is the maximum number of messages to return (default 50, max 200).","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status filters messages by delivery status.","Required":false}],"Example":null},{"Service":"email","Name":"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","Method":"GET","Path":"/v1/email/sendgrid/status","Args":[],"Flags":[{"Name":"domain","Field":"domain","Type":"string","Help":"Domain is an optional sending domain to generate SendGrid whitelabel DKIM, Return-Path, and DMARC records for.","Required":false}],"Example":null},{"Service":"email","Name":"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","Method":"GET","Path":"/v1/email/ses/status","Args":[],"Flags":[{"Name":"domain","Field":"domain","Type":"string","Help":"Domain optionally specifies the sending domain to generate Easy DKIM and MAIL FROM records for.","Required":false}],"Example":null},{"Service":"email","Name":"verify-create","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","Method":"POST","Path":"/v1/email/verify","Args":[],"Flags":[{"Name":"checks","Field":"checks","Type":"json","Help":"Checks explicitly selects which checks to run.\nDefaults to [\"syntax\", \"domain\", \"mx\", \"classification\"].","Required":false},{"Name":"email","Field":"email","Type":"string","Help":"Email is the address to evaluate.","Required":false},{"Name":"from-email","Field":"from_email","Type":"string","Help":"FromEmail sets sender used in MAIL FROM for SMTP probe when explicitly enabled.","Required":false},{"Name":"hello-name","Field":"hello_name","Type":"string","Help":"HelloName sets domain used in EHLO for SMTP probe when explicitly enabled.","Required":false},{"Name":"proxy-uri","Field":"proxy_uri","Type":"string","Help":"ProxyURI sets optional proxy for network lookups.","Required":false},{"Name":"suggestions","Field":"suggestions","Type":"boolean","Help":"Suggestions requests domain typo suggestions without altering the original email.","Required":false}],"Example":null},{"Service":"email","Name":"webhooks-sendgrid-create","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","Method":"POST","Path":"/v1/email/webhooks/sendgrid","Args":[],"Flags":null,"Example":null},{"Service":"email","Name":"webhooks-ses-create","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","Method":"POST","Path":"/v1/email/webhooks/ses","Args":[],"Flags":null,"Example":null},{"Service":"embeddings","Name":"create","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.","Method":"POST","Path":"/v1/embeddings","Args":[],"Flags":[{"Name":"dimensions","Field":"dimensions","Type":"integer","Help":"","Required":false},{"Name":"encoding-format","Field":"encoding_format","Type":"string","Help":"","Required":false},{"Name":"input","Field":"input","Type":"json","Help":"","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"","Required":false},{"Name":"user","Field":"user","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"engine","Name":"model","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.","Method":"GET","Path":"/v1/engine/model","Args":[],"Flags":[{"Name":"model","Field":"model","Type":"string","Help":"Model is the model id to inspect, exactly as the model list reports it.","Required":false}],"Example":{"model":"Qwen/Qwen3-4B"}},{"Service":"engine","Name":"models","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.","Method":"GET","Path":"/v1/engine/models","Args":[],"Flags":null,"Example":null},{"Service":"engine","Name":"status","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.","Method":"GET","Path":"/v1/engine/status","Args":[],"Flags":null,"Example":null},{"Service":"engine","Name":"system","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.","Method":"GET","Path":"/v1/engine/system","Args":[],"Flags":null,"Example":null},{"Service":"entitlement","Name":"list","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.","Method":"GET","Path":"/v1/entitlement","Args":[],"Flags":null,"Example":null},{"Service":"entitlement","Name":"orgs-create","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.","Method":"POST","Path":"/v1/entitlement/orgs/:org","Args":[{"Name":"org","Help":""}],"Flags":[{"Name":"add","Field":"add","Type":"json","Help":"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.","Required":false},{"Name":"remove","Field":"remove","Type":"json","Help":"Remove is the product ids to turn OFF. Disabling is never gated.","Required":false}],"Example":{"add":["chat"],"remove":["engine"]}},{"Service":"entitlement","Name":"orgs-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.","Method":"GET","Path":"/v1/entitlement/orgs/:org","Args":[{"Name":"org","Help":""}],"Flags":null,"Example":null},{"Service":"environment","Name":"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.","Method":"DELETE","Path":"/v1/environment/:repo","Args":[{"Name":"repo","Help":"Repo is the repository's name in the caller's org — a name, never owner/name."}],"Flags":null,"Example":null},{"Service":"environment","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.","Method":"DELETE","Path":"/v1/environment/:repo/secrets/:name","Args":[{"Name":"repo","Help":"Repo is the repository's name in the caller's org."},{"Name":"name","Help":"Name is the secret's environment variable name."}],"Flags":null,"Example":null},{"Service":"environment","Name":"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.","Method":"GET","Path":"/v1/environment/:repo","Args":[{"Name":"repo","Help":"Repo is the repository's name in the caller's org — a name, never owner/name."}],"Flags":null,"Example":null},{"Service":"environment","Name":"list","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.","Method":"GET","Path":"/v1/environment","Args":[],"Flags":null,"Example":null},{"Service":"environment","Name":"update","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.","Method":"PUT","Path":"/v1/environment/:repo","Args":[{"Name":"repo","Help":"Repo is the repository's name in the caller's org."}],"Flags":[{"Name":"install","Field":"install","Type":"string","Help":"Install is run in every fresh checkout before the agent starts, from the\nrepository root, and must be non-interactive. Empty installs nothing.","Required":false},{"Name":"start","Field":"start","Type":"string","Help":"Start is left running in the background after the install. Empty starts\nnothing.","Required":false}],"Example":null},{"Service":"environment","Name":"update","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.","Method":"PUT","Path":"/v1/environment/:repo/secrets/:name","Args":[{"Name":"repo","Help":"Repo is the repository's name in the caller's org."},{"Name":"name","Help":"Name is the environment variable the run exports the value under."}],"Flags":[{"Name":"value","Field":"value","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"esign","Name":"documents-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.","Method":"GET","Path":"/v1/esign/documents/:id/audit","Args":[{"Name":"id","Help":"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."}],"Flags":null,"Example":null},{"Service":"esign","Name":"documents-create","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.","Method":"POST","Path":"/v1/esign/documents","Args":[],"Flags":[{"Name":"external-id","Field":"externalId","Type":"json","Help":"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.","Required":false},{"Name":"message","Field":"message","Type":"json","Help":"Message is the covering message carried with the document. Optional, and like\nthe subject it is stored rather than sent.","Required":false},{"Name":"pdf-base64","Field":"pdfBase64","Type":"json","Help":"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.","Required":false},{"Name":"signing-order","Field":"signingOrder","Type":"json","Help":"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.","Required":false},{"Name":"subject","Field":"subject","Type":"json","Help":"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.","Required":false},{"Name":"title","Field":"title","Type":"json","Help":"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.","Required":false}],"Example":{"pdfBase64":"JVBERi0xLjQK…","signingOrder":"SEQUENTIAL","title":"Mutual NDA"}},{"Service":"esign","Name":"documents-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.","Method":"GET","Path":"/v1/esign/documents/:id/download","Args":[{"Name":"id","Help":"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."}],"Flags":null,"Example":null},{"Service":"esign","Name":"documents-fields","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.","Method":"POST","Path":"/v1/esign/documents/:id/fields","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"field-meta","Field":"fieldMeta","Type":"json","Help":"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.","Required":false},{"Name":"height","Field":"height","Type":"json","Help":"Height is the field's height, defaulting to -1, which means the renderer\nchooses one when the document is sealed.","Required":false},{"Name":"page","Field":"page","Type":"json","Help":"Page is the 1-based page the field sits on, defaulting to 1.","Required":false},{"Name":"position-x","Field":"positionX","Type":"json","Help":"PositionX is the field's horizontal position on that page, defaulting to 0.","Required":false},{"Name":"position-y","Field":"positionY","Type":"json","Help":"PositionY is the field's vertical position on that page, defaulting to 0.","Required":false},{"Name":"recipient-id","Field":"recipientId","Type":"json","Help":"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.","Required":false},{"Name":"type","Field":"type","Type":"json","Help":"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.","Required":false},{"Name":"width","Field":"width","Type":"json","Help":"Width is the field's width, defaulting to -1, which means the renderer\nchooses one when the document is sealed.","Required":false}],"Example":{"page":1,"positionX":72,"positionY":640,"recipientId":"rec_2f…","type":"SIGNATURE"}},{"Service":"esign","Name":"documents-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.","Method":"GET","Path":"/v1/esign/documents/:id","Args":[{"Name":"id","Help":"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."}],"Flags":null,"Example":null},{"Service":"esign","Name":"documents-list","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.","Method":"GET","Path":"/v1/esign/documents","Args":[],"Flags":null,"Example":null},{"Service":"esign","Name":"documents-recipients","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.","Method":"POST","Path":"/v1/esign/documents/:id/recipients","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"email","Field":"email","Type":"json","Help":"Email is where the signing link is meant to go, lower-cased on the way in.\nRequired.","Required":false},{"Name":"name","Field":"name","Type":"json","Help":"Name is the recipient's display name, also the fallback a NAME field is\nfilled with when they leave it blank. Optional.","Required":false},{"Name":"role","Field":"role","Type":"json","Help":"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.","Required":false},{"Name":"signing-order","Field":"signingOrder","Type":"json","Help":"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.","Required":false}],"Example":{"email":"counterparty@example.com","name":"Dana Lee","role":"SIGNER"}},{"Service":"esign","Name":"documents-send","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.","Method":"POST","Path":"/v1/esign/documents/:id/send","Args":[{"Name":"id","Help":"ID is the document to send. The URL is the addressing authority."}],"Flags":null,"Example":null},{"Service":"esign","Name":"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.","Method":"GET","Path":"/v1/esign/health","Args":[],"Flags":null,"Example":null},{"Service":"esign","Name":"o-complete","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.","Method":"POST","Path":"/v1/esign/o/:org/sign/:token/complete","Args":[{"Name":"org","Help":""},{"Name":"token","Help":""}],"Flags":null,"Example":null},{"Service":"esign","Name":"o-create","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.","Method":"POST","Path":"/v1/esign/o/:org/sign/:token/fields/:fieldId","Args":[{"Name":"org","Help":""},{"Name":"token","Help":""},{"Name":"fieldId","Help":""}],"Flags":[{"Name":"is-base64","Field":"isBase64","Type":"json","Help":"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.","Required":false},{"Name":"value","Field":"value","Type":"json","Help":"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.","Required":false}],"Example":{"isBase64":false,"value":"Dana Lee"}},{"Service":"esign","Name":"o-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.","Method":"GET","Path":"/v1/esign/o/:org/sign/:token","Args":[{"Name":"org","Help":""},{"Name":"token","Help":""}],"Flags":null,"Example":null},{"Service":"esign","Name":"o-reject","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.","Method":"POST","Path":"/v1/esign/o/:org/sign/:token/reject","Args":[{"Name":"org","Help":""},{"Name":"token","Help":""}],"Flags":[{"Name":"reason","Field":"reason","Type":"json","Help":"Reason is why the signer is declining. Optional, stored, and written onto the\naudit trail with the rejection — it is what the sender sees.","Required":false}],"Example":{"reason":"Terms changed since we agreed them."}},{"Service":"eval","Name":"datasets-create","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.","Method":"POST","Path":"/v1/eval/datasets","Args":[],"Flags":[{"Name":"description","Field":"description","Type":"string","Help":"Description is free text about what this set measures; over 64 KiB is refused.","Required":false},{"Name":"metadata","Field":"metadata","Type":"json","Help":"Metadata is a free-form object stored with the set and echoed back verbatim.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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}$.","Required":true}],"Example":null},{"Service":"eval","Name":"datasets-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.","Method":"DELETE","Path":"/v1/eval/datasets/:name","Args":[{"Name":"name","Help":"Name is the dataset the URL names."}],"Flags":null,"Example":null},{"Service":"eval","Name":"datasets-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.","Method":"GET","Path":"/v1/eval/datasets/:name","Args":[{"Name":"name","Help":"Name is the dataset the URL names."}],"Flags":null,"Example":null},{"Service":"eval","Name":"datasets-items","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.","Method":"POST","Path":"/v1/eval/datasets/:name/items","Args":[{"Name":"name","Help":""}],"Flags":[{"Name":"expected-output","Field":"expectedOutput","Type":"json","Help":"Expected is the answer a correct model produces, which the judge grades\nagainst, stored as raw JSON exactly as sent, up to 64 KiB.","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"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.","Required":false},{"Name":"input","Field":"input","Type":"json","Help":"Input is what the model under test will be given, stored as raw JSON exactly\nas sent, up to 64 KiB.","Required":false},{"Name":"metadata","Field":"metadata","Type":"json","Help":"Metadata is a free-form object stored with the example.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"eval","Name":"datasets-items-list","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.","Method":"GET","Path":"/v1/eval/datasets/:name/items","Args":[{"Name":"name","Help":"Dataset is the set to read, from the path — this collection only exists\ninside one."}],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"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.","Required":false}],"Example":null},{"Service":"eval","Name":"datasets-list","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.","Method":"GET","Path":"/v1/eval/datasets","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"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.","Required":false}],"Example":null},{"Service":"eval","Name":"evaluators-create","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.","Method":"POST","Path":"/v1/eval/evaluators","Args":[],"Flags":[{"Name":"criteria","Field":"criteria","Type":"string","Help":"Criteria is the written standard the judge applies; over 64 KiB is refused.","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"Model is the model that will do the grading.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":true},{"Name":"score-name","Field":"scoreName","Type":"string","Help":"ScoreName is the name the resulting scores are filed under. It defaults to\nthe judge's own name and must match the same pattern.","Required":false}],"Example":null},{"Service":"eval","Name":"evaluators-list","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.","Method":"GET","Path":"/v1/eval/evaluators","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"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.","Required":false}],"Example":null},{"Service":"eval","Name":"metrics-list","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.","Method":"GET","Path":"/v1/eval/metrics","Args":[],"Flags":[{"Name":"range","Field":"range","Type":"string","Help":"Range is 24h (the default), 7d or 30d. Anything else normalises to 24h\nrather than failing, so the board always has a valid window.","Required":false},{"Name":"interval","Field":"interval","Type":"string","Help":"Interval overrides the bucket the series is grouped into: \"hour\" or \"day\".\nAny other value leaves the range's own default in place.","Required":false}],"Example":null},{"Service":"eval","Name":"rubrics-create","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.","Method":"POST","Path":"/v1/eval/rubrics","Args":[],"Flags":[{"Name":"categories","Field":"categories","Type":"json","Help":"Categories is the closed set of labels a CATEGORICAL score may carry. A\nCATEGORICAL rubric with none is refused.","Required":false},{"Name":"data-type","Field":"dataType","Type":"string","Help":"DataType is NUMERIC (the default), CATEGORICAL or BOOLEAN.","Required":false},{"Name":"max-value","Field":"maxValue","Type":"number","Help":"MaxValue is the inclusive ceiling a NUMERIC score must stay under, finite.","Required":false},{"Name":"min-value","Field":"minValue","Type":"number","Help":"MinValue is the inclusive floor a NUMERIC score must clear. It must be\nfinite and must not exceed MaxValue.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":true}],"Example":null},{"Service":"eval","Name":"rubrics-list","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.","Method":"GET","Path":"/v1/eval/rubrics","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"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.","Required":false}],"Example":null},{"Service":"eval","Name":"runs-create","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.","Method":"POST","Path":"/v1/eval/runs","Args":[],"Flags":[{"Name":"dataset","Field":"dataset","Type":"string","Help":"Dataset is the set to score, which must belong to the caller's org and hold\nat least one ACTIVE example.","Required":true},{"Name":"judge","Field":"judge","Type":"json","Help":"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\".","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many examples this run scores. It defaults to 20, and\nanything above 100 falls back to that default.","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"Model is the model under test.","Required":true},{"Name":"run-name","Field":"runName","Type":"string","Help":"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}$.","Required":false}],"Example":null},{"Service":"eval","Name":"runs-list","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.","Method":"GET","Path":"/v1/eval/runs","Args":[],"Flags":[{"Name":"dataset-name","Field":"datasetName","Type":"string","Help":"Dataset narrows to the runs against one dataset.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"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.","Required":false}],"Example":null},{"Service":"eval","Name":"scores-create","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.","Method":"POST","Path":"/v1/eval/scores","Args":[],"Flags":[{"Name":"comment","Field":"comment","Type":"string","Help":"Comment is the grader's reasoning, truncated at 2000 characters.","Required":false},{"Name":"data-type","Field":"dataType","Type":"string","Help":"DataType is NUMERIC, CATEGORICAL or BOOLEAN. A declared rubric overrides it\n— a caller cannot claim a type the org's rubric contradicts.","Required":false},{"Name":"dataset-item-id","Field":"datasetItemId","Type":"string","Help":"ItemID attaches the score to one graded example.","Required":false},{"Name":"dataset-name","Field":"datasetName","Type":"string","Help":"Dataset attaches the score to one dataset.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":true},{"Name":"run-name","Field":"runName","Type":"string","Help":"RunName attaches the score to one run.","Required":false},{"Name":"string-value","Field":"stringValue","Type":"string","Help":"StringValue is the label of a CATEGORICAL score, which must be one the\nrubric allows.","Required":false},{"Name":"trace-id","Field":"traceId","Type":"string","Help":"TraceID attaches the score to one model call.","Required":false},{"Name":"value","Field":"value","Type":"number","Help":"Value is the numeric score, which must be finite: NaN and Inf are refused.\nA BOOLEAN score takes 0 or 1.","Required":false}],"Example":null},{"Service":"eval","Name":"scores-list","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\".","Method":"GET","Path":"/v1/eval/scores","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"Name narrows to one score name.","Required":false},{"Name":"run-name","Field":"runName","Type":"string","Help":"RunName narrows to the scores of one run.","Required":false},{"Name":"trace-id","Field":"traceId","Type":"string","Help":"TraceID narrows to the scores on one model call.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"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.","Required":false}],"Example":null},{"Service":"eval","Name":"traces-list","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.","Method":"GET","Path":"/v1/eval/traces","Args":[],"Flags":[{"Name":"session-id","Field":"sessionId","Type":"string","Help":"SessionID narrows to one session, which for an evaluation is one run.","Required":false},{"Name":"run-name","Field":"runName","Type":"string","Help":"RunName narrows to the calls one run made.","Required":false},{"Name":"dataset-name","Field":"datasetName","Type":"string","Help":"Dataset narrows to the calls made against one dataset.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"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.","Required":false}],"Example":null},{"Service":"event","Name":"create","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.","Method":"POST","Path":"/v1/event","Args":[],"Flags":null,"Example":null},{"Service":"event","Name":"economic-dispute-create","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.","Method":"POST","Path":"/v1/event/economic/dispute","Args":[],"Flags":[{"Name":"event","Field":"event","Type":"string","Help":"Event is the id of the economic event disputed.","Required":true},{"Name":"reason","Field":"reason","Type":"string","Help":"Reason is what the caller's org says is wrong, at most 1024 characters.","Required":true}],"Example":{"event":"econ_4f1c…","reason":"the service was never delivered"}},{"Service":"event","Name":"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.","Method":"GET","Path":"/v1/event/economic","Args":[],"Flags":[{"Name":"year","Field":"year","Type":"integer","Help":"Year is the calendar year to read, UTC.","Required":true},{"Name":"counterparty","Field":"counterparty","Type":"string","Help":"Counterparty keeps only payments with this org on the other side.","Required":false},{"Name":"rail","Field":"rail","Type":"string","Help":"Rail keeps only payments that moved on this rail.","Required":false},{"Name":"cursor","Field":"cursor","Type":"string","Help":"Cursor continues from the next of the page before; empty starts the year.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit is how many events to answer, default 100 and at most 1000.","Required":false}],"Example":{"rail":"x402","year":2026}},{"Service":"event","Name":"errors-list","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.","Method":"GET","Path":"/v1/event/errors","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"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.","Required":false}],"Example":{"limit":100}},{"Service":"event","Name":"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.","Method":"GET","Path":"/v1/event/health","Args":[],"Flags":null,"Example":null},{"Service":"event","Name":"insights-events-list","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.","Method":"GET","Path":"/v1/event/insights/events","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"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.","Required":false},{"Name":"impersonated","Field":"impersonated","Type":"string","Help":"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.","Required":false}],"Example":{"limit":100}},{"Service":"event","Name":"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.","Method":"GET","Path":"/v1/event/insights/health","Args":[],"Flags":null,"Example":null},{"Service":"event","Name":"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.","Method":"GET","Path":"/v1/event/overview","Args":[],"Flags":[{"Name":"range","Field":"range","Type":"string","Help":"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.","Required":false},{"Name":"start","Field":"start","Type":"string","Help":"Start is the inclusive lower bound of a custom window, RFC3339. Requires end.","Required":false},{"Name":"end","Field":"end","Type":"string","Help":"End is the exclusive upper bound of a custom window, RFC3339. Requires start.","Required":false},{"Name":"impersonated","Field":"impersonated","Type":"string","Help":"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.","Required":false}],"Example":{"range":"7d"}},{"Service":"event","Name":"pixel-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.","Method":"GET","Path":"/v1/event/pixel/:key","Args":[{"Name":"key","Help":""}],"Flags":null,"Example":null,"Stream":"bytes"},{"Service":"event","Name":"replay-create","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.","Method":"POST","Path":"/v1/event/replay","Args":[],"Flags":[{"Name":"consent","Field":"consent","Type":"json","Help":"","Required":false},{"Name":"distinct-id","Field":"distinctId","Type":"string","Help":"","Required":false},{"Name":"events","Field":"events","Type":"json","Help":"","Required":false},{"Name":"session-id","Field":"sessionId","Type":"string","Help":"","Required":false},{"Name":"window-id","Field":"windowId","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"event","Name":"tag-js-list","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.","Method":"GET","Path":"/v1/event/tag.js","Args":[],"Flags":null,"Example":null,"Stream":"bytes"},{"Service":"event","Name":"timeseries-list","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.","Method":"GET","Path":"/v1/event/timeseries","Args":[],"Flags":[{"Name":"range","Field":"range","Type":"string","Help":"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.","Required":false},{"Name":"start","Field":"start","Type":"string","Help":"Start is the inclusive lower bound of a custom window, RFC3339. Requires end.","Required":false},{"Name":"end","Field":"end","Type":"string","Help":"End is the exclusive upper bound of a custom window, RFC3339. Requires start.","Required":false}],"Example":{"range":"30d"}},{"Service":"event","Name":"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.","Method":"GET","Path":"/v1/event/top","Args":[],"Flags":[{"Name":"range","Field":"range","Type":"string","Help":"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.","Required":false},{"Name":"start","Field":"start","Type":"string","Help":"Start is the inclusive lower bound of a custom window, RFC3339. Requires end.","Required":false},{"Name":"end","Field":"end","Type":"string","Help":"End is the exclusive upper bound of a custom window, RFC3339. Requires start.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"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.","Required":false},{"Name":"impersonated","Field":"impersonated","Type":"string","Help":"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.","Required":false}],"Example":{"limit":25,"range":"7d"}},{"Service":"exec","Name":"create","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.","Method":"POST","Path":"/v1/exec","Args":[],"Flags":[{"Name":"args","Field":"args","Type":"json","Help":"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.","Required":false},{"Name":"code","Field":"code","Type":"string","Help":"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.","Required":true},{"Name":"files","Field":"files","Type":"json","Help":"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.","Required":false},{"Name":"lang","Field":"lang","Type":"string","Help":"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.","Required":true},{"Name":"runtime-session-hint","Field":"runtime_session_hint","Type":"string","Help":"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.","Required":false},{"Name":"session-id","Field":"session_id","Type":"string","Help":"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.","Required":false},{"Name":"user-id","Field":"user_id","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"exec","Name":"files-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.","Method":"GET","Path":"/v1/exec/files/:sid","Args":[{"Name":"sid","Help":"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."}],"Flags":null,"Example":null},{"Service":"exec","Name":"upload-create","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.","Method":"POST","Path":"/v1/exec/upload","Args":[],"Flags":null,"Example":null},{"Service":"experiment","Name":"analyze","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.","Method":"POST","Path":"/v1/experiment/:id/analyze","Args":[{"Name":"id","Help":"ID is the experiment the URL names."}],"Flags":[{"Name":"alpha","Field":"alpha","Type":"number","Help":"Alpha overrides the 0.05 two-tailed significance threshold when it lies\nstrictly between 0 and 1; anything else leaves the default in place.","Required":false},{"Name":"days","Field":"days","Type":"integer","Help":"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.","Required":false},{"Name":"end","Field":"end","Type":"string","Help":"End is the window's exclusive end in RFC3339, defaulting to now.","Required":false},{"Name":"start","Field":"start","Type":"string","Help":"Start is the window's inclusive start in RFC3339. Given, it wins over days.","Required":false}],"Example":null},{"Service":"experiment","Name":"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.","Method":"GET","Path":"/v1/experiment/:id/assign","Args":[{"Name":"id","Help":"ID is the experiment the URL names."}],"Flags":[{"Name":"subject","Field":"subject","Type":"string","Help":"Subject is the unit to bucket — a user, org, session or audience key,\nmatching the experiment's subjectKind.","Required":true},{"Name":"props","Field":"props","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"experiment","Name":"create","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.","Method":"POST","Path":"/v1/experiment","Args":[],"Flags":[{"Name":"exposure-event","Field":"exposureEvent","Type":"string","Help":"ExposureEvent is the event that marks a subject as enrolled — the analysis\ndenominator — defaulting to the SDK's $feature_flag_called marker.","Required":false},{"Name":"flag-key","Field":"flagKey","Type":"string","Help":"FlagKey names the assignment flag this experiment writes, defaulting to\nexp_\u003cid\u003e. It must be a slug.","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"ID is the experiment's slug, claimed once per project. It must match\n[A-Za-z0-9][A-Za-z0-9._-]{0,127}.","Required":true},{"Name":"metric-event","Field":"metricEvent","Type":"string","Help":"MetricEvent is the event that counts as a conversion — the analysis\nnumerator.","Required":true},{"Name":"name","Field":"name","Type":"string","Help":"Name is free text for a reader; the id is what addresses the experiment.","Required":false},{"Name":"subject-kind","Field":"subjectKind","Type":"string","Help":"SubjectKind is the unit assigned and measured: user (the default), org,\nsession or audience.","Required":false},{"Name":"variants","Field":"variants","Type":"json","Help":"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.","Required":true}],"Example":null},{"Service":"experiment","Name":"decide","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.","Method":"POST","Path":"/v1/experiment/:id/decide","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"winner","Field":"winner","Type":"string","Help":"Winner is the variant to promote. It must name one of this experiment's own\narms.","Required":true}],"Example":null},{"Service":"experiment","Name":"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.","Method":"GET","Path":"/v1/experiment/:id","Args":[{"Name":"id","Help":"ID is the experiment the URL names."}],"Flags":null,"Example":null},{"Service":"experiment","Name":"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.","Method":"GET","Path":"/v1/experiment/health","Args":[],"Flags":null,"Example":null},{"Service":"experiment","Name":"list","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.","Method":"GET","Path":"/v1/experiment","Args":[],"Flags":null,"Example":null},{"Service":"explorer","Name":"indexers-list","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.","Method":"GET","Path":"/v1/explorer/indexers","Args":[],"Flags":null,"Example":null},{"Service":"explorer","Name":"oracles-list","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.","Method":"GET","Path":"/v1/explorer/oracles","Args":[],"Flags":null,"Example":null},{"Service":"flag","Name":"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.","Method":"GET","Path":"/v1/flag/activity","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the rows returned. 1–500; anything else takes the default 100.","Required":false}],"Example":null},{"Service":"flag","Name":"create","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.","Method":"POST","Path":"/v1/flag","Args":[],"Flags":[{"Name":"distinct-id","Field":"distinct_id","Type":"string","Help":"DistinctID is the identity the flags are evaluated for. Required.","Required":false},{"Name":"groups","Field":"groups","Type":"json","Help":"Groups are the group-level properties, keyed by group type index.","Required":false},{"Name":"person-properties","Field":"person_properties","Type":"json","Help":"PersonProperties are the person-level properties conditions match against.","Required":false}],"Example":{"distinct_id":"u1","groups":{"0":{"key":"acme"}},"person_properties":{"plan":"pro"}}},{"Service":"flag","Name":"decide-create","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.","Method":"POST","Path":"/v1/flag/decide","Args":[],"Flags":[{"Name":"distinct-id","Field":"distinct_id","Type":"string","Help":"DistinctID is the identity the flags are evaluated for. Required.","Required":false},{"Name":"groups","Field":"groups","Type":"json","Help":"Groups are the group-level properties, keyed by group type index.","Required":false},{"Name":"person-properties","Field":"person_properties","Type":"json","Help":"PersonProperties are the person-level properties conditions match against.","Required":false}],"Example":{"distinct_id":"u1","groups":{"0":{"key":"acme"}},"person_properties":{"plan":"pro"}}},{"Service":"flag","Name":"defs-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.","Method":"DELETE","Path":"/v1/flag/defs/:key","Args":[{"Name":"key","Help":"Key is the flag key to act on, from the path."}],"Flags":null,"Example":null},{"Service":"flag","Name":"defs-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.","Method":"GET","Path":"/v1/flag/defs/:key","Args":[{"Name":"key","Help":"Key is the flag key to act on, from the path."}],"Flags":null,"Example":null},{"Service":"flag","Name":"defs-list","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.","Method":"GET","Path":"/v1/flag/defs","Args":[],"Flags":null,"Example":null},{"Service":"flag","Name":"defs-update","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.","Method":"PUT","Path":"/v1/flag/defs/:key","Args":[{"Name":"key","Help":"Key is the flag key to write, from the path."}],"Flags":null,"Example":{"active":true,"filters":{"groups":[{"rollout_percentage":25}]},"key":"new-editor"}},{"Service":"flag","Name":"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.","Method":"GET","Path":"/v1/flag/health","Args":[],"Flags":null,"Example":null},{"Service":"flag","Name":"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.","Method":"GET","Path":"/v1/flag/optin","Args":[],"Flags":null,"Example":null},{"Service":"flag","Name":"optin-org-update","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.","Method":"PUT","Path":"/v1/flag/optin/org","Args":[],"Flags":[{"Name":"blocked","Field":"blocked","Type":"boolean","Help":"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.","Required":false}],"Example":{"blocked":true}},{"Service":"flag","Name":"optin-update","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.","Method":"PUT","Path":"/v1/flag/optin","Args":[],"Flags":[{"Name":"on","Field":"on","Type":"boolean","Help":"On opts the caller in to every public beta, current and future, when true,\nand out when false.","Required":false}],"Example":{"on":true}},{"Service":"flag","Name":"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.","Method":"GET","Path":"/v1/flag/platform","Args":[],"Flags":null,"Example":null},{"Service":"flow","Name":"runs-create","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.","Method":"POST","Path":"/v1/flow/runs","Args":[],"Flags":[{"Name":"input","Field":"input","Type":"string","Help":"Input is the run's chat input value, handed to the graph's input node.","Required":false},{"Name":"session","Field":"session","Type":"string","Help":"Session groups runs into one conversation; the product mints one when\nabsent and returns it in the response.","Required":false},{"Name":"tweaks","Field":"tweaks","Type":"json","Help":"Tweaks override component fields for this run only (the product's\ntweaks document), verbatim.","Required":false},{"Name":"workflow","Field":"workflow","Type":"string","Help":"Workflow is the UUID of the workflow to run.","Required":false}],"Example":{"input":"summarize today's tickets","workflow":"8f14e45f-…"}},{"Service":"flow","Name":"runs-list","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.","Method":"GET","Path":"/v1/flow/runs","Args":[],"Flags":[{"Name":"workflow","Field":"workflow","Type":"string","Help":"Workflow is the UUID of the workflow whose run records to read. It rides\nthe query string.","Required":false}],"Example":null},{"Service":"flow","Name":"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.","Method":"GET","Path":"/v1/flow/status","Args":[],"Flags":null,"Example":null},{"Service":"flow","Name":"workflows-create","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.","Method":"POST","Path":"/v1/flow/workflows","Args":[],"Flags":[{"Name":"data","Field":"data","Type":"json","Help":"Data is the workflow graph (the product's nodes/edges document),\nverbatim. Omit it to create an empty workflow.","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"Description says what the workflow does.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the workflow's display name, unique within the org's project\n(the product de-duplicates by suffixing).","Required":false}],"Example":{"description":"route tickets","name":"support-triage"}},{"Service":"flow","Name":"workflows-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.","Method":"DELETE","Path":"/v1/flow/workflows/:workflow","Args":[{"Name":"workflow","Help":"Workflow is the workflow's UUID, taken from the path."}],"Flags":null,"Example":null},{"Service":"flow","Name":"workflows-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.","Method":"GET","Path":"/v1/flow/workflows/:workflow","Args":[{"Name":"workflow","Help":"Workflow is the workflow's UUID, taken from the path."}],"Flags":null,"Example":null},{"Service":"flow","Name":"workflows-list","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.","Method":"GET","Path":"/v1/flow/workflows","Args":[],"Flags":[{"Name":"page","Field":"page","Type":"string","Help":"Page is the 1-based page of workflows to return.","Required":false},{"Name":"size","Field":"size","Type":"string","Help":"Size is how many workflows one page holds (the product caps it at 100).","Required":false}],"Example":null},{"Service":"flow","Name":"workflows-update","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.","Method":"PATCH","Path":"/v1/flow/workflows/:workflow","Args":[{"Name":"workflow","Help":"Workflow is the workflow's UUID, taken from the path."}],"Flags":[{"Name":"data","Field":"data","Type":"json","Help":"Data replaces the workflow graph when present, verbatim.","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"Description replaces the description when present.","Required":false},{"Name":"locked","Field":"locked","Type":"boolean","Help":"Locked freezes or unfreezes the workflow against edits when present.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name renames the workflow when present.","Required":false}],"Example":{"description":"route tickets to the right queue"}},{"Service":"framework","Name":"cancel","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.","Method":"POST","Path":"/v1/framework/:doctype/:name/cancel","Args":[{"Name":"doctype","Help":"DocType is the document's DocType, by ADDRESS — \"module.name\", from the path."},{"Name":"name","Help":"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."}],"Flags":null,"Example":{"doctype":"Projects.Task","name":"TASK-00001"}},{"Service":"framework","Name":"create","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.","Method":"POST","Path":"/v1/framework/:doctype","Args":[{"Name":"doctype","Help":""}],"Flags":null,"Example":null},{"Service":"framework","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.","Method":"DELETE","Path":"/v1/framework/:doctype/:name","Args":[{"Name":"doctype","Help":"DocType is the document's DocType, by ADDRESS — \"module.name\", from the path."},{"Name":"name","Help":"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."}],"Flags":null,"Example":{"doctype":"Projects.Task","name":"TASK-00001"}},{"Service":"framework","Name":"doctypes-create","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.","Method":"POST","Path":"/v1/framework/doctypes","Args":[],"Flags":[{"Name":"autoname","Field":"autoname","Type":"string","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"integer","Help":"","Required":false},{"Name":"fields","Field":"fields","Type":"json","Help":"","Required":false},{"Name":"immutable","Field":"immutable","Type":"boolean","Help":"","Required":false},{"Name":"is-single","Field":"isSingle","Type":"boolean","Help":"","Required":false},{"Name":"is-submittable","Field":"isSubmittable","Type":"boolean","Help":"","Required":false},{"Name":"module","Field":"module","Type":"string","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"permissions","Field":"permissions","Type":"json","Help":"","Required":false},{"Name":"title-field","Field":"titleField","Type":"string","Help":"","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"integer","Help":"","Required":false}],"Example":{"autoname":"TASK-.#####","fields":[{"fieldname":"subject","fieldtype":"Data","reqd":true}],"module":"Projects","name":"Task"}},{"Service":"framework","Name":"doctypes-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.","Method":"DELETE","Path":"/v1/framework/doctypes/:name","Args":[{"Name":"name","Help":"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."}],"Flags":null,"Example":{"name":"Projects.Task"}},{"Service":"framework","Name":"doctypes-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.","Method":"GET","Path":"/v1/framework/doctypes/:name","Args":[{"Name":"name","Help":"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."}],"Flags":null,"Example":{"name":"Projects.Task"}},{"Service":"framework","Name":"doctypes-list","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.","Method":"GET","Path":"/v1/framework/doctypes","Args":[],"Flags":null,"Example":null},{"Service":"framework","Name":"doctypes-update","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.","Method":"PUT","Path":"/v1/framework/doctypes/:name","Args":[{"Name":"name","Help":""}],"Flags":[{"Name":"autoname","Field":"autoname","Type":"string","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"integer","Help":"","Required":false},{"Name":"fields","Field":"fields","Type":"json","Help":"","Required":false},{"Name":"immutable","Field":"immutable","Type":"boolean","Help":"","Required":false},{"Name":"is-single","Field":"isSingle","Type":"boolean","Help":"","Required":false},{"Name":"is-submittable","Field":"isSubmittable","Type":"boolean","Help":"","Required":false},{"Name":"module","Field":"module","Type":"string","Help":"","Required":false},{"Name":"permissions","Field":"permissions","Type":"json","Help":"","Required":false},{"Name":"title-field","Field":"titleField","Type":"string","Help":"","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"integer","Help":"","Required":false}],"Example":{"fields":[{"fieldname":"subject","fieldtype":"Data"}],"name":"Projects.Task"}},{"Service":"framework","Name":"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.","Method":"GET","Path":"/v1/framework/:doctype","Args":[{"Name":"doctype","Help":"DocType is the DocType to list, by ADDRESS — \"module.name\", from the path."}],"Flags":[{"Name":"filters","Field":"filters","Type":"string","Help":"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.","Required":false},{"Name":"fields","Field":"fields","Type":"string","Help":"Fields projects the response to a subset — a JSON array [\"a\",\"b\"] or a\ncomma list \"a,b\". The envelope keys are always returned.","Required":false},{"Name":"order-by","Field":"order_by","Type":"string","Help":"OrderBy is \"\u003cfield\u003e [asc|desc]\". Empty means most-recently-updated first.","Required":false},{"Name":"limit","Field":"limit","Type":"string","Help":"Limit caps the rows returned. Anything that is not a positive integer\nleaves the engine's default in place.","Required":false}],"Example":{"doctype":"Projects.Task","filters":"{\"priority\":\"High\"}","limit":"20","order_by":"estimate asc"}},{"Service":"framework","Name":"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.","Method":"GET","Path":"/v1/framework/:doctype/:name","Args":[{"Name":"doctype","Help":"DocType is the document's DocType, by ADDRESS — \"module.name\", from the path."},{"Name":"name","Help":"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."}],"Flags":null,"Example":{"doctype":"Projects.Task","name":"TASK-00001"}},{"Service":"framework","Name":"modules-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.","Method":"GET","Path":"/v1/framework/modules/:module","Args":[{"Name":"module","Help":"Module is the lane's registered name (\"cms\", \"erp\"), from the path."}],"Flags":null,"Example":{"module":"cms"}},{"Service":"framework","Name":"modules-install","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.","Method":"POST","Path":"/v1/framework/modules/:module/install","Args":[{"Name":"module","Help":"Module is the lane's registered name (\"cms\", \"erp\"), from the path."}],"Flags":null,"Example":{"module":"cms"}},{"Service":"framework","Name":"modules-list","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.","Method":"GET","Path":"/v1/framework/modules","Args":[],"Flags":null,"Example":null},{"Service":"framework","Name":"submit","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.","Method":"POST","Path":"/v1/framework/:doctype/:name/submit","Args":[{"Name":"doctype","Help":"DocType is the document's DocType, by ADDRESS — \"module.name\", from the path."},{"Name":"name","Help":"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."}],"Flags":null,"Example":{"doctype":"Projects.Task","name":"TASK-00001"}},{"Service":"framework","Name":"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.","Method":"GET","Path":"/v1/framework/summary","Args":[],"Flags":null,"Example":null},{"Service":"framework","Name":"update","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.","Method":"PUT","Path":"/v1/framework/:doctype/:name","Args":[{"Name":"doctype","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"function","Name":"create","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.","Method":"POST","Path":"/v1/function","Args":[],"Flags":[{"Name":"code","Field":"code","Type":"string","Help":"Code is the source to run, capped so one function cannot amplify the store.","Required":false},{"Name":"env-names","Field":"envNames","Type":"json","Help":"EnvNames are the secret NAMES to mount. Values live in the secret store and\nare never carried here.","Required":false},{"Name":"environment","Field":"environment","Type":"string","Help":"Environment is a second spelling of runtime, accepted so a console that says\n\"environment\" needs no translation.","Required":false},{"Name":"handler","Field":"handler","Type":"string","Help":"Handler is the entry point within the code.","Required":false},{"Name":"image","Field":"image","Type":"string","Help":"Image names a prebuilt image to run instead of source.","Required":false},{"Name":"memory-limit","Field":"memoryLimit","Type":"string","Help":"MemoryLimit is the memory the function runs with, defaulting to 256Mi. It is\nalso the multiplier on the GB-seconds compute charge.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":true},{"Name":"namespace","Field":"namespace","Type":"string","Help":"Namespace groups functions for display. It is cosmetic — the org is the\nisolation key — and is normalised to a DNS-safe label.","Required":false},{"Name":"runtime","Field":"runtime","Type":"string","Help":"Runtime is the language the code runs under: node, python or deno.","Required":false},{"Name":"target","Field":"target","Type":"string","Help":"Target is where the function runs: sandbox (the default) or fleet, the org's\nown GPU fleet. fleet supports runtime=python only.","Required":false},{"Name":"timeout-sec","Field":"timeoutSec","Type":"integer","Help":"TimeoutSec is the per-invocation deadline, defaulting to 30 and clamped at\n900 — a larger value is capped rather than reset to the default.","Required":false}],"Example":null},{"Service":"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.","Method":"DELETE","Path":"/v1/function/:name","Args":[{"Name":"name","Help":"Name is the function the URL names."}],"Flags":null,"Example":null},{"Service":"function","Name":"deployments-list","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.","Method":"GET","Path":"/v1/function/deployments","Args":[],"Flags":null,"Example":null},{"Service":"function","Name":"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.","Method":"GET","Path":"/v1/function/:name","Args":[{"Name":"name","Help":"Name is the function the URL names."}],"Flags":null,"Example":null},{"Service":"function","Name":"invocations-list","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.","Method":"GET","Path":"/v1/function/:name/invocations","Args":[{"Name":"name","Help":"Name is the function the URL names."}],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the page, defaulting to 100.","Required":false}],"Example":null},{"Service":"function","Name":"invoke","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.","Method":"POST","Path":"/v1/function/:name/invoke","Args":[{"Name":"name","Help":""}],"Flags":[{"Name":"input","Field":"input","Type":"string","Help":"Input is what the function is given on stdin. It is opaque to this surface.","Required":false}],"Example":null},{"Service":"function","Name":"list","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.","Method":"GET","Path":"/v1/function","Args":[],"Flags":null,"Example":null},{"Service":"function","Name":"logs-list","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.","Method":"GET","Path":"/v1/function/:name/logs","Args":[{"Name":"name","Help":"Name is the function the URL names."}],"Flags":null,"Example":null},{"Service":"function","Name":"metrics-list","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.","Method":"GET","Path":"/v1/function/metrics","Args":[],"Flags":[{"Name":"range","Field":"range","Type":"string","Help":"Range is 1H, 6H, 24H (the default), 7D or 30D. Anything else falls back to\n24H rather than failing.","Required":false}],"Example":null},{"Service":"function","Name":"secrets-list","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).","Method":"GET","Path":"/v1/function/secrets","Args":[],"Flags":null,"Example":null},{"Service":"function","Name":"triggers-list","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\".","Method":"GET","Path":"/v1/function/triggers","Args":[],"Flags":null,"Example":null},{"Service":"gateway","Name":"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.","Method":"GET","Path":"/v1/gateway/config","Args":[],"Flags":null,"Example":null},{"Service":"gateway","Name":"config-update","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.","Method":"PUT","Path":"/v1/gateway/config","Args":[],"Flags":[{"Name":"cache-paths","Field":"cache_paths","Type":"json","Help":"CachePaths overrides CacheTTLSec per path PREFIX (key \"/v1/models\" → seconds).\nThe longest matching prefix wins.","Required":false},{"Name":"cache-ttl-sec","Field":"cache_ttl_sec","Type":"integer","Help":"CacheTTLSec is the org's default edge-cache TTL for its responses, in seconds;\n0 means no caching. Unset inherits the platform default.","Required":false},{"Name":"cors-origins","Field":"cors_origins","Type":"json","Help":"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.","Required":false},{"Name":"methods","Field":"methods","Type":"json","Help":"Methods is the allowlist of HTTP methods the edge accepts for this org. Empty\nmeans all are accepted.","Required":false},{"Name":"mode","Field":"mode","Type":"string","Help":"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.","Required":false},{"Name":"org-cap","Field":"org_cap","Type":"integer","Help":"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.","Required":false},{"Name":"org-rpm","Field":"org_rpm","Type":"integer","Help":"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.","Required":false},{"Name":"per-ip-rpm","Field":"per_ip_rpm","Type":"integer","Help":"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.","Required":false},{"Name":"updated-at","Field":"updated_at","Type":"integer","Help":"UpdatedAt is the unix second this policy row was last written. Server-stamped;\na client-supplied value is ignored.","Required":false},{"Name":"updated-by","Field":"updated_by","Type":"string","Help":"UpdatedBy is the validated user id that wrote this policy row. Server-stamped;\na client-supplied value is ignored.","Required":false},{"Name":"window-sec","Field":"window_sec","Type":"integer","Help":"WindowSec is the window PerIPRPM is counted over, in seconds. SuperAdmin-only.","Required":false}],"Example":{"cache_ttl_sec":30,"methods":["GET","POST"],"org_rpm":120}},{"Service":"gateway","Name":"traffic","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=.","Method":"GET","Path":"/v1/gateway/traffic","Args":[],"Flags":null,"Example":null},{"Service":"git","Name":"commits-list","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.","Method":"GET","Path":"/v1/git/:org/:repo/commits","Args":[{"Name":"org","Help":""},{"Name":"repo","Help":""}],"Flags":null,"Example":null},{"Service":"git","Name":"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.","Method":"GET","Path":"/v1/git/explore","Args":[],"Flags":null,"Example":null},{"Service":"git","Name":"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.","Method":"GET","Path":"/v1/git/:org/:repo","Args":[{"Name":"org","Help":""},{"Name":"repo","Help":""}],"Flags":null,"Example":null},{"Service":"git","Name":"git-receive-pack","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.","Method":"POST","Path":"/v1/git/:org/:project/:repo/git-receive-pack","Args":[{"Name":"org","Help":""},{"Name":"project","Help":""},{"Name":"repo","Help":""}],"Flags":[{"Name":"body","Field":"body","Type":"file","Help":"","Required":false,"In":"body"}],"Example":null,"Consumes":["application/octet-stream"]},{"Service":"git","Name":"git-receive-pack","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.","Method":"POST","Path":"/v1/git/:org/:repo/git-receive-pack","Args":[{"Name":"org","Help":""},{"Name":"repo","Help":""}],"Flags":[{"Name":"body","Field":"body","Type":"file","Help":"","Required":false,"In":"body"}],"Example":null,"Consumes":["application/octet-stream"]},{"Service":"git","Name":"git-upload-pack","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.","Method":"POST","Path":"/v1/git/:org/:project/:repo/git-upload-pack","Args":[{"Name":"org","Help":""},{"Name":"project","Help":""},{"Name":"repo","Help":""}],"Flags":[{"Name":"body","Field":"body","Type":"file","Help":"","Required":false,"In":"body"}],"Example":null,"Consumes":["application/octet-stream"]},{"Service":"git","Name":"git-upload-pack","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.","Method":"POST","Path":"/v1/git/:org/:repo/git-upload-pack","Args":[{"Name":"org","Help":""},{"Name":"repo","Help":""}],"Flags":[{"Name":"body","Field":"body","Type":"file","Help":"","Required":false,"In":"body"}],"Example":null,"Consumes":["application/octet-stream"]},{"Service":"git","Name":"info-refs-list","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.","Method":"GET","Path":"/v1/git/:org/:project/:repo/info/refs","Args":[{"Name":"org","Help":""},{"Name":"project","Help":""},{"Name":"repo","Help":""}],"Flags":null,"Example":null},{"Service":"git","Name":"info-refs-list","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.","Method":"GET","Path":"/v1/git/:org/:repo/info/refs","Args":[{"Name":"org","Help":""},{"Name":"repo","Help":""}],"Flags":null,"Example":null},{"Service":"git","Name":"link-create","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.","Method":"POST","Path":"/v1/git/link","Args":[],"Flags":[{"Name":"owner","Field":"owner","Type":"string","Help":"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.","Required":false}],"Example":{"owner":"acme"}},{"Service":"git","Name":"list","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.","Method":"GET","Path":"/v1/git","Args":[],"Flags":null,"Example":null},{"Service":"git","Name":"pools-create","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.","Method":"POST","Path":"/v1/git/pools","Args":[],"Flags":[{"Name":"labels","Field":"labels","Type":"json","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the pool's handle in this org, e.g. \"evo\" or \"spark\".","Required":false}],"Example":{"labels":["ubuntu-latest","linux/amd64"],"name":"evo"}},{"Service":"git","Name":"pools-list","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.","Method":"GET","Path":"/v1/git/pools","Args":[],"Flags":null,"Example":null},{"Service":"git","Name":"repos-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.","Method":"GET","Path":"/v1/git/repos/:name/blob","Args":[{"Name":"name","Help":"Name is the repo to read, from the :name path segment."}],"Flags":[{"Name":"ref","Field":"ref","Type":"string","Help":"Ref is a branch, tag or commit; empty means the repo's HEAD.","Required":false},{"Name":"path","Field":"path","Type":"string","Help":"Path is repo-relative; empty is the tree root. Traversal is stripped.","Required":false}],"Example":{"name":"widgets","path":"go.mod","ref":"main"}},{"Service":"git","Name":"repos-commits-list","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.","Method":"GET","Path":"/v1/git/repos/:name/commits","Args":[{"Name":"name","Help":"Name is the repo to read, from the :name path segment."}],"Flags":[{"Name":"ref","Field":"ref","Type":"string","Help":"Ref is the branch, tag or commit to walk back from; empty means HEAD.","Required":false},{"Name":"path","Field":"path","Type":"string","Help":"Path narrows the history to commits touching it; empty walks the whole ref.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the page. Anything not positive means 50; the cap is 100.","Required":false}],"Example":{"limit":2,"name":"widgets","ref":"main"}},{"Service":"git","Name":"repos-create","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.","Method":"POST","Path":"/v1/git/repos","Args":[],"Flags":[{"Name":"description","Field":"description","Type":"string","Help":"Description is a free-form blurb, max 4KiB.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"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.","Required":false},{"Name":"public","Field":"public","Type":"boolean","Help":"Public grants ANONYMOUS read (fetch) only; push and the whole control plane\nstay org-authed. Defaults to false.","Required":false}],"Example":{"description":"the widget service","name":"widgets"}},{"Service":"git","Name":"repos-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.","Method":"DELETE","Path":"/v1/git/repos/:name","Args":[{"Name":"name","Help":"Name is the repo's org-unique handle, from the :name path segment. A\ntrailing \".git\" is stripped."}],"Flags":null,"Example":{"name":"widgets"}},{"Service":"git","Name":"repos-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.","Method":"DELETE","Path":"/v1/git/repos/:name/subscriptions/:id","Args":[{"Name":"name","Help":"Name is the repo, from the :name path segment."},{"Name":"id","Help":"ID is the row to remove, from the :id path segment."}],"Flags":null,"Example":{"id":"sub_7c2e","name":"widgets"}},{"Service":"git","Name":"repos-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.","Method":"DELETE","Path":"/v1/git/repos/:name/targets/:id","Args":[{"Name":"name","Help":"Name is the repo, from the :name path segment."},{"Name":"id","Help":"ID is the row to remove, from the :id path segment."}],"Flags":null,"Example":{"id":"mir_2d90","name":"widgets"}},{"Service":"git","Name":"repos-files-list","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.","Method":"GET","Path":"/v1/git/repos/:name/files","Args":[{"Name":"name","Help":"Name is the repo to read, from the :name path segment."}],"Flags":[{"Name":"ref","Field":"ref","Type":"string","Help":"Ref is a branch, tag or commit; empty means the repo's HEAD.","Required":false},{"Name":"glob","Field":"glob","Type":"string","Help":"Glob selects files, matched segment by segment so `*` never crosses a `/`.\n`**` matches zero or more whole segments.","Required":false}],"Example":{"glob":"charts/app/values/*/*.yaml","name":"universe","ref":"main"}},{"Service":"git","Name":"repos-gc","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.","Method":"POST","Path":"/v1/git/repos/:name/gc","Args":[{"Name":"name","Help":"Name is the repo's org-unique handle, from the :name path segment. A\ntrailing \".git\" is stripped."}],"Flags":null,"Example":{"name":"widgets"}},{"Service":"git","Name":"repos-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.","Method":"GET","Path":"/v1/git/repos/:name","Args":[{"Name":"name","Help":"Name is the repo's org-unique handle, from the :name path segment. A\ntrailing \".git\" is stripped."}],"Flags":null,"Example":{"name":"widgets"}},{"Service":"git","Name":"repos-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.","Method":"GET","Path":"/v1/git/repos/:name/pulls/:number","Args":[{"Name":"name","Help":"Name is the repo, from the :name path segment."},{"Name":"number","Help":"Number is the proposal's per-repo number, from the :number path segment."}],"Flags":null,"Example":{"name":"widgets","number":4}},{"Service":"git","Name":"repos-home","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.","Method":"POST","Path":"/v1/git/repos/:name/home","Args":[{"Name":"name","Help":"Name is the repository, from the :name path segment."}],"Flags":null,"Example":{"name":"widgets"}},{"Service":"git","Name":"repos-link","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.","Method":"POST","Path":"/v1/git/repos/:name/link","Args":[{"Name":"name","Help":"Name is the repository, from the :name path segment. It is made when the\norg has none of that name."}],"Flags":[{"Name":"project","Field":"project","Type":"string","Help":"Project is the sub-scope to make it in; empty uses the caller's own.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"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.","Required":false}],"Example":{"name":"widgets","source":"https://github.com/acme/widgets.git"}},{"Service":"git","Name":"repos-list","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.","Method":"GET","Path":"/v1/git/repos","Args":[],"Flags":null,"Example":null},{"Service":"git","Name":"repos-merge","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.","Method":"POST","Path":"/v1/git/repos/:name/pulls/:number/merge","Args":[{"Name":"name","Help":"Name is the repo, from the :name path segment."},{"Name":"number","Help":"Number is the proposal's per-repo number, from the :number path segment."}],"Flags":null,"Example":{"name":"widgets","number":4}},{"Service":"git","Name":"repos-pulls","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.","Method":"POST","Path":"/v1/git/repos/:name/pulls","Args":[{"Name":"name","Help":"Name is the repo the proposal belongs to, from the :name path segment."}],"Flags":[{"Name":"base","Field":"base","Type":"string","Help":"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.","Required":false},{"Name":"body","Field":"body","Type":"string","Help":"Body is the longer description. Optional.","Required":false},{"Name":"head","Field":"head","Type":"string","Help":"Head is the branch holding the work, by short name (agent/fix-503).\nRequired, and must already exist.","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"Title is the one-line summary of what is being proposed. Required.","Required":false}],"Example":{"base":"main","head":"agent/cache-catalog","name":"widgets","title":"cache the catalog read"}},{"Service":"git","Name":"repos-pulls-list","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.","Method":"GET","Path":"/v1/git/repos/:name/pulls","Args":[{"Name":"name","Help":"Name is the repo, from the :name path segment."}],"Flags":[{"Name":"state","Field":"state","Type":"string","Help":"State narrows the list to \"open\" or \"merged\". Omit it for every proposal.","Required":false}],"Example":{"name":"widgets","state":"open"}},{"Service":"git","Name":"repos-push","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.","Method":"POST","Path":"/v1/git/repos/:name/push","Args":[{"Name":"name","Help":"Name is the repo to push into, from the :name path segment. It is CREATED\non first push if it does not exist."}],"Flags":[{"Name":"branch","Field":"branch","Type":"string","Help":"Branch to advance; empty means \"main\". A fresh branch that is the repo's\nfirst also becomes HEAD.","Required":false},{"Name":"files","Field":"files","Type":"json","Help":"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.","Required":false},{"Name":"message","Field":"message","Type":"string","Help":"Message is the commit message; empty gets a generated one.","Required":false}],"Example":{"branch":"main","files":[{"content":"\u003ch1\u003ehi\u003c/h1\u003e","path":"index.html"}],"message":"generated build","name":"widgets"}},{"Service":"git","Name":"repos-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.","Method":"GET","Path":"/v1/git/repos/:name/readme","Args":[{"Name":"name","Help":"Name is the repo to read, from the :name path segment."}],"Flags":[{"Name":"ref","Field":"ref","Type":"string","Help":"Ref is a branch, tag or commit; empty means the repo's HEAD.","Required":false}],"Example":{"name":"widgets","ref":"main"}},{"Service":"git","Name":"repos-refs-list","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.","Method":"GET","Path":"/v1/git/repos/:name/refs","Args":[{"Name":"name","Help":"Name is the repo's org-unique handle, from the :name path segment. A\ntrailing \".git\" is stripped."}],"Flags":null,"Example":{"name":"widgets"}},{"Service":"git","Name":"repos-subscriptions","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.","Method":"POST","Path":"/v1/git/repos/:name/subscriptions","Args":[{"Name":"name","Help":"Name is the repo to subscribe, from the :name path segment."}],"Flags":[{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is the Slack channel the notifier posts to — an id (C…/G…), a\n#name, or a bare name. Required.","Required":false},{"Name":"events","Field":"events","Type":"json","Help":"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.","Required":false}],"Example":{"channel":"#builds","events":["push.landed"],"name":"widgets"}},{"Service":"git","Name":"repos-subscriptions-list","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.","Method":"GET","Path":"/v1/git/repos/:name/subscriptions","Args":[{"Name":"name","Help":"Name is the repo's org-unique handle, from the :name path segment. A\ntrailing \".git\" is stripped."}],"Flags":null,"Example":{"name":"widgets"}},{"Service":"git","Name":"repos-targets","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.","Method":"POST","Path":"/v1/git/repos/:name/targets","Args":[{"Name":"name","Help":"Name is the repo whose advanced refs are pushed downstream, from the :name\npath segment."}],"Flags":[{"Name":"host","Field":"host","Type":"string","Help":"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.","Required":false},{"Name":"url","Field":"url","Type":"string","Help":"URL is the downstream https git remote. Must be https to an allowlisted\nhost (github.com / gitlab.com); any embedded credentials are stripped.\nRequired.","Required":false}],"Example":{"name":"widgets","url":"https://github.com/acme/widgets.git"}},{"Service":"git","Name":"repos-targets-list","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.","Method":"GET","Path":"/v1/git/repos/:name/targets","Args":[{"Name":"name","Help":"Name is the repo's org-unique handle, from the :name path segment. A\ntrailing \".git\" is stripped."}],"Flags":null,"Example":{"name":"widgets"}},{"Service":"git","Name":"repos-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.","Method":"GET","Path":"/v1/git/repos/:name/tree","Args":[{"Name":"name","Help":"Name is the repo to read, from the :name path segment."}],"Flags":[{"Name":"ref","Field":"ref","Type":"string","Help":"Ref is a branch, tag or commit; empty means the repo's HEAD.","Required":false},{"Name":"path","Field":"path","Type":"string","Help":"Path is repo-relative; empty is the tree root. Traversal is stripped.","Required":false}],"Example":{"name":"widgets","path":"cmd","ref":"main"}},{"Service":"git","Name":"repos-update","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.","Method":"PATCH","Path":"/v1/git/repos/:name","Args":[{"Name":"name","Help":"Name is the repo to update, from the :name path segment."}],"Flags":[{"Name":"public","Field":"public","Type":"boolean","Help":"Public flips anonymous read access. Omit it and the request is refused —\nthere is nothing else to update yet.","Required":false}],"Example":{"name":"widgets","public":true}},{"Service":"git","Name":"runners-list","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.","Method":"GET","Path":"/v1/git/runners","Args":[],"Flags":null,"Example":null},{"Service":"git","Name":"runs-create","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.","Method":"POST","Path":"/v1/git/runs","Args":[],"Flags":[{"Name":"ref","Field":"ref","Type":"string","Help":"Ref is the branch to run; empty means the repository's default.","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"Repo is the repository to run.","Required":false}],"Example":{"ref":"main","repo":"widgets"}},{"Service":"git","Name":"runs-get","OperationID":"get_git_runs_by_id","Summary":"Returns one run.","Description":"Returns one run.","Method":"GET","Path":"/v1/git/runs/:id","Args":[{"Name":"id","Help":"ID is the run to read, from the :id path segment."}],"Flags":null,"Example":null},{"Service":"git","Name":"runs-list","OperationID":"get_git_runs","Summary":"Returns this org's runs, newest first.","Description":"Returns this org's runs, newest first.","Method":"GET","Path":"/v1/git/runs","Args":[],"Flags":[{"Name":"repo","Field":"repo","Type":"string","Help":"Repo restricts the listing to one repository. Empty lists the whole org.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the answer; 0 means the default of 50, and 200 is the ceiling.","Required":false}],"Example":null},{"Service":"git","Name":"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.","Method":"GET","Path":"/v1/git/usage","Args":[],"Flags":null,"Example":null},{"Service":"git","Name":"webhook-create","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.","Method":"POST","Path":"/v1/git/webhook","Args":[],"Flags":null,"Example":null},{"Service":"git","Name":"workflows-list","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\".","Method":"GET","Path":"/v1/git/workflows","Args":[],"Flags":[{"Name":"repo","Field":"repo","Type":"string","Help":"Repo is the repository whose workflows to read.","Required":false},{"Name":"ref","Field":"ref","Type":"string","Help":"Ref is the branch to read them at; empty means the default.","Required":false}],"Example":null},{"Service":"git","Name":"workspace-create","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.","Method":"POST","Path":"/v1/git/workspace","Args":[],"Flags":null,"Example":null},{"Service":"graph","Name":"answer","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.","Method":"POST","Path":"/v1/graph/answer","Args":[],"Flags":[{"Name":"as-known","Field":"as_known","Type":"string","Help":"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.","Required":false},{"Name":"as-of","Field":"as_of","Type":"string","Help":"AsOf answers from the graph as it stood at an instant of the world, RFC\n3339: what held then. Absent is now.","Required":false},{"Name":"question","Field":"question","Type":"string","Help":"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.","Required":true}],"Example":{"question":"Which teams own the billing services?"}},{"Service":"graph","Name":"assert","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.","Method":"POST","Path":"/v1/graph","Args":[],"Flags":[{"Name":"assertions","Field":"assertions","Type":"json","Help":"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.","Required":true}],"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"}]}},{"Service":"graph","Name":"communities","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.","Method":"POST","Path":"/v1/graph/communities","Args":[],"Flags":[{"Name":"as-known","Field":"as_known","Type":"string","Help":"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.","Required":false},{"Name":"as-of","Field":"as_of","Type":"string","Help":"AsOf partitions the graph as it stood at an instant of the world, RFC\n3339: the edges that held then. Absent is now.","Required":false},{"Name":"level","Field":"level","Type":"integer","Help":"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.","Required":false},{"Name":"relation","Field":"relation","Type":"string","Help":"Relation narrows the graph to one edge relation, by its key. Absent\npartitions every edge.","Required":false}],"Example":{"as_of":"2026-09-01T00:00:00Z"}},{"Service":"graph","Name":"derive","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.","Method":"POST","Path":"/v1/graph/derive","Args":[],"Flags":[{"Name":"as-known","Field":"as_known","Type":"string","Help":"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.","Required":false},{"Name":"as-of","Field":"as_of","Type":"string","Help":"AsOf derives from the graph as it stood at an instant of the world, RFC\n3339: the statements that held then. Absent is now.","Required":false},{"Name":"file","Field":"file","Type":"boolean","Help":"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.","Required":false},{"Name":"predicates","Field":"predicates","Type":"json","Help":"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.","Required":false},{"Name":"without","Field":"without","Type":"json","Help":"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.","Required":false}],"Example":{"as_of":"2026-09-01T00:00:00Z","predicates":["ancestor"]}},{"Service":"graph","Name":"diff","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.","Method":"POST","Path":"/v1/graph/diff","Args":[],"Flags":[{"Name":"entity","Field":"entity","Type":"string","Help":"Entity narrows the diff to what was asserted about one entity. Absent\ndiffs the whole graph, bounded by Limit.","Required":false},{"Name":"from","Field":"from","Type":"string","Help":"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.","Required":false},{"Name":"from-known","Field":"from_known","Type":"string","Help":"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.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many (entity, relation) pairs are examined, in key order.\nAbsent, zero, or anything above the walk ceiling is the ceiling.","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"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.","Required":false},{"Name":"to-known","Field":"to_known","Type":"string","Help":"ToKnown is how much it had heard at the later point, RFC 3339, and may\nnot precede FromKnown. Absent is now.","Required":false}],"Example":{"entity":"acme/svc/api","from":"2026-08-01T00:00:00Z","to":"2026-09-01T00:00:00Z"}},{"Service":"graph","Name":"erase","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.","Method":"POST","Path":"/v1/graph/erase","Args":[],"Flags":[{"Name":"entity","Field":"entity","Type":"string","Help":"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.","Required":true},{"Name":"reason","Field":"reason","Type":"string","Help":"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.","Required":true}],"Example":{"entity":"acme/person/42","reason":"DSR-1187, GDPR Art. 17"}},{"Service":"graph","Name":"extract","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.","Method":"POST","Path":"/v1/graph/extract","Args":[],"Flags":[{"Name":"at","Field":"at","Type":"string","Help":"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.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"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.","Required":true},{"Name":"subject","Field":"subject","Type":"string","Help":"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.","Required":false},{"Name":"text","Field":"text","Type":"string","Help":"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.","Required":true}],"Example":{"at":"2026-09-01T00:00:00Z","source":"wiki/api","text":"# acme/svc/api\nowner:: [[acme/team/core]]\ntier:: 1"}},{"Service":"graph","Name":"graphql-create","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.","Method":"POST","Path":"/v1/graph/graphql","Args":[],"Flags":[{"Name":"operation-name","Field":"operationName","Type":"string","Help":"","Required":false},{"Name":"query","Field":"query","Type":"string","Help":"","Required":false},{"Name":"variables","Field":"variables","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"graph","Name":"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.","Method":"GET","Path":"/v1/graph/graphql","Args":[],"Flags":null,"Example":null,"Stream":"bytes"},{"Service":"graph","Name":"ingest","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.","Method":"POST","Path":"/v1/graph/ingest","Args":[],"Flags":[{"Name":"at","Field":"at","Type":"string","Help":"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.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"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.","Required":true},{"Name":"subject","Field":"subject","Type":"string","Help":"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.","Required":false},{"Name":"text","Field":"text","Type":"string","Help":"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.","Required":true}],"Example":{"at":"2026-09-01T00:00:00Z","source":"wiki/api","text":"# acme/svc/api\nowner:: [[acme/team/core]]\ntier:: 1"}},{"Service":"graph","Name":"neighbors","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.","Method":"POST","Path":"/v1/graph/neighbors","Args":[],"Flags":[{"Name":"as-known","Field":"as_known","Type":"string","Help":"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.","Required":false},{"Name":"as-of","Field":"as_of","Type":"string","Help":"AsOf walks the graph as it stood at an instant of the world, RFC 3339:\nthe edges that held then. Absent is now.","Required":false},{"Name":"depth","Field":"depth","Type":"integer","Help":"Depth is how many hops. Absent is one.","Required":false},{"Name":"direction","Field":"direction","Type":"string","Help":"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.","Required":false},{"Name":"relation","Field":"relation","Type":"string","Help":"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.","Required":false},{"Name":"seeds","Field":"seeds","Type":"json","Help":"Seeds is where the walk starts. At least one.","Required":true}],"Example":{"depth":2,"relation":"depends","seeds":["acme/svc/api"]}},{"Service":"graph","Name":"path","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.","Method":"POST","Path":"/v1/graph/path","Args":[],"Flags":[{"Name":"as-known","Field":"as_known","Type":"string","Help":"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.","Required":false},{"Name":"as-of","Field":"as_of","Type":"string","Help":"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.","Required":false},{"Name":"direction","Field":"direction","Type":"string","Help":"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.","Required":false},{"Name":"from","Field":"from","Type":"string","Help":"From is the entity the path starts at. Required.","Required":true},{"Name":"relations","Field":"relations","Type":"json","Help":"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.","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"To is the entity the path ends at. Required.","Required":true}],"Example":{"direction":"both","from":"acme/svc/api","to":"acme/team/core"}},{"Service":"graph","Name":"read","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.","Method":"GET","Path":"/v1/graph","Args":[],"Flags":[{"Name":"entity","Field":"entity","Type":"string","Help":"Entity narrows to what was asserted ABOUT one entity. Absent matches every\nentity.","Required":false},{"Name":"relation","Field":"relation","Type":"string","Help":"Relation narrows to one relation. Absent matches every relation.","Required":false},{"Name":"value","Field":"value","Type":"string","Help":"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.","Required":false},{"Name":"as-of","Field":"as_of","Type":"string","Help":"AsOf bounds the read to statements begun by an instant of the world, RFC\n3339. Absent reads every instant.","Required":false},{"Name":"as-known","Field":"as_known","Type":"string","Help":"AsKnown bounds the read to what this plane had heard by an instant, RFC\n3339. Absent reads everything it holds.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many assertions come back. Absent, zero, or anything above\nthe walk ceiling is the ceiling.","Required":false}],"Example":{"as_known":"2026-09-01T00:00:00Z","entity":"acme/svc/api"}},{"Service":"graph","Name":"resolve","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.","Method":"POST","Path":"/v1/graph/resolve","Args":[],"Flags":[{"Name":"as-known","Field":"as_known","Type":"string","Help":"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.","Required":false},{"Name":"as-of","Field":"as_of","Type":"string","Help":"AsOf is the instant of the world to answer about, RFC 3339: what held\nthen. Absent is now.","Required":false},{"Name":"entity","Field":"entity","Type":"string","Help":"Entity is the thing to answer about. Required.","Required":true},{"Name":"relation","Field":"relation","Type":"string","Help":"Relation is the one relation to settle. Required: this answers a single\n(entity, relation) pair, never a whole entity at once.","Required":true}],"Example":{"as_of":"2026-09-01T00:00:00Z","entity":"acme/svc/api","relation":"owner"}},{"Service":"graph","Name":"search","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.","Method":"GET","Path":"/v1/graph/search","Args":[],"Flags":[{"Name":"q","Field":"q","Type":"string","Help":"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.","Required":true},{"Name":"relation","Field":"relation","Type":"string","Help":"Relation narrows to one relation. Absent matches every relation.","Required":false},{"Name":"as-of","Field":"as_of","Type":"string","Help":"AsOf bounds the search to statements begun by an instant of the world,\nRFC 3339. Absent searches every instant.","Required":false},{"Name":"as-known","Field":"as_known","Type":"string","Help":"AsKnown bounds the search to what this plane had heard by an instant, RFC\n3339. Absent searches everything it holds.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many assertions come back. Absent, zero, or anything above\nthe walk ceiling is the ceiling.","Required":false}],"Example":{"q":"billing owner"}},{"Service":"graph","Name":"vocabulary","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.","Method":"GET","Path":"/v1/graph/vocabulary","Args":[],"Flags":null,"Example":null},{"Service":"guide","Name":"actions-list","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.","Method":"GET","Path":"/v1/guide/actions","Args":[],"Flags":null,"Example":null},{"Service":"guide","Name":"analytics-list","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.","Method":"GET","Path":"/v1/guide/analytics","Args":[],"Flags":null,"Example":null},{"Service":"guide","Name":"chat-create","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.","Method":"POST","Path":"/v1/guide/chat","Args":[],"Flags":[{"Name":"message","Field":"message","Type":"string","Help":"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.","Required":false}],"Example":{"message":"what should I do next to get my first customers?"}},{"Service":"guide","Name":"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.","Method":"DELETE","Path":"/v1/guide/curriculum","Args":[],"Flags":null,"Example":null},{"Service":"guide","Name":"curriculum-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.","Method":"GET","Path":"/v1/guide/curriculum","Args":[],"Flags":null,"Example":null},{"Service":"guide","Name":"curriculum-update","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.","Method":"PUT","Path":"/v1/guide/curriculum","Args":[],"Flags":null,"Example":null},{"Service":"guide","Name":"list","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.","Method":"GET","Path":"/v1/guide","Args":[],"Flags":null,"Example":null},{"Service":"guide","Name":"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).","Method":"GET","Path":"/v1/guide/profile","Args":[],"Flags":null,"Example":null},{"Service":"guide","Name":"steps-do","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.","Method":"POST","Path":"/v1/guide/steps/:id/do","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"guide","Name":"steps-done","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.","Method":"POST","Path":"/v1/guide/steps/:id/done","Args":[{"Name":"id","Help":"ID is the step's id, as it appears in the journey (e.g. \"gsuite\")."}],"Flags":null,"Example":null},{"Service":"guide","Name":"steps-reset","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.","Method":"POST","Path":"/v1/guide/steps/:id/reset","Args":[{"Name":"id","Help":"ID is the step's id, as it appears in the journey (e.g. \"gsuite\")."}],"Flags":null,"Example":null},{"Service":"guide","Name":"steps-skip","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.","Method":"POST","Path":"/v1/guide/steps/:id/skip","Args":[{"Name":"id","Help":"ID is the step's id, as it appears in the journey (e.g. \"gsuite\")."}],"Flags":null,"Example":null},{"Service":"guide","Name":"steps-start","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.","Method":"POST","Path":"/v1/guide/steps/:id/start","Args":[{"Name":"id","Help":"ID is the step's id, as it appears in the journey (e.g. \"gsuite\")."}],"Flags":null,"Example":null},{"Service":"guide","Name":"strategies-list","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.","Method":"GET","Path":"/v1/guide/strategies","Args":[],"Flags":[{"Name":"category","Field":"category","Type":"string","Help":"Category filters to tactics in exactly this category.","Required":false},{"Name":"stage","Field":"stage","Type":"string","Help":"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.","Required":false},{"Name":"workload","Field":"workload","Type":"string","Help":"Workload filters to tactics with exactly this workload.","Required":false}],"Example":{"category":"viral-coefficient","stage":"scaling"}},{"Service":"guide","Name":"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.","Method":"GET","Path":"/v1/guide/suggest","Args":[],"Flags":null,"Example":null},{"Service":"help","Name":"articles-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\".","Method":"GET","Path":"/v1/help/articles/:slug","Args":[{"Name":"slug","Help":"Slug is the article's public identifier, from the path. It IS the document\nname in the help center's store."}],"Flags":null,"Example":null},{"Service":"help","Name":"articles-list","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.","Method":"GET","Path":"/v1/help/articles","Args":[],"Flags":[{"Name":"category","Field":"category","Type":"string","Help":"Category narrows the list to one knowledge-base section, matched against\nthe article's category by exact name. Empty lists every section.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many articles are returned. Anything that is not a positive\ninteger uses 50, and values above 200 are clamped to 200.","Required":false}],"Example":null},{"Service":"help","Name":"categories-list","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.","Method":"GET","Path":"/v1/help/categories","Args":[],"Flags":null,"Example":null},{"Service":"help","Name":"tickets-create","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.","Method":"POST","Path":"/v1/help/tickets","Args":[],"Flags":[{"Name":"description","Field":"description","Type":"string","Help":"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.","Required":false},{"Name":"email","Field":"email","Type":"string","Help":"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.","Required":false},{"Name":"priority","Field":"priority","Type":"string","Help":"Priority is Low, Medium, High or Urgent, case-insensitively. Anything else —\nincluding omitting it — is recorded as Medium rather than refused.","Required":false},{"Name":"subject","Field":"subject","Type":"string","Help":"Subject is the one-line summary of the problem. Required; longer than 300\ncharacters is clipped rather than refused.","Required":false}],"Example":null},{"Service":"iam","Name":"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.","Method":"GET","Path":"/v1/iam/account","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"account-update","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.","Method":"PUT","Path":"/v1/iam/account","Args":[],"Flags":[{"Name":"avatar","Field":"avatar","Type":"string","Help":"","Required":false},{"Name":"bio","Field":"bio","Type":"string","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"homepage","Field":"homepage","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"accounts-list","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.","Method":"GET","Path":"/v1/iam/accounts","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"add-provider","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.","Method":"POST","Path":"/v1/iam/providers","Args":[],"Flags":[{"Name":"app-id","Field":"appId","Type":"string","Help":"","Required":false},{"Name":"bucket","Field":"bucket","Type":"string","Help":"","Required":false},{"Name":"category","Field":"category","Type":"string","Help":"","Required":false},{"Name":"cert","Field":"cert","Type":"string","Help":"","Required":false},{"Name":"client-id","Field":"clientId","Type":"string","Help":"","Required":false},{"Name":"client-id2","Field":"clientId2","Type":"string","Help":"","Required":false},{"Name":"client-secret","Field":"clientSecret","Type":"string","Help":"","Required":false},{"Name":"client-secret2","Field":"clientSecret2","Type":"string","Help":"","Required":false},{"Name":"content","Field":"content","Type":"string","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"custom-auth-url","Field":"customAuthUrl","Type":"string","Help":"","Required":false},{"Name":"custom-logo","Field":"customLogo","Type":"string","Help":"","Required":false},{"Name":"custom-token-url","Field":"customTokenUrl","Type":"string","Help":"","Required":false},{"Name":"custom-user-info-url","Field":"customUserInfoUrl","Type":"string","Help":"","Required":false},{"Name":"deleted","Field":"deleted","Type":"boolean","Help":"","Required":false},{"Name":"disable-ssl","Field":"disableSsl","Type":"boolean","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"domain","Field":"domain","Type":"string","Help":"","Required":false},{"Name":"email-regex","Field":"emailRegex","Type":"string","Help":"","Required":false},{"Name":"enable-pkce","Field":"enablePkce","Type":"boolean","Help":"","Required":false},{"Name":"enable-proxy","Field":"enableProxy","Type":"boolean","Help":"","Required":false},{"Name":"enable-sign-authn-request","Field":"enableSignAuthnRequest","Type":"boolean","Help":"","Required":false},{"Name":"endpoint","Field":"endpoint","Type":"string","Help":"","Required":false},{"Name":"host","Field":"host","Type":"string","Help":"","Required":false},{"Name":"http-headers","Field":"httpHeaders","Type":"json","Help":"","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"Persisted fields","Required":false},{"Name":"id-p","Field":"idP","Type":"string","Help":"","Required":false},{"Name":"intranet-endpoint","Field":"intranetEndpoint","Type":"string","Help":"","Required":false},{"Name":"issuer-url","Field":"issuerUrl","Type":"string","Help":"","Required":false},{"Name":"metadata","Field":"metadata","Type":"string","Help":"","Required":false},{"Name":"method","Field":"method","Type":"string","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false},{"Name":"path-prefix","Field":"pathPrefix","Type":"string","Help":"","Required":false},{"Name":"port","Field":"port","Type":"integer","Help":"","Required":false},{"Name":"provider-url","Field":"providerUrl","Type":"string","Help":"","Required":false},{"Name":"receiver","Field":"receiver","Type":"string","Help":"","Required":false},{"Name":"region-id","Field":"regionId","Type":"string","Help":"","Required":false},{"Name":"scopes","Field":"scopes","Type":"string","Help":"","Required":false},{"Name":"sign-name","Field":"signName","Type":"string","Help":"","Required":false},{"Name":"ssl-mode","Field":"sslMode","Type":"string","Help":"","Required":false},{"Name":"sub-type","Field":"subType","Type":"string","Help":"","Required":false},{"Name":"template-code","Field":"templateCode","Type":"string","Help":"","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"","Required":false},{"Name":"type","Field":"type","Type":"string","Help":"","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"string","Help":"","Required":false},{"Name":"user-mapping","Field":"userMapping","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"add-token","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.","Method":"POST","Path":"/v1/iam/tokens","Args":[],"Flags":[{"Name":"access-token","Field":"accessToken","Type":"string","Help":"","Required":false},{"Name":"access-token-hash","Field":"accessTokenHash","Type":"string","Help":"","Required":false},{"Name":"actor","Field":"actor","Type":"string","Help":"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.","Required":false},{"Name":"application","Field":"application","Type":"string","Help":"","Required":false},{"Name":"code","Field":"code","Type":"string","Help":"","Required":false},{"Name":"code-challenge","Field":"codeChallenge","Type":"string","Help":"","Required":false},{"Name":"code-challenge-method","Field":"codeChallengeMethod","Type":"string","Help":"","Required":false},{"Name":"code-expire-in","Field":"codeExpireIn","Type":"integer","Help":"","Required":false},{"Name":"code-is-used","Field":"codeIsUsed","Type":"boolean","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"deleted","Field":"deleted","Type":"boolean","Help":"","Required":false},{"Name":"expires-in","Field":"expiresIn","Type":"integer","Help":"","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"Persisted fields","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"nonce","Field":"nonce","Type":"string","Help":"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.","Required":false},{"Name":"organization","Field":"organization","Type":"string","Help":"","Required":false},{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false},{"Name":"public-grant","Field":"publicGrant","Type":"boolean","Help":"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.","Required":false},{"Name":"reason","Field":"reason","Type":"string","Help":"","Required":false},{"Name":"redirect-uri","Field":"redirectUri","Type":"string","Help":"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.","Required":false},{"Name":"refresh-consumed","Field":"refreshConsumed","Type":"boolean","Help":"","Required":false},{"Name":"refresh-expire-in","Field":"refreshExpireIn","Type":"integer","Help":"","Required":false},{"Name":"refresh-family","Field":"refreshFamily","Type":"string","Help":"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.","Required":false},{"Name":"refresh-token","Field":"refreshToken","Type":"string","Help":"","Required":false},{"Name":"refresh-token-hash","Field":"refreshTokenHash","Type":"string","Help":"","Required":false},{"Name":"resource","Field":"resource","Type":"string","Help":"RFC 8707 resource indicator","Required":false},{"Name":"scope","Field":"scope","Type":"string","Help":"","Required":false},{"Name":"token-type","Field":"tokenType","Type":"string","Help":"","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"string","Help":"","Required":false},{"Name":"user","Field":"user","Type":"string","Help":"","Required":false},{"Name":"user-code","Field":"userCode","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"add-webauthn-credential","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.","Method":"POST","Path":"/v1/iam/webauthn-credentials","Args":[],"Flags":[{"Name":"aaguid","Field":"aaguid","Type":"string","Help":"","Required":false},{"Name":"attachment","Field":"attachment","Type":"string","Help":"","Required":false},{"Name":"attestation-format","Field":"attestationFormat","Type":"string","Help":"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.","Required":false},{"Name":"attestation-type","Field":"attestationType","Type":"string","Help":"","Required":false},{"Name":"backup-eligible","Field":"backupEligible","Type":"boolean","Help":"","Required":false},{"Name":"backup-state","Field":"backupState","Type":"boolean","Help":"","Required":false},{"Name":"clone-warning","Field":"cloneWarning","Type":"boolean","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"credential-id","Field":"credentialId","Type":"string","Help":"","Required":false},{"Name":"deleted","Field":"deleted","Type":"boolean","Help":"","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"Persisted fields","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false},{"Name":"public-key","Field":"publicKey","Type":"string","Help":"","Required":false},{"Name":"sign-count","Field":"signCount","Type":"integer","Help":"","Required":false},{"Name":"transport","Field":"transport","Type":"json","Help":"","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"string","Help":"","Required":false},{"Name":"user","Field":"user","Type":"string","Help":"","Required":false},{"Name":"user-present","Field":"userPresent","Type":"boolean","Help":"","Required":false},{"Name":"user-verified","Field":"userVerified","Type":"boolean","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"admin-provision-create","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.","Method":"POST","Path":"/v1/iam/admin/provision","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"applications-create","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.","Method":"POST","Path":"/v1/iam/applications","Args":[],"Flags":[{"Name":"affiliation-url","Field":"affiliationUrl","Type":"string","Help":"","Required":false},{"Name":"category","Field":"category","Type":"string","Help":"","Required":false},{"Name":"cert","Field":"cert","Type":"string","Help":"","Required":false},{"Name":"cert-obj","Field":"certObj","Type":"json","Help":"","Required":false},{"Name":"cert-public-key","Field":"certPublicKey","Type":"string","Help":"","Required":false},{"Name":"client-cert","Field":"clientCert","Type":"string","Help":"","Required":false},{"Name":"client-id","Field":"clientId","Type":"string","Help":"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.","Required":false},{"Name":"client-secret","Field":"clientSecret","Type":"string","Help":"","Required":false},{"Name":"code-resend-timeout","Field":"codeResendTimeout","Type":"integer","Help":"","Required":false},{"Name":"cookie-expire-in-hours","Field":"cookieExpireInHours","Type":"integer","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"custom-scopes","Field":"customScopes","Type":"json","Help":"","Required":false},{"Name":"default-group","Field":"defaultGroup","Type":"string","Help":"","Required":false},{"Name":"deleted","Field":"deleted","Type":"boolean","Help":"","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"disable-saml-attributes","Field":"disableSamlAttributes","Type":"boolean","Help":"","Required":false},{"Name":"disable-signin","Field":"disableSignin","Type":"boolean","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"domain","Field":"domain","Type":"string","Help":"","Required":false},{"Name":"enable-auto-signin","Field":"enableAutoSignin","Type":"boolean","Help":"","Required":false},{"Name":"enable-code-signin","Field":"enableCodeSignin","Type":"boolean","Help":"","Required":false},{"Name":"enable-exclusive-signin","Field":"enableExclusiveSignin","Type":"boolean","Help":"","Required":false},{"Name":"enable-link-with-email","Field":"enableLinkWithEmail","Type":"boolean","Help":"","Required":false},{"Name":"enable-password","Field":"enablePassword","Type":"boolean","Help":"","Required":false},{"Name":"enable-saml-assertion-signature","Field":"enableSamlAssertionSignature","Type":"boolean","Help":"","Required":false},{"Name":"enable-saml-c14n10","Field":"enableSamlC14n10","Type":"boolean","Help":"","Required":false},{"Name":"enable-saml-compress","Field":"enableSamlCompress","Type":"boolean","Help":"","Required":false},{"Name":"enable-saml-post-binding","Field":"enableSamlPostBinding","Type":"boolean","Help":"","Required":false},{"Name":"enable-sign-up","Field":"enableSignUp","Type":"boolean","Help":"","Required":false},{"Name":"enable-signin-session","Field":"enableSigninSession","Type":"boolean","Help":"","Required":false},{"Name":"enable-web-authn","Field":"enableWebAuthn","Type":"boolean","Help":"","Required":false},{"Name":"environment","Field":"environment","Type":"string","Help":"","Required":false},{"Name":"expire-in-hours","Field":"expireInHours","Type":"number","Help":"","Required":false},{"Name":"failed-signin-frozen-time","Field":"failedSigninFrozenTime","Type":"integer","Help":"","Required":false},{"Name":"failed-signin-limit","Field":"failedSigninLimit","Type":"integer","Help":"","Required":false},{"Name":"favicon","Field":"favicon","Type":"string","Help":"","Required":false},{"Name":"footer-html","Field":"footerHtml","Type":"string","Help":"","Required":false},{"Name":"forced-redirect-origin","Field":"forcedRedirectOrigin","Type":"string","Help":"","Required":false},{"Name":"forget-url","Field":"forgetUrl","Type":"string","Help":"","Required":false},{"Name":"form-background-url","Field":"formBackgroundUrl","Type":"string","Help":"","Required":false},{"Name":"form-background-url-mobile","Field":"formBackgroundUrlMobile","Type":"string","Help":"","Required":false},{"Name":"form-css","Field":"formCss","Type":"string","Help":"","Required":false},{"Name":"form-css-mobile","Field":"formCssMobile","Type":"string","Help":"","Required":false},{"Name":"form-offset","Field":"formOffset","Type":"integer","Help":"","Required":false},{"Name":"form-side-html","Field":"formSideHtml","Type":"string","Help":"","Required":false},{"Name":"grant-types","Field":"grantTypes","Type":"json","Help":"","Required":false},{"Name":"header-html","Field":"headerHtml","Type":"string","Help":"","Required":false},{"Name":"homepage-url","Field":"homepageUrl","Type":"string","Help":"","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"Persisted fields","Required":false},{"Name":"ip-restriction","Field":"ipRestriction","Type":"string","Help":"","Required":false},{"Name":"ip-whitelist","Field":"ipWhitelist","Type":"string","Help":"","Required":false},{"Name":"is-shared","Field":"isShared","Type":"boolean","Help":"","Required":false},{"Name":"logo","Field":"logo","Type":"string","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"order","Field":"order","Type":"integer","Help":"","Required":false},{"Name":"org-choice-mode","Field":"orgChoiceMode","Type":"string","Help":"","Required":false},{"Name":"organization","Field":"organization","Type":"string","Help":"","Required":false},{"Name":"organization-obj","Field":"organizationObj","Type":"json","Help":"","Required":false},{"Name":"other-domains","Field":"otherDomains","Type":"json","Help":"","Required":false},{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false},{"Name":"platform","Field":"platform","Type":"boolean","Help":"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.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"","Required":false},{"Name":"providers","Field":"providers","Type":"json","Help":"","Required":false},{"Name":"redirect-uris","Field":"redirectUris","Type":"json","Help":"","Required":false},{"Name":"refresh-expire-in-hours","Field":"refreshExpireInHours","Type":"number","Help":"","Required":false},{"Name":"saml-attributes","Field":"samlAttributes","Type":"json","Help":"","Required":false},{"Name":"saml-hash-algorithm","Field":"samlHashAlgorithm","Type":"string","Help":"","Required":false},{"Name":"saml-reply-url","Field":"samlReplyUrl","Type":"string","Help":"","Required":false},{"Name":"scopes","Field":"scopes","Type":"json","Help":"","Required":false},{"Name":"signin-html","Field":"signinHtml","Type":"string","Help":"","Required":false},{"Name":"signin-items","Field":"signinItems","Type":"json","Help":"","Required":false},{"Name":"signin-methods","Field":"signinMethods","Type":"json","Help":"","Required":false},{"Name":"signin-url","Field":"signinUrl","Type":"string","Help":"","Required":false},{"Name":"signup-html","Field":"signupHtml","Type":"string","Help":"","Required":false},{"Name":"signup-items","Field":"signupItems","Type":"json","Help":"","Required":false},{"Name":"signup-url","Field":"signupUrl","Type":"string","Help":"","Required":false},{"Name":"ssl-cert","Field":"sslCert","Type":"string","Help":"","Required":false},{"Name":"ssl-mode","Field":"sslMode","Type":"string","Help":"","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"","Required":false},{"Name":"terms-of-use","Field":"termsOfUse","Type":"string","Help":"","Required":false},{"Name":"theme-data","Field":"themeData","Type":"json","Help":"","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"","Required":false},{"Name":"token-attributes","Field":"tokenAttributes","Type":"json","Help":"","Required":false},{"Name":"token-fields","Field":"tokenFields","Type":"json","Help":"","Required":false},{"Name":"token-format","Field":"tokenFormat","Type":"string","Help":"","Required":false},{"Name":"token-signing-method","Field":"tokenSigningMethod","Type":"string","Help":"","Required":false},{"Name":"type","Field":"type","Type":"string","Help":"","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"string","Help":"","Required":false},{"Name":"upstream-host","Field":"upstreamHost","Type":"string","Help":"","Required":false},{"Name":"use-email-as-saml-name-id","Field":"useEmailAsSamlNameId","Type":"boolean","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"applications-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.","Method":"DELETE","Path":"/v1/iam/applications/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"applications-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.","Method":"GET","Path":"/v1/iam/applications/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"applications-list","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.","Method":"GET","Path":"/v1/iam/applications","Args":[],"Flags":[{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":true}],"Example":null},{"Service":"iam","Name":"applications-update","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.","Method":"PUT","Path":"/v1/iam/applications/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":[{"Name":"affiliation-url","Field":"affiliationUrl","Type":"string","Help":"","Required":false},{"Name":"category","Field":"category","Type":"string","Help":"","Required":false},{"Name":"cert","Field":"cert","Type":"string","Help":"","Required":false},{"Name":"cert-obj","Field":"certObj","Type":"json","Help":"","Required":false},{"Name":"cert-public-key","Field":"certPublicKey","Type":"string","Help":"","Required":false},{"Name":"client-cert","Field":"clientCert","Type":"string","Help":"","Required":false},{"Name":"client-id","Field":"clientId","Type":"string","Help":"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.","Required":false},{"Name":"client-secret","Field":"clientSecret","Type":"string","Help":"","Required":false},{"Name":"code-resend-timeout","Field":"codeResendTimeout","Type":"integer","Help":"","Required":false},{"Name":"cookie-expire-in-hours","Field":"cookieExpireInHours","Type":"integer","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"custom-scopes","Field":"customScopes","Type":"json","Help":"","Required":false},{"Name":"default-group","Field":"defaultGroup","Type":"string","Help":"","Required":false},{"Name":"deleted","Field":"deleted","Type":"boolean","Help":"","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"disable-saml-attributes","Field":"disableSamlAttributes","Type":"boolean","Help":"","Required":false},{"Name":"disable-signin","Field":"disableSignin","Type":"boolean","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"domain","Field":"domain","Type":"string","Help":"","Required":false},{"Name":"enable-auto-signin","Field":"enableAutoSignin","Type":"boolean","Help":"","Required":false},{"Name":"enable-code-signin","Field":"enableCodeSignin","Type":"boolean","Help":"","Required":false},{"Name":"enable-exclusive-signin","Field":"enableExclusiveSignin","Type":"boolean","Help":"","Required":false},{"Name":"enable-link-with-email","Field":"enableLinkWithEmail","Type":"boolean","Help":"","Required":false},{"Name":"enable-password","Field":"enablePassword","Type":"boolean","Help":"","Required":false},{"Name":"enable-saml-assertion-signature","Field":"enableSamlAssertionSignature","Type":"boolean","Help":"","Required":false},{"Name":"enable-saml-c14n10","Field":"enableSamlC14n10","Type":"boolean","Help":"","Required":false},{"Name":"enable-saml-compress","Field":"enableSamlCompress","Type":"boolean","Help":"","Required":false},{"Name":"enable-saml-post-binding","Field":"enableSamlPostBinding","Type":"boolean","Help":"","Required":false},{"Name":"enable-sign-up","Field":"enableSignUp","Type":"boolean","Help":"","Required":false},{"Name":"enable-signin-session","Field":"enableSigninSession","Type":"boolean","Help":"","Required":false},{"Name":"enable-web-authn","Field":"enableWebAuthn","Type":"boolean","Help":"","Required":false},{"Name":"environment","Field":"environment","Type":"string","Help":"","Required":false},{"Name":"expire-in-hours","Field":"expireInHours","Type":"number","Help":"","Required":false},{"Name":"failed-signin-frozen-time","Field":"failedSigninFrozenTime","Type":"integer","Help":"","Required":false},{"Name":"failed-signin-limit","Field":"failedSigninLimit","Type":"integer","Help":"","Required":false},{"Name":"favicon","Field":"favicon","Type":"string","Help":"","Required":false},{"Name":"footer-html","Field":"footerHtml","Type":"string","Help":"","Required":false},{"Name":"forced-redirect-origin","Field":"forcedRedirectOrigin","Type":"string","Help":"","Required":false},{"Name":"forget-url","Field":"forgetUrl","Type":"string","Help":"","Required":false},{"Name":"form-background-url","Field":"formBackgroundUrl","Type":"string","Help":"","Required":false},{"Name":"form-background-url-mobile","Field":"formBackgroundUrlMobile","Type":"string","Help":"","Required":false},{"Name":"form-css","Field":"formCss","Type":"string","Help":"","Required":false},{"Name":"form-css-mobile","Field":"formCssMobile","Type":"string","Help":"","Required":false},{"Name":"form-offset","Field":"formOffset","Type":"integer","Help":"","Required":false},{"Name":"form-side-html","Field":"formSideHtml","Type":"string","Help":"","Required":false},{"Name":"grant-types","Field":"grantTypes","Type":"json","Help":"","Required":false},{"Name":"header-html","Field":"headerHtml","Type":"string","Help":"","Required":false},{"Name":"homepage-url","Field":"homepageUrl","Type":"string","Help":"","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"Persisted fields","Required":false},{"Name":"ip-restriction","Field":"ipRestriction","Type":"string","Help":"","Required":false},{"Name":"ip-whitelist","Field":"ipWhitelist","Type":"string","Help":"","Required":false},{"Name":"is-shared","Field":"isShared","Type":"boolean","Help":"","Required":false},{"Name":"logo","Field":"logo","Type":"string","Help":"","Required":false},{"Name":"order","Field":"order","Type":"integer","Help":"","Required":false},{"Name":"org-choice-mode","Field":"orgChoiceMode","Type":"string","Help":"","Required":false},{"Name":"organization","Field":"organization","Type":"string","Help":"","Required":false},{"Name":"organization-obj","Field":"organizationObj","Type":"json","Help":"","Required":false},{"Name":"other-domains","Field":"otherDomains","Type":"json","Help":"","Required":false},{"Name":"platform","Field":"platform","Type":"boolean","Help":"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.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"","Required":false},{"Name":"providers","Field":"providers","Type":"json","Help":"","Required":false},{"Name":"redirect-uris","Field":"redirectUris","Type":"json","Help":"","Required":false},{"Name":"refresh-expire-in-hours","Field":"refreshExpireInHours","Type":"number","Help":"","Required":false},{"Name":"saml-attributes","Field":"samlAttributes","Type":"json","Help":"","Required":false},{"Name":"saml-hash-algorithm","Field":"samlHashAlgorithm","Type":"string","Help":"","Required":false},{"Name":"saml-reply-url","Field":"samlReplyUrl","Type":"string","Help":"","Required":false},{"Name":"scopes","Field":"scopes","Type":"json","Help":"","Required":false},{"Name":"signin-html","Field":"signinHtml","Type":"string","Help":"","Required":false},{"Name":"signin-items","Field":"signinItems","Type":"json","Help":"","Required":false},{"Name":"signin-methods","Field":"signinMethods","Type":"json","Help":"","Required":false},{"Name":"signin-url","Field":"signinUrl","Type":"string","Help":"","Required":false},{"Name":"signup-html","Field":"signupHtml","Type":"string","Help":"","Required":false},{"Name":"signup-items","Field":"signupItems","Type":"json","Help":"","Required":false},{"Name":"signup-url","Field":"signupUrl","Type":"string","Help":"","Required":false},{"Name":"ssl-cert","Field":"sslCert","Type":"string","Help":"","Required":false},{"Name":"ssl-mode","Field":"sslMode","Type":"string","Help":"","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"","Required":false},{"Name":"terms-of-use","Field":"termsOfUse","Type":"string","Help":"","Required":false},{"Name":"theme-data","Field":"themeData","Type":"json","Help":"","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"","Required":false},{"Name":"token-attributes","Field":"tokenAttributes","Type":"json","Help":"","Required":false},{"Name":"token-fields","Field":"tokenFields","Type":"json","Help":"","Required":false},{"Name":"token-format","Field":"tokenFormat","Type":"string","Help":"","Required":false},{"Name":"token-signing-method","Field":"tokenSigningMethod","Type":"string","Help":"","Required":false},{"Name":"type","Field":"type","Type":"string","Help":"","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"string","Help":"","Required":false},{"Name":"upstream-host","Field":"upstreamHost","Type":"string","Help":"","Required":false},{"Name":"use-email-as-saml-name-id","Field":"useEmailAsSamlNameId","Type":"boolean","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"audit-logs-create","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.","Method":"POST","Path":"/v1/iam/audit-logs","Args":[],"Flags":[{"Name":"action","Field":"action","Type":"string","Help":"","Required":false},{"Name":"client-ip","Field":"clientIp","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"is-triggered","Field":"isTriggered","Type":"boolean","Help":"","Required":false},{"Name":"language","Field":"language","Type":"string","Help":"","Required":false},{"Name":"method","Field":"method","Type":"string","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"object","Field":"object","Type":"string","Help":"","Required":false},{"Name":"organization","Field":"organization","Type":"string","Help":"","Required":false},{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false},{"Name":"request-uri","Field":"requestUri","Type":"string","Help":"","Required":false},{"Name":"response","Field":"response","Type":"string","Help":"","Required":false},{"Name":"status-code","Field":"statusCode","Type":"integer","Help":"","Required":false},{"Name":"user","Field":"user","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"audit-logs-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.","Method":"DELETE","Path":"/v1/iam/audit-logs/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"audit-logs-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.","Method":"GET","Path":"/v1/iam/audit-logs/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"audit-logs-list","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.","Method":"GET","Path":"/v1/iam/audit-logs","Args":[],"Flags":[{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"audit-logs-update","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.","Method":"PUT","Path":"/v1/iam/audit-logs/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":[{"Name":"action","Field":"action","Type":"string","Help":"","Required":false},{"Name":"client-ip","Field":"clientIp","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"is-triggered","Field":"isTriggered","Type":"boolean","Help":"","Required":false},{"Name":"language","Field":"language","Type":"string","Help":"","Required":false},{"Name":"method","Field":"method","Type":"string","Help":"","Required":false},{"Name":"object","Field":"object","Type":"string","Help":"","Required":false},{"Name":"organization","Field":"organization","Type":"string","Help":"","Required":false},{"Name":"request-uri","Field":"requestUri","Type":"string","Help":"","Required":false},{"Name":"response","Field":"response","Type":"string","Help":"","Required":false},{"Name":"status-code","Field":"statusCode","Type":"integer","Help":"","Required":false},{"Name":"user","Field":"user","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"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.","Method":"GET","Path":"/v1/iam/auth/application","Args":[],"Flags":[{"Name":"client-id","Field":"clientId","Type":"string","Help":"ClientId is the application's OAuth client id — the one field that selects\nwhich login screen this is.","Required":false},{"Name":"response-type","Field":"responseType","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"iam","Name":"auth-identifier-create","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.","Method":"POST","Path":"/v1/iam/auth/identifier","Args":[],"Flags":[{"Name":"client-id","Field":"clientId","Type":"string","Help":"ClientId is the application's OAuth client id.","Required":false},{"Name":"identifier","Field":"identifier","Type":"string","Help":"Identifier is the email address the person typed.","Required":false}],"Example":null},{"Service":"iam","Name":"auth-methods-list","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.","Method":"GET","Path":"/v1/iam/auth/methods","Args":[],"Flags":[{"Name":"client-id","Field":"clientId","Type":"string","Help":"ClientId is the application's OAuth client id.","Required":false}],"Example":null},{"Service":"iam","Name":"certs-create","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.","Method":"POST","Path":"/v1/iam/certs","Args":[],"Flags":[{"Name":"access-key","Field":"accessKey","Type":"string","Help":"","Required":false},{"Name":"access-secret","Field":"accessSecret","Type":"string","Help":"","Required":false},{"Name":"account","Field":"account","Type":"string","Help":"","Required":false},{"Name":"bit-size","Field":"bitSize","Type":"integer","Help":"","Required":false},{"Name":"certificate","Field":"certificate","Type":"string","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"crypto-algorithm","Field":"cryptoAlgorithm","Type":"string","Help":"","Required":false},{"Name":"deleted","Field":"deleted","Type":"boolean","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"domain-expire-time","Field":"domainExpireTime","Type":"string","Help":"","Required":false},{"Name":"expire-in-years","Field":"expireInYears","Type":"integer","Help":"","Required":false},{"Name":"expire-time","Field":"expireTime","Type":"string","Help":"","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"Persisted fields","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false},{"Name":"provider","Field":"provider","Type":"string","Help":"","Required":false},{"Name":"scope","Field":"scope","Type":"string","Help":"","Required":false},{"Name":"type","Field":"type","Type":"string","Help":"","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"certs-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.","Method":"DELETE","Path":"/v1/iam/certs/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"certs-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.","Method":"GET","Path":"/v1/iam/certs/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"certs-list","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.","Method":"GET","Path":"/v1/iam/certs","Args":[],"Flags":[{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"certs-update","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.","Method":"PUT","Path":"/v1/iam/certs/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":[{"Name":"access-key","Field":"accessKey","Type":"string","Help":"","Required":false},{"Name":"access-secret","Field":"accessSecret","Type":"string","Help":"","Required":false},{"Name":"account","Field":"account","Type":"string","Help":"","Required":false},{"Name":"bit-size","Field":"bitSize","Type":"integer","Help":"","Required":false},{"Name":"certificate","Field":"certificate","Type":"string","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"crypto-algorithm","Field":"cryptoAlgorithm","Type":"string","Help":"","Required":false},{"Name":"deleted","Field":"deleted","Type":"boolean","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"domain-expire-time","Field":"domainExpireTime","Type":"string","Help":"","Required":false},{"Name":"expire-in-years","Field":"expireInYears","Type":"integer","Help":"","Required":false},{"Name":"expire-time","Field":"expireTime","Type":"string","Help":"","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"Persisted fields","Required":false},{"Name":"provider","Field":"provider","Type":"string","Help":"","Required":false},{"Name":"scope","Field":"scope","Type":"string","Help":"","Required":false},{"Name":"type","Field":"type","Type":"string","Help":"","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"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.","Method":"GET","Path":"/v1/iam/consent","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"consent-update","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.","Method":"PUT","Path":"/v1/iam/consent","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"create-organization","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.","Method":"POST","Path":"/v1/iam/organizations","Args":[],"Flags":[{"Name":"account-items","Field":"accountItems","Type":"json","Help":"","Required":false},{"Name":"account-menu","Field":"accountMenu","Type":"string","Help":"","Required":false},{"Name":"avatar","Field":"avatar","Type":"string","Help":"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.","Required":false},{"Name":"balance-credit","Field":"balanceCredit","Type":"number","Help":"","Required":false},{"Name":"balance-currency","Field":"balanceCurrency","Type":"string","Help":"","Required":false},{"Name":"country-codes","Field":"countryCodes","Type":"json","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"dcr-policy","Field":"dcrPolicy","Type":"string","Help":"","Required":false},{"Name":"default-application","Field":"defaultApplication","Type":"string","Help":"","Required":false},{"Name":"default-avatar","Field":"defaultAvatar","Type":"string","Help":"","Required":false},{"Name":"default-password","Field":"defaultPassword","Type":"string","Help":"","Required":false},{"Name":"deleted","Field":"deleted","Type":"boolean","Help":"","Required":false},{"Name":"disable-signin","Field":"disableSignin","Type":"boolean","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"emoji","Field":"emoji","Type":"string","Help":"","Required":false},{"Name":"enable-soft-deletion","Field":"enableSoftDeletion","Type":"boolean","Help":"","Required":false},{"Name":"enable-tour","Field":"enableTour","Type":"boolean","Help":"","Required":false},{"Name":"failed-signin-frozen-time","Field":"failedSigninFrozenTime","Type":"integer","Help":"","Required":false},{"Name":"failed-signin-limit","Field":"failedSigninLimit","Type":"integer","Help":"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.","Required":false},{"Name":"favicon","Field":"favicon","Type":"string","Help":"","Required":false},{"Name":"founder","Field":"founder","Type":"string","Help":"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.","Required":false},{"Name":"has-privilege-consent","Field":"hasPrivilegeConsent","Type":"boolean","Help":"","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"Persisted fields","Required":false},{"Name":"init-score","Field":"initScore","Type":"integer","Help":"","Required":false},{"Name":"ip-restriction","Field":"ipRestriction","Type":"string","Help":"","Required":false},{"Name":"ip-whitelist","Field":"ipWhitelist","Type":"string","Help":"","Required":false},{"Name":"is-personal","Field":"isPersonal","Type":"boolean","Help":"","Required":false},{"Name":"is-profile-public","Field":"isProfilePublic","Type":"boolean","Help":"","Required":false},{"Name":"kerberos-kdc-host","Field":"kerberosKdcHost","Type":"string","Help":"","Required":false},{"Name":"kerberos-keytab","Field":"kerberosKeytab","Type":"string","Help":"","Required":false},{"Name":"kerberos-realm","Field":"kerberosRealm","Type":"string","Help":"","Required":false},{"Name":"kerberos-service-name","Field":"kerberosServiceName","Type":"string","Help":"","Required":false},{"Name":"languages","Field":"languages","Type":"json","Help":"","Required":false},{"Name":"ldap-attributes","Field":"ldapAttributes","Type":"json","Help":"","Required":false},{"Name":"logo","Field":"logo","Type":"string","Help":"","Required":false},{"Name":"logo-dark","Field":"logoDark","Type":"string","Help":"","Required":false},{"Name":"master-password","Field":"masterPassword","Type":"string","Help":"","Required":false},{"Name":"master-verification-code","Field":"masterVerificationCode","Type":"string","Help":"","Required":false},{"Name":"mfa-items","Field":"mfaItems","Type":"json","Help":"","Required":false},{"Name":"mfa-remember-in-hours","Field":"mfaRememberInHours","Type":"integer","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"nav-items","Field":"navItems","Type":"json","Help":"","Required":false},{"Name":"org-balance","Field":"orgBalance","Type":"number","Help":"Balance fields are read-only mirrors; authoritative balances live in\nCommerce (billing.hanzo.ai). Carried for field-complete v1 parity.","Required":false},{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false},{"Name":"password-expire-days","Field":"passwordExpireDays","Type":"integer","Help":"","Required":false},{"Name":"password-obfuscator-key","Field":"passwordObfuscatorKey","Type":"string","Help":"","Required":false},{"Name":"password-obfuscator-type","Field":"passwordObfuscatorType","Type":"string","Help":"","Required":false},{"Name":"password-options","Field":"passwordOptions","Type":"json","Help":"","Required":false},{"Name":"password-salt","Field":"passwordSalt","Type":"string","Help":"","Required":false},{"Name":"password-type","Field":"passwordType","Type":"string","Help":"","Required":false},{"Name":"platform","Field":"platform","Type":"boolean","Help":"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.","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"","Required":false},{"Name":"theme-data","Field":"themeData","Type":"json","Help":"","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"string","Help":"","Required":false},{"Name":"use-email-as-username","Field":"useEmailAsUsername","Type":"boolean","Help":"","Required":false},{"Name":"use-permanent-avatar","Field":"usePermanentAvatar","Type":"boolean","Help":"","Required":false},{"Name":"user-balance","Field":"userBalance","Type":"number","Help":"","Required":false},{"Name":"user-nav-items","Field":"userNavItems","Type":"json","Help":"","Required":false},{"Name":"user-types","Field":"userTypes","Type":"json","Help":"","Required":false},{"Name":"website-url","Field":"websiteUrl","Type":"string","Help":"","Required":false},{"Name":"widget-items","Field":"widgetItems","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"create-session","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.","Method":"POST","Path":"/v1/iam/sessions","Args":[],"Flags":[{"Name":"application","Field":"application","Type":"string","Help":"","Required":true},{"Name":"exclusive-signin","Field":"exclusiveSignin","Type":"boolean","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":true},{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":true},{"Name":"session-id","Field":"sessionId","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"delete-membership-create","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.","Method":"POST","Path":"/v1/iam/delete-membership","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"delete-organization","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.","Method":"DELETE","Path":"/v1/iam/organizations/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"delete-provider","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.","Method":"DELETE","Path":"/v1/iam/providers/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"delete-session","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.","Method":"DELETE","Path":"/v1/iam/sessions/:owner/:name/:application","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""},{"Name":"application","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"delete-token","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.","Method":"DELETE","Path":"/v1/iam/tokens/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"delete-webauthn-credential","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.","Method":"DELETE","Path":"/v1/iam/webauthn-credentials/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"get-organization","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.","Method":"GET","Path":"/v1/iam/organizations/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"get-organization-tombstone","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.","Method":"GET","Path":"/v1/iam/organizations/tombstones/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"get-provider","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.","Method":"GET","Path":"/v1/iam/providers/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"get-session","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.","Method":"GET","Path":"/v1/iam/sessions/:owner/:name/:application","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""},{"Name":"application","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"get-token","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.","Method":"GET","Path":"/v1/iam/tokens/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"get-webauthn-credential","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.","Method":"GET","Path":"/v1/iam/webauthn-credentials/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"invitations-accept-create","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.","Method":"POST","Path":"/v1/iam/invitations/accept","Args":[],"Flags":[{"Name":"code","Field":"code","Type":"string","Help":"","Required":false},{"Name":"email-code","Field":"emailCode","Type":"string","Help":"","Required":false},{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"invitations-create","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.","Method":"POST","Path":"/v1/iam/invitations","Args":[],"Flags":[{"Name":"application","Field":"application","Type":"string","Help":"","Required":false},{"Name":"code","Field":"code","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"default-code","Field":"defaultCode","Type":"string","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"email","Field":"email","Type":"string","Help":"","Required":false},{"Name":"is-regexp","Field":"isRegexp","Type":"boolean","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false},{"Name":"phone","Field":"phone","Type":"string","Help":"","Required":false},{"Name":"quota","Field":"quota","Type":"integer","Help":"","Required":false},{"Name":"signup-group","Field":"signupGroup","Type":"string","Help":"","Required":false},{"Name":"state","Field":"state","Type":"string","Help":"","Required":false},{"Name":"updated-time","Field":"updatedTime","Type":"string","Help":"","Required":false},{"Name":"used-count","Field":"usedCount","Type":"integer","Help":"","Required":false},{"Name":"username","Field":"username","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"invitations-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.","Method":"DELETE","Path":"/v1/iam/invitations/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"invitations-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.","Method":"GET","Path":"/v1/iam/invitations/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"invitations-list","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.","Method":"GET","Path":"/v1/iam/invitations","Args":[],"Flags":[{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"invitations-send","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.","Method":"POST","Path":"/v1/iam/invitations/:owner/:name/send","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"invitations-update","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.","Method":"PUT","Path":"/v1/iam/invitations/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":[{"Name":"application","Field":"application","Type":"string","Help":"","Required":false},{"Name":"code","Field":"code","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"default-code","Field":"defaultCode","Type":"string","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"email","Field":"email","Type":"string","Help":"","Required":false},{"Name":"is-regexp","Field":"isRegexp","Type":"boolean","Help":"","Required":false},{"Name":"phone","Field":"phone","Type":"string","Help":"","Required":false},{"Name":"quota","Field":"quota","Type":"integer","Help":"","Required":false},{"Name":"signup-group","Field":"signupGroup","Type":"string","Help":"","Required":false},{"Name":"state","Field":"state","Type":"string","Help":"","Required":false},{"Name":"updated-time","Field":"updatedTime","Type":"string","Help":"","Required":false},{"Name":"used-count","Field":"usedCount","Type":"integer","Help":"","Required":false},{"Name":"username","Field":"username","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"keys-create","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.","Method":"POST","Path":"/v1/iam/keys","Args":[],"Flags":[{"Name":"access-key","Field":"accessKey","Type":"string","Help":"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.","Required":false},{"Name":"access-secret","Field":"accessSecret","Type":"string","Help":"","Required":false},{"Name":"access-secret-digest","Field":"accessSecretDigest","Type":"string","Help":"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.","Required":false},{"Name":"act","Field":"act","Type":"boolean","Help":"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.","Required":false},{"Name":"application","Field":"application","Type":"string","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"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).","Required":false},{"Name":"deleted","Field":"deleted","Type":"boolean","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"DisplayName is the human-facing label.","Required":false},{"Name":"expire-time","Field":"expireTime","Type":"string","Help":"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.","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"Persisted fields","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"organization","Field":"organization","Type":"string","Help":"","Required":false},{"Name":"owner","Field":"owner","Type":"string","Help":"Owner is the tenant that holds the key; Name is unique within Owner.","Required":false},{"Name":"prefix","Field":"prefix","Type":"string","Help":"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.","Required":false},{"Name":"revoke-time","Field":"revokeTime","Type":"string","Help":"","Required":false},{"Name":"revoker","Field":"revoker","Type":"string","Help":"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.","Required":false},{"Name":"scope","Field":"scope","Type":"string","Help":"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.","Required":false},{"Name":"state","Field":"state","Type":"string","Help":"","Required":false},{"Name":"type","Field":"type","Type":"string","Help":"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.","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"string","Help":"","Required":false},{"Name":"updated-time","Field":"updatedTime","Type":"string","Help":"","Required":false},{"Name":"used-time","Field":"usedTime","Type":"string","Help":"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.","Required":false},{"Name":"user","Field":"user","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"keys-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.","Method":"DELETE","Path":"/v1/iam/keys/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"keys-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.","Method":"GET","Path":"/v1/iam/keys/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"keys-list","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.","Method":"GET","Path":"/v1/iam/keys","Args":[],"Flags":[{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"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.","Method":"GET","Path":"/v1/iam/keys/org","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"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.","Method":"GET","Path":"/v1/iam/keys/principal","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"keys-update","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.","Method":"PUT","Path":"/v1/iam/keys/:owner/:name","Args":[{"Name":"owner","Help":"Owner is the tenant that holds the key; Name is unique within Owner."},{"Name":"name","Help":""}],"Flags":[{"Name":"access-key","Field":"accessKey","Type":"string","Help":"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.","Required":false},{"Name":"access-secret","Field":"accessSecret","Type":"string","Help":"","Required":false},{"Name":"access-secret-digest","Field":"accessSecretDigest","Type":"string","Help":"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.","Required":false},{"Name":"act","Field":"act","Type":"boolean","Help":"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.","Required":false},{"Name":"application","Field":"application","Type":"string","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"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).","Required":false},{"Name":"deleted","Field":"deleted","Type":"boolean","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"DisplayName is the human-facing label.","Required":false},{"Name":"expire-time","Field":"expireTime","Type":"string","Help":"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.","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"Persisted fields","Required":false},{"Name":"organization","Field":"organization","Type":"string","Help":"","Required":false},{"Name":"prefix","Field":"prefix","Type":"string","Help":"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.","Required":false},{"Name":"revoke-time","Field":"revokeTime","Type":"string","Help":"","Required":false},{"Name":"revoker","Field":"revoker","Type":"string","Help":"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.","Required":false},{"Name":"scope","Field":"scope","Type":"string","Help":"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.","Required":false},{"Name":"state","Field":"state","Type":"string","Help":"","Required":false},{"Name":"type","Field":"type","Type":"string","Help":"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.","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"string","Help":"","Required":false},{"Name":"updated-time","Field":"updatedTime","Type":"string","Help":"","Required":false},{"Name":"used-time","Field":"usedTime","Type":"string","Help":"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.","Required":false},{"Name":"user","Field":"user","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"link-create","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.","Method":"POST","Path":"/v1/iam/link","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"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.","Method":"GET","Path":"/v1/iam/link","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"linked-accounts-list","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.","Method":"GET","Path":"/v1/iam/linked-accounts","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"list-organizations","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.","Method":"GET","Path":"/v1/iam/organizations","Args":[],"Flags":[{"Name":"q","Field":"q","Type":"string","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"cursor","Field":"cursor","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"list-providers","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.","Method":"GET","Path":"/v1/iam/providers","Args":[],"Flags":[{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"list-sessions","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.","Method":"GET","Path":"/v1/iam/sessions","Args":[],"Flags":[{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"application","Field":"application","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"list-tokens","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.","Method":"GET","Path":"/v1/iam/tokens","Args":[],"Flags":[{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false},{"Name":"organization","Field":"organization","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"list-webauthn-credentials","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.","Method":"GET","Path":"/v1/iam/webauthn-credentials","Args":[],"Flags":[{"Name":"user","Field":"user","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"login-create","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.","Method":"POST","Path":"/v1/iam/login","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"memberships-create","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).","Method":"POST","Path":"/v1/iam/memberships","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"memberships-list","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.","Method":"GET","Path":"/v1/iam/memberships","Args":[],"Flags":[{"Name":"user","Field":"user","Type":"string","Help":"User is \"\u003chomeOrg\u003e/\u003cusername\u003e\" — which organizations that identity may act in.","Required":false},{"Name":"org","Field":"org","Type":"string","Help":"Org is an organization — who may act in it.","Required":false}],"Example":null},{"Service":"iam","Name":"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.","Method":"DELETE","Path":"/v1/iam/mfa","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"mfa-preferred-create","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.","Method":"POST","Path":"/v1/iam/mfa/preferred","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"mfa-setup-enable-create","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.","Method":"POST","Path":"/v1/iam/mfa/setup/enable","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"mfa-setup-initiate-create","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.","Method":"POST","Path":"/v1/iam/mfa/setup/initiate","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"oauth-authorize-create","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.","Method":"POST","Path":"/v1/iam/oauth/authorize","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"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.","Method":"GET","Path":"/v1/iam/oauth/authorize","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"oauth-callback-create","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.","Method":"POST","Path":"/v1/iam/oauth/callback","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"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.","Method":"GET","Path":"/v1/iam/oauth/callback","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"oauth-delegation-keys-list","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.","Method":"GET","Path":"/v1/iam/oauth/delegation/keys","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"oauth-device-create","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.","Method":"POST","Path":"/v1/iam/oauth/device","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"oauth-device-info-create","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.","Method":"POST","Path":"/v1/iam/oauth/device/info","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"oauth-federation-mfa-create","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.","Method":"POST","Path":"/v1/iam/oauth/federation/mfa","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"oauth-introspect-create","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.","Method":"POST","Path":"/v1/iam/oauth/introspect","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"oauth-logout-create","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.","Method":"POST","Path":"/v1/iam/oauth/logout","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"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.","Method":"GET","Path":"/v1/iam/oauth/logout","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"oauth-refresh-token-create","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.","Method":"POST","Path":"/v1/iam/oauth/refresh_token","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"oauth-revoke-create","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.","Method":"POST","Path":"/v1/iam/oauth/revoke","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"oauth-token-create","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.","Method":"POST","Path":"/v1/iam/oauth/token","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"oauth-userinfo-create","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.","Method":"POST","Path":"/v1/iam/oauth/userinfo","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"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.","Method":"GET","Path":"/v1/iam/oauth/userinfo","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"onboard-create","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.","Method":"POST","Path":"/v1/iam/onboard","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"password-update","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.","Method":"PUT","Path":"/v1/iam/password","Args":[],"Flags":[{"Name":"code","Field":"code","Type":"string","Help":"Code is the one-time code delivered to the account's own address.","Required":false},{"Name":"old-password","Field":"oldPassword","Type":"string","Help":"OldPassword is the credential being replaced, the proof a signed-in caller\ngives instead of a code.","Required":false},{"Name":"organization","Field":"organization","Type":"string","Help":"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.","Required":false},{"Name":"password","Field":"password","Type":"string","Help":"Password is the new credential. It must satisfy the platform floor and the\norganization's own complexity options.","Required":false},{"Name":"username","Field":"username","Type":"string","Help":"email, username OR phone","Required":false}],"Example":null},{"Service":"iam","Name":"permissions-create","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.","Method":"POST","Path":"/v1/iam/permissions","Args":[],"Flags":[{"Name":"actions","Field":"actions","Type":"json","Help":"","Required":false},{"Name":"adapter","Field":"adapter","Type":"string","Help":"","Required":false},{"Name":"approve-time","Field":"approveTime","Type":"string","Help":"","Required":false},{"Name":"approver","Field":"approver","Type":"string","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"Descriptive metadata.","Required":false},{"Name":"deleted","Field":"deleted","Type":"boolean","Help":"","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"domains","Field":"domains","Type":"json","Help":"","Required":false},{"Name":"effect","Field":"effect","Type":"string","Help":"","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"Persisted fields","Required":false},{"Name":"is-enabled","Field":"isEnabled","Type":"boolean","Help":"","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"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\".","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"owner","Field":"owner","Type":"string","Help":"Identity — the (owner, name) natural key.","Required":false},{"Name":"resource-type","Field":"resourceType","Type":"string","Help":"","Required":false},{"Name":"resources","Field":"resources","Type":"json","Help":"","Required":false},{"Name":"roles","Field":"roles","Type":"json","Help":"","Required":false},{"Name":"state","Field":"state","Type":"string","Help":"","Required":false},{"Name":"submitter","Field":"submitter","Type":"string","Help":"Submission / approval workflow.","Required":false},{"Name":"teams","Field":"teams","Type":"json","Help":"","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"string","Help":"","Required":false},{"Name":"users","Field":"users","Type":"json","Help":"Subjects the grant is evaluated for.","Required":false}],"Example":null},{"Service":"iam","Name":"permissions-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.","Method":"DELETE","Path":"/v1/iam/permissions/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"permissions-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.","Method":"GET","Path":"/v1/iam/permissions/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"permissions-list","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.","Method":"GET","Path":"/v1/iam/permissions","Args":[],"Flags":[{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"permissions-update","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.","Method":"PUT","Path":"/v1/iam/permissions/:owner/:name","Args":[{"Name":"owner","Help":"Identity — the (owner, name) natural key."},{"Name":"name","Help":""}],"Flags":[{"Name":"actions","Field":"actions","Type":"json","Help":"","Required":false},{"Name":"adapter","Field":"adapter","Type":"string","Help":"","Required":false},{"Name":"approve-time","Field":"approveTime","Type":"string","Help":"","Required":false},{"Name":"approver","Field":"approver","Type":"string","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"Descriptive metadata.","Required":false},{"Name":"deleted","Field":"deleted","Type":"boolean","Help":"","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"domains","Field":"domains","Type":"json","Help":"","Required":false},{"Name":"effect","Field":"effect","Type":"string","Help":"","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"Persisted fields","Required":false},{"Name":"is-enabled","Field":"isEnabled","Type":"boolean","Help":"","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"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\".","Required":false},{"Name":"resource-type","Field":"resourceType","Type":"string","Help":"","Required":false},{"Name":"resources","Field":"resources","Type":"json","Help":"","Required":false},{"Name":"roles","Field":"roles","Type":"json","Help":"","Required":false},{"Name":"state","Field":"state","Type":"string","Help":"","Required":false},{"Name":"submitter","Field":"submitter","Type":"string","Help":"Submission / approval workflow.","Required":false},{"Name":"teams","Field":"teams","Type":"json","Help":"","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"string","Help":"","Required":false},{"Name":"users","Field":"users","Type":"json","Help":"Subjects the grant is evaluated for.","Required":false}],"Example":null},{"Service":"iam","Name":"preferences-create","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.","Method":"POST","Path":"/v1/iam/preferences","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"projects-create","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.","Method":"POST","Path":"/v1/iam/projects","Args":[],"Flags":[{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"is-default","Field":"isDefault","Type":"boolean","Help":"","Required":false},{"Name":"metadata","Field":"metadata","Type":"string","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"organization","Field":"organization","Type":"string","Help":"","Required":false},{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"","Required":false},{"Name":"workspace","Field":"workspace","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"projects-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.","Method":"DELETE","Path":"/v1/iam/projects/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"projects-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.","Method":"GET","Path":"/v1/iam/projects/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"projects-list","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.","Method":"GET","Path":"/v1/iam/projects","Args":[],"Flags":[{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"projects-update","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.","Method":"PUT","Path":"/v1/iam/projects/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":[{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"is-default","Field":"isDefault","Type":"boolean","Help":"","Required":false},{"Name":"metadata","Field":"metadata","Type":"string","Help":"","Required":false},{"Name":"organization","Field":"organization","Type":"string","Help":"","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"","Required":false},{"Name":"workspace","Field":"workspace","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"registry-jwks-list","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.","Method":"GET","Path":"/v1/iam/registry/jwks","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"registry-token-create","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.","Method":"POST","Path":"/v1/iam/registry/token","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"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.","Method":"GET","Path":"/v1/iam/registry/token","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"release-organization-name","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.","Method":"DELETE","Path":"/v1/iam/organizations/tombstones/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"roles-create","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.","Method":"POST","Path":"/v1/iam/roles","Args":[],"Flags":[{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"domains","Field":"domains","Type":"json","Help":"","Required":false},{"Name":"is-enabled","Field":"isEnabled","Type":"boolean","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name addresses the team on update and names it on create; every other\nfield is content and binds from the BODY, never the URL.","Required":false},{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false},{"Name":"roles","Field":"roles","Type":"json","Help":"","Required":false},{"Name":"teams","Field":"teams","Type":"json","Help":"","Required":false},{"Name":"users","Field":"users","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"roles-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.","Method":"DELETE","Path":"/v1/iam/roles/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"roles-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.","Method":"GET","Path":"/v1/iam/roles/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"roles-list","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.","Method":"GET","Path":"/v1/iam/roles","Args":[],"Flags":[{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"roles-update","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.","Method":"PUT","Path":"/v1/iam/roles/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":"Name addresses the team on update and names it on create; every other\nfield is content and binds from the BODY, never the URL."}],"Flags":[{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"domains","Field":"domains","Type":"json","Help":"","Required":false},{"Name":"is-enabled","Field":"isEnabled","Type":"boolean","Help":"","Required":false},{"Name":"roles","Field":"roles","Type":"json","Help":"","Required":false},{"Name":"teams","Field":"teams","Type":"json","Help":"","Required":false},{"Name":"users","Field":"users","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"scim-resource-types-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.","Method":"GET","Path":"/v1/iam/scim/v2/ResourceTypes/:name","Args":[{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"scim-resource-types-list","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.","Method":"GET","Path":"/v1/iam/scim/v2/ResourceTypes","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"scim-schemas-get","OperationID":"get_iam_scim_v2_schemas_by_id","Summary":"Returns one attribute definition in full.","Description":"Returns one attribute definition in full.","Method":"GET","Path":"/v1/iam/scim/v2/Schemas/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"scim-schemas-list","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.","Method":"GET","Path":"/v1/iam/scim/v2/Schemas","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"scim-service-provider-config-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.","Method":"GET","Path":"/v1/iam/scim/v2/ServiceProviderConfig","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"scim-users-create","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.","Method":"POST","Path":"/v1/iam/scim/v2/Users","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"scim-users-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.","Method":"DELETE","Path":"/v1/iam/scim/v2/Users/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"scim-users-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.","Method":"GET","Path":"/v1/iam/scim/v2/Users/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"scim-users-list","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.","Method":"GET","Path":"/v1/iam/scim/v2/Users","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"scim-users-update","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.","Method":"PATCH","Path":"/v1/iam/scim/v2/Users/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"scim-users-update","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.","Method":"PUT","Path":"/v1/iam/scim/v2/Users/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"service-accounts-create","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.","Method":"POST","Path":"/v1/iam/service-accounts","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"service-accounts-delete","OperationID":"delete_iam_service-accounts_by_name","Summary":"Serves DELETE /v1/iam/service-accounts/:name.","Description":"Serves DELETE /v1/iam/service-accounts/:name.","Method":"DELETE","Path":"/v1/iam/service-accounts/:name","Args":[{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"service-accounts-keys","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.","Method":"POST","Path":"/v1/iam/service-accounts/:name/keys","Args":[{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"service-accounts-list","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).","Method":"GET","Path":"/v1/iam/service-accounts","Args":[],"Flags":[{"Name":"organization","Field":"organization","Type":"string","Help":"Organization is the organization whose service accounts to list. Required.","Required":false},{"Name":"p","Field":"p","Type":"integer","Help":"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.","Required":false},{"Name":"page-size","Field":"pageSize","Type":"integer","Help":"Size is how many accounts a page holds.","Required":false}],"Example":null},{"Service":"iam","Name":"set-organization-avatar","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.","Method":"POST","Path":"/v1/iam/organizations/avatar","Args":[],"Flags":[{"Name":"avatar","Field":"avatar","Type":"string","Help":"","Required":false},{"Name":"emoji","Field":"emoji","Type":"string","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"set-organization-profile","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.","Method":"POST","Path":"/v1/iam/organizations/profile","Args":[],"Flags":[{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"favicon","Field":"favicon","Type":"string","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false},{"Name":"website-url","Field":"websiteUrl","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"signin-create","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.","Method":"POST","Path":"/v1/iam/signin","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"signup-create","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.","Method":"POST","Path":"/v1/iam/signup","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"teams-create","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.","Method":"POST","Path":"/v1/iam/teams","Args":[],"Flags":[{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"is-enabled","Field":"isEnabled","Type":"boolean","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name addresses the team on update and names it on create; every other\nfield is content and binds from the BODY, never the URL.","Required":false},{"Name":"organization","Field":"organization","Type":"string","Help":"","Required":false},{"Name":"parent","Field":"parent","Type":"string","Help":"","Required":false},{"Name":"users","Field":"users","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"teams-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.","Method":"DELETE","Path":"/v1/iam/teams/:name","Args":[{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"teams-get","OperationID":"get_iam_teams_by_name","Summary":"Returns one team: who is in it.","Description":"Returns one team: who is in it.","Method":"GET","Path":"/v1/iam/teams/:name","Args":[{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"teams-list","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.","Method":"GET","Path":"/v1/iam/teams","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"teams-update","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.","Method":"PUT","Path":"/v1/iam/teams/:name","Args":[{"Name":"name","Help":"Name addresses the team on update and names it on create; every other\nfield is content and binds from the BODY, never the URL."}],"Flags":[{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"is-enabled","Field":"isEnabled","Type":"boolean","Help":"","Required":false},{"Name":"organization","Field":"organization","Type":"string","Help":"","Required":false},{"Name":"parent","Field":"parent","Type":"string","Help":"","Required":false},{"Name":"users","Field":"users","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"terms-update","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.","Method":"PUT","Path":"/v1/iam/terms","Args":[],"Flags":[{"Name":"aup","Field":"aup","Type":"string","Help":"","Required":false},{"Name":"terms","Field":"terms","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"tokens-issue-create","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.","Method":"POST","Path":"/v1/iam/tokens/issue","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"unlink-create","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.","Method":"POST","Path":"/v1/iam/unlink","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"update-organization","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.","Method":"PUT","Path":"/v1/iam/organizations/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":[{"Name":"account-items","Field":"accountItems","Type":"json","Help":"","Required":false},{"Name":"account-menu","Field":"accountMenu","Type":"string","Help":"","Required":false},{"Name":"avatar","Field":"avatar","Type":"string","Help":"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.","Required":false},{"Name":"balance-credit","Field":"balanceCredit","Type":"number","Help":"","Required":false},{"Name":"balance-currency","Field":"balanceCurrency","Type":"string","Help":"","Required":false},{"Name":"country-codes","Field":"countryCodes","Type":"json","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"dcr-policy","Field":"dcrPolicy","Type":"string","Help":"","Required":false},{"Name":"default-application","Field":"defaultApplication","Type":"string","Help":"","Required":false},{"Name":"default-avatar","Field":"defaultAvatar","Type":"string","Help":"","Required":false},{"Name":"default-password","Field":"defaultPassword","Type":"string","Help":"","Required":false},{"Name":"deleted","Field":"deleted","Type":"boolean","Help":"","Required":false},{"Name":"disable-signin","Field":"disableSignin","Type":"boolean","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"emoji","Field":"emoji","Type":"string","Help":"","Required":false},{"Name":"enable-soft-deletion","Field":"enableSoftDeletion","Type":"boolean","Help":"","Required":false},{"Name":"enable-tour","Field":"enableTour","Type":"boolean","Help":"","Required":false},{"Name":"failed-signin-frozen-time","Field":"failedSigninFrozenTime","Type":"integer","Help":"","Required":false},{"Name":"failed-signin-limit","Field":"failedSigninLimit","Type":"integer","Help":"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.","Required":false},{"Name":"favicon","Field":"favicon","Type":"string","Help":"","Required":false},{"Name":"founder","Field":"founder","Type":"string","Help":"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.","Required":false},{"Name":"has-privilege-consent","Field":"hasPrivilegeConsent","Type":"boolean","Help":"","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"Persisted fields","Required":false},{"Name":"init-score","Field":"initScore","Type":"integer","Help":"","Required":false},{"Name":"ip-restriction","Field":"ipRestriction","Type":"string","Help":"","Required":false},{"Name":"ip-whitelist","Field":"ipWhitelist","Type":"string","Help":"","Required":false},{"Name":"is-personal","Field":"isPersonal","Type":"boolean","Help":"","Required":false},{"Name":"is-profile-public","Field":"isProfilePublic","Type":"boolean","Help":"","Required":false},{"Name":"kerberos-kdc-host","Field":"kerberosKdcHost","Type":"string","Help":"","Required":false},{"Name":"kerberos-keytab","Field":"kerberosKeytab","Type":"string","Help":"","Required":false},{"Name":"kerberos-realm","Field":"kerberosRealm","Type":"string","Help":"","Required":false},{"Name":"kerberos-service-name","Field":"kerberosServiceName","Type":"string","Help":"","Required":false},{"Name":"languages","Field":"languages","Type":"json","Help":"","Required":false},{"Name":"ldap-attributes","Field":"ldapAttributes","Type":"json","Help":"","Required":false},{"Name":"logo","Field":"logo","Type":"string","Help":"","Required":false},{"Name":"logo-dark","Field":"logoDark","Type":"string","Help":"","Required":false},{"Name":"master-password","Field":"masterPassword","Type":"string","Help":"","Required":false},{"Name":"master-verification-code","Field":"masterVerificationCode","Type":"string","Help":"","Required":false},{"Name":"mfa-items","Field":"mfaItems","Type":"json","Help":"","Required":false},{"Name":"mfa-remember-in-hours","Field":"mfaRememberInHours","Type":"integer","Help":"","Required":false},{"Name":"nav-items","Field":"navItems","Type":"json","Help":"","Required":false},{"Name":"org-balance","Field":"orgBalance","Type":"number","Help":"Balance fields are read-only mirrors; authoritative balances live in\nCommerce (billing.hanzo.ai). Carried for field-complete v1 parity.","Required":false},{"Name":"password-expire-days","Field":"passwordExpireDays","Type":"integer","Help":"","Required":false},{"Name":"password-obfuscator-key","Field":"passwordObfuscatorKey","Type":"string","Help":"","Required":false},{"Name":"password-obfuscator-type","Field":"passwordObfuscatorType","Type":"string","Help":"","Required":false},{"Name":"password-options","Field":"passwordOptions","Type":"json","Help":"","Required":false},{"Name":"password-salt","Field":"passwordSalt","Type":"string","Help":"","Required":false},{"Name":"password-type","Field":"passwordType","Type":"string","Help":"","Required":false},{"Name":"platform","Field":"platform","Type":"boolean","Help":"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.","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"","Required":false},{"Name":"theme-data","Field":"themeData","Type":"json","Help":"","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"string","Help":"","Required":false},{"Name":"use-email-as-username","Field":"useEmailAsUsername","Type":"boolean","Help":"","Required":false},{"Name":"use-permanent-avatar","Field":"usePermanentAvatar","Type":"boolean","Help":"","Required":false},{"Name":"user-balance","Field":"userBalance","Type":"number","Help":"","Required":false},{"Name":"user-nav-items","Field":"userNavItems","Type":"json","Help":"","Required":false},{"Name":"user-types","Field":"userTypes","Type":"json","Help":"","Required":false},{"Name":"website-url","Field":"websiteUrl","Type":"string","Help":"","Required":false},{"Name":"widget-items","Field":"widgetItems","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"update-provider","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.","Method":"PUT","Path":"/v1/iam/providers/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":[{"Name":"app-id","Field":"appId","Type":"string","Help":"","Required":false},{"Name":"bucket","Field":"bucket","Type":"string","Help":"","Required":false},{"Name":"category","Field":"category","Type":"string","Help":"","Required":false},{"Name":"cert","Field":"cert","Type":"string","Help":"","Required":false},{"Name":"client-id","Field":"clientId","Type":"string","Help":"","Required":false},{"Name":"client-id2","Field":"clientId2","Type":"string","Help":"","Required":false},{"Name":"client-secret","Field":"clientSecret","Type":"string","Help":"","Required":false},{"Name":"client-secret2","Field":"clientSecret2","Type":"string","Help":"","Required":false},{"Name":"content","Field":"content","Type":"string","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"custom-auth-url","Field":"customAuthUrl","Type":"string","Help":"","Required":false},{"Name":"custom-logo","Field":"customLogo","Type":"string","Help":"","Required":false},{"Name":"custom-token-url","Field":"customTokenUrl","Type":"string","Help":"","Required":false},{"Name":"custom-user-info-url","Field":"customUserInfoUrl","Type":"string","Help":"","Required":false},{"Name":"deleted","Field":"deleted","Type":"boolean","Help":"","Required":false},{"Name":"disable-ssl","Field":"disableSsl","Type":"boolean","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"domain","Field":"domain","Type":"string","Help":"","Required":false},{"Name":"email-regex","Field":"emailRegex","Type":"string","Help":"","Required":false},{"Name":"enable-pkce","Field":"enablePkce","Type":"boolean","Help":"","Required":false},{"Name":"enable-proxy","Field":"enableProxy","Type":"boolean","Help":"","Required":false},{"Name":"enable-sign-authn-request","Field":"enableSignAuthnRequest","Type":"boolean","Help":"","Required":false},{"Name":"endpoint","Field":"endpoint","Type":"string","Help":"","Required":false},{"Name":"host","Field":"host","Type":"string","Help":"","Required":false},{"Name":"http-headers","Field":"httpHeaders","Type":"json","Help":"","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"Persisted fields","Required":false},{"Name":"id-p","Field":"idP","Type":"string","Help":"","Required":false},{"Name":"intranet-endpoint","Field":"intranetEndpoint","Type":"string","Help":"","Required":false},{"Name":"issuer-url","Field":"issuerUrl","Type":"string","Help":"","Required":false},{"Name":"metadata","Field":"metadata","Type":"string","Help":"","Required":false},{"Name":"method","Field":"method","Type":"string","Help":"","Required":false},{"Name":"path-prefix","Field":"pathPrefix","Type":"string","Help":"","Required":false},{"Name":"port","Field":"port","Type":"integer","Help":"","Required":false},{"Name":"provider-url","Field":"providerUrl","Type":"string","Help":"","Required":false},{"Name":"receiver","Field":"receiver","Type":"string","Help":"","Required":false},{"Name":"region-id","Field":"regionId","Type":"string","Help":"","Required":false},{"Name":"scopes","Field":"scopes","Type":"string","Help":"","Required":false},{"Name":"sign-name","Field":"signName","Type":"string","Help":"","Required":false},{"Name":"ssl-mode","Field":"sslMode","Type":"string","Help":"","Required":false},{"Name":"sub-type","Field":"subType","Type":"string","Help":"","Required":false},{"Name":"template-code","Field":"templateCode","Type":"string","Help":"","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"","Required":false},{"Name":"type","Field":"type","Type":"string","Help":"","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"string","Help":"","Required":false},{"Name":"user-mapping","Field":"userMapping","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"update-session","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.","Method":"PUT","Path":"/v1/iam/sessions/:owner/:name/:application","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""},{"Name":"application","Help":""}],"Flags":[{"Name":"session-id","Field":"sessionId","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"update-token","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.","Method":"PUT","Path":"/v1/iam/tokens/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":[{"Name":"access-token","Field":"accessToken","Type":"string","Help":"","Required":false},{"Name":"access-token-hash","Field":"accessTokenHash","Type":"string","Help":"","Required":false},{"Name":"actor","Field":"actor","Type":"string","Help":"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.","Required":false},{"Name":"application","Field":"application","Type":"string","Help":"","Required":false},{"Name":"code","Field":"code","Type":"string","Help":"","Required":false},{"Name":"code-challenge","Field":"codeChallenge","Type":"string","Help":"","Required":false},{"Name":"code-challenge-method","Field":"codeChallengeMethod","Type":"string","Help":"","Required":false},{"Name":"code-expire-in","Field":"codeExpireIn","Type":"integer","Help":"","Required":false},{"Name":"code-is-used","Field":"codeIsUsed","Type":"boolean","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"deleted","Field":"deleted","Type":"boolean","Help":"","Required":false},{"Name":"expires-in","Field":"expiresIn","Type":"integer","Help":"","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"Persisted fields","Required":false},{"Name":"nonce","Field":"nonce","Type":"string","Help":"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.","Required":false},{"Name":"organization","Field":"organization","Type":"string","Help":"","Required":false},{"Name":"public-grant","Field":"publicGrant","Type":"boolean","Help":"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.","Required":false},{"Name":"reason","Field":"reason","Type":"string","Help":"","Required":false},{"Name":"redirect-uri","Field":"redirectUri","Type":"string","Help":"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.","Required":false},{"Name":"refresh-consumed","Field":"refreshConsumed","Type":"boolean","Help":"","Required":false},{"Name":"refresh-expire-in","Field":"refreshExpireIn","Type":"integer","Help":"","Required":false},{"Name":"refresh-family","Field":"refreshFamily","Type":"string","Help":"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.","Required":false},{"Name":"refresh-token","Field":"refreshToken","Type":"string","Help":"","Required":false},{"Name":"refresh-token-hash","Field":"refreshTokenHash","Type":"string","Help":"","Required":false},{"Name":"resource","Field":"resource","Type":"string","Help":"RFC 8707 resource indicator","Required":false},{"Name":"scope","Field":"scope","Type":"string","Help":"","Required":false},{"Name":"token-type","Field":"tokenType","Type":"string","Help":"","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"string","Help":"","Required":false},{"Name":"user","Field":"user","Type":"string","Help":"","Required":false},{"Name":"user-code","Field":"userCode","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"update-webauthn-credential","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.","Method":"PUT","Path":"/v1/iam/webauthn-credentials/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":[{"Name":"aaguid","Field":"aaguid","Type":"string","Help":"","Required":false},{"Name":"attachment","Field":"attachment","Type":"string","Help":"","Required":false},{"Name":"attestation-format","Field":"attestationFormat","Type":"string","Help":"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.","Required":false},{"Name":"attestation-type","Field":"attestationType","Type":"string","Help":"","Required":false},{"Name":"backup-eligible","Field":"backupEligible","Type":"boolean","Help":"","Required":false},{"Name":"backup-state","Field":"backupState","Type":"boolean","Help":"","Required":false},{"Name":"clone-warning","Field":"cloneWarning","Type":"boolean","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"credential-id","Field":"credentialId","Type":"string","Help":"","Required":false},{"Name":"deleted","Field":"deleted","Type":"boolean","Help":"","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"Persisted fields","Required":false},{"Name":"public-key","Field":"publicKey","Type":"string","Help":"","Required":false},{"Name":"sign-count","Field":"signCount","Type":"integer","Help":"","Required":false},{"Name":"transport","Field":"transport","Type":"json","Help":"","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"string","Help":"","Required":false},{"Name":"user","Field":"user","Type":"string","Help":"","Required":false},{"Name":"user-present","Field":"userPresent","Type":"boolean","Help":"","Required":false},{"Name":"user-verified","Field":"userVerified","Type":"boolean","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"upsert-application","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.","Method":"POST","Path":"/v1/iam/admin/applications/upsert","Args":[],"Flags":[{"Name":"cert","Field":"cert","Type":"string","Help":"","Required":false},{"Name":"client-id","Field":"clientId","Type":"string","Help":"","Required":false},{"Name":"client-secret","Field":"clientSecret","Type":"string","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"enable-code-signin","Field":"enableCodeSignin","Type":"boolean","Help":"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.","Required":false},{"Name":"expire-in-hours","Field":"expireInHours","Type":"number","Help":"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\".","Required":false},{"Name":"grant-types","Field":"grantTypes","Type":"json","Help":"","Required":false},{"Name":"is-shared","Field":"isShared","Type":"boolean","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"organization","Field":"organization","Type":"string","Help":"","Required":false},{"Name":"public","Field":"public","Type":"boolean","Help":"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.","Required":false},{"Name":"redirect-uris","Field":"redirectUris","Type":"json","Help":"","Required":false},{"Name":"refresh-expire-in-hours","Field":"refreshExpireInHours","Type":"number","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"upsert-user","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.","Method":"POST","Path":"/v1/iam/admin/users/upsert","Args":[],"Flags":[{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"email","Field":"email","Type":"string","Help":"","Required":false},{"Name":"is-admin","Field":"isAdmin","Type":"boolean","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false},{"Name":"password","Field":"password","Type":"string","Help":"","Required":false},{"Name":"password-type","Field":"passwordType","Type":"string","Help":"","Required":false},{"Name":"phone","Field":"phone","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"users-create","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.","Method":"POST","Path":"/v1/iam/users","Args":[],"Flags":[{"Name":"password","Field":"password","Type":"string","Help":"","Required":false},{"Name":"user","Field":"user","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"users-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.","Method":"DELETE","Path":"/v1/iam/users/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"users-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.","Method":"GET","Path":"/v1/iam/users/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":[{"Name":"email","Field":"email","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"users-keys","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.","Method":"POST","Path":"/v1/iam/users/:owner/:name/keys","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"users-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.","Method":"DELETE","Path":"/v1/iam/users/:owner/:name/keys","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"users-list","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.","Method":"GET","Path":"/v1/iam/users","Args":[],"Flags":[{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false},{"Name":"email","Field":"email","Type":"string","Help":"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.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"users-update","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.","Method":"PUT","Path":"/v1/iam/users/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":[{"Name":"password","Field":"password","Type":"string","Help":"","Required":false},{"Name":"user","Field":"user","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"verification-codes-create","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.","Method":"POST","Path":"/v1/iam/verification-codes","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"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.","Method":"GET","Path":"/v1/iam/web3/nonce","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"web3-verify-create","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.","Method":"POST","Path":"/v1/iam/web3/verify","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"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.","Method":"GET","Path":"/v1/iam/webauthn/signin/begin","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"webauthn-signin-finish-create","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.","Method":"POST","Path":"/v1/iam/webauthn/signin/finish","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"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.","Method":"GET","Path":"/v1/iam/webauthn/signup/begin","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"webauthn-signup-finish-create","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.","Method":"POST","Path":"/v1/iam/webauthn/signup/finish","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"well-known-jwks-list","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.","Method":"GET","Path":"/v1/iam/.well-known/jwks","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"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.","Method":"GET","Path":"/v1/iam/.well-known/oauth-authorization-server","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"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.","Method":"GET","Path":"/v1/iam/.well-known/openid-configuration","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"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.","Method":"GET","Path":"/v1/iam/whoami","Args":[],"Flags":null,"Example":null},{"Service":"iam","Name":"workspaces-create","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.","Method":"POST","Path":"/v1/iam/workspaces","Args":[],"Flags":[{"Name":"bucket","Field":"bucket","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"is-default","Field":"isDefault","Type":"boolean","Help":"","Required":false},{"Name":"metadata","Field":"metadata","Type":"string","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"organization","Field":"organization","Type":"string","Help":"","Required":false},{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"workspaces-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.","Method":"DELETE","Path":"/v1/iam/workspaces/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"workspaces-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.","Method":"GET","Path":"/v1/iam/workspaces/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"iam","Name":"workspaces-list","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.","Method":"GET","Path":"/v1/iam/workspaces","Args":[],"Flags":[{"Name":"owner","Field":"owner","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"iam","Name":"workspaces-update","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.","Method":"PUT","Path":"/v1/iam/workspaces/:owner/:name","Args":[{"Name":"owner","Help":""},{"Name":"name","Help":""}],"Flags":[{"Name":"bucket","Field":"bucket","Type":"string","Help":"","Required":false},{"Name":"created-time","Field":"createdTime","Type":"string","Help":"","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"","Required":false},{"Name":"is-default","Field":"isDefault","Type":"boolean","Help":"","Required":false},{"Name":"metadata","Field":"metadata","Type":"string","Help":"","Required":false},{"Name":"organization","Field":"organization","Type":"string","Help":"","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"images","Name":"generations-create","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.","Method":"POST","Path":"/v1/images/generations","Args":[],"Flags":null,"Example":null},{"Service":"index","Name":"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.","Method":"GET","Path":"/v1/index/health","Args":[],"Flags":null,"Example":null},{"Service":"index","Name":"indexes-create","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.","Method":"POST","Path":"/v1/index/indexes","Args":[],"Flags":[{"Name":"primary-key","Field":"primaryKey","Type":"string","Help":"PrimaryKey is the document field that identifies a row. Optional — the\nfirst write establishes one when it is omitted.","Required":false},{"Name":"uid","Field":"uid","Type":"string","Help":"UID is the index's name within the org. Required.","Required":false}],"Example":{"primaryKey":"id","uid":"messages"}},{"Service":"index","Name":"indexes-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.","Method":"DELETE","Path":"/v1/index/indexes/:uid","Args":[{"Name":"uid","Help":""}],"Flags":null,"Example":null},{"Service":"index","Name":"indexes-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.","Method":"DELETE","Path":"/v1/index/indexes/:uid/documents/:id","Args":[{"Name":"uid","Help":""},{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"index","Name":"indexes-documents","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.","Method":"POST","Path":"/v1/index/indexes/:uid/documents","Args":[{"Name":"uid","Help":""}],"Flags":null,"Example":null},{"Service":"index","Name":"indexes-documents-delete-batch","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.","Method":"POST","Path":"/v1/index/indexes/:uid/documents/delete-batch","Args":[{"Name":"uid","Help":""}],"Flags":null,"Example":null},{"Service":"index","Name":"indexes-documents-list","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`.","Method":"GET","Path":"/v1/index/indexes/:uid/documents","Args":[{"Name":"uid","Help":""}],"Flags":[{"Name":"limit","Field":"limit","Type":"string","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"index","Name":"indexes-documents-update","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.","Method":"PUT","Path":"/v1/index/indexes/:uid/documents","Args":[{"Name":"uid","Help":""}],"Flags":null,"Example":null},{"Service":"index","Name":"indexes-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.","Method":"GET","Path":"/v1/index/indexes/:uid","Args":[{"Name":"uid","Help":""}],"Flags":null,"Example":null},{"Service":"index","Name":"indexes-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.","Method":"GET","Path":"/v1/index/indexes/:uid/documents/:id","Args":[{"Name":"uid","Help":""},{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"index","Name":"indexes-list","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.","Method":"GET","Path":"/v1/index/indexes","Args":[],"Flags":null,"Example":null},{"Service":"index","Name":"indexes-search","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`.","Method":"POST","Path":"/v1/index/indexes/:uid/search","Args":[{"Name":"uid","Help":""}],"Flags":[{"Name":"filter","Field":"filter","Type":"json","Help":"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.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit is how many hits to return. Absent means 20; the ceiling is 1000.","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset is where to start. Absent means 0.","Required":false},{"Name":"q","Field":"q","Type":"string","Help":"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.","Required":false}],"Example":{"filter":"user = alice","limit":20,"q":"roadmap"}},{"Service":"index","Name":"indexes-settings-list","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`.","Method":"GET","Path":"/v1/index/indexes/:uid/settings","Args":[{"Name":"uid","Help":""}],"Flags":null,"Example":null},{"Service":"index","Name":"indexes-settings-update","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.","Method":"PATCH","Path":"/v1/index/indexes/:uid/settings","Args":[{"Name":"uid","Help":""}],"Flags":[{"Name":"filterable-attributes","Field":"filterableAttributes","Type":"json","Help":"FilterableAttributes replaces the whole filterable set. Omitted leaves it\nunchanged; an empty array clears it.","Required":false}],"Example":{"filterableAttributes":["user","conversationId"]}},{"Service":"index","Name":"stats-list","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.","Method":"GET","Path":"/v1/index/stats","Args":[],"Flags":null,"Example":null},{"Service":"index","Name":"tasks-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.","Method":"GET","Path":"/v1/index/tasks/:uid","Args":[{"Name":"uid","Help":""}],"Flags":null,"Example":null},{"Service":"index","Name":"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.","Method":"GET","Path":"/v1/index/version","Args":[],"Flags":null,"Example":null},{"Service":"ingress","Name":"middlewares-create","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.","Method":"POST","Path":"/v1/ingress/middlewares","Args":[],"Flags":[{"Name":"config","Field":"config","Type":"json","Help":"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.","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"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.","Required":false},{"Name":"type","Field":"type","Type":"string","Help":"Type is the transform: redirectScheme, stripPrefix, addPrefix or headers.","Required":false}],"Example":{"config":{"prefixes":"/api"},"id":"strip-api","type":"stripPrefix"}},{"Service":"ingress","Name":"middlewares-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.","Method":"DELETE","Path":"/v1/ingress/middlewares/:id","Args":[{"Name":"id","Help":"ID is the object to act on, from the path."}],"Flags":null,"Example":{"id":"strip-api"}},{"Service":"ingress","Name":"middlewares-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.","Method":"GET","Path":"/v1/ingress/middlewares/:id","Args":[{"Name":"id","Help":"ID is the object to act on, from the path."}],"Flags":null,"Example":{"id":"strip-api"}},{"Service":"ingress","Name":"middlewares-list","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.","Method":"GET","Path":"/v1/ingress/middlewares","Args":[],"Flags":null,"Example":null},{"Service":"ingress","Name":"middlewares-update","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.","Method":"PUT","Path":"/v1/ingress/middlewares/:id","Args":[{"Name":"id","Help":"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."}],"Flags":[{"Name":"config","Field":"config","Type":"json","Help":"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.","Required":false},{"Name":"type","Field":"type","Type":"string","Help":"Type is the transform: redirectScheme, stripPrefix, addPrefix or headers.","Required":false}],"Example":{"config":{"prefixes":"/api"},"id":"strip-api","type":"stripPrefix"}},{"Service":"ingress","Name":"routes-create","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.","Method":"POST","Path":"/v1/ingress/routes","Args":[],"Flags":[{"Name":"host","Field":"host","Type":"string","Help":"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.","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"ID identifies the route within the org: [A-Za-z0-9-_.], at most 128 chars.\nA create that omits it gets a generated one.","Required":false},{"Name":"middlewares","Field":"middlewares","Type":"json","Help":"Middlewares are the ids of the edge transforms to apply, in this order,\nbefore the request reaches the service. At most 16.","Required":false},{"Name":"path-prefix","Field":"pathPrefix","Type":"string","Help":"PathPrefix narrows the match to requests under this path; it must start\nwith \"/\". Empty matches every path on the host.","Required":false},{"Name":"priority","Field":"priority","Type":"integer","Help":"Priority orders routes that share a host: higher wins, and equal priorities\nfall back to the longer PathPrefix.","Required":false},{"Name":"service","Field":"service","Type":"string","Help":"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.","Required":false},{"Name":"tls","Field":"tls","Type":"boolean","Help":"TLS asks the edge to terminate TLS for Host with an ACME-managed certificate.","Required":false}],"Example":{"host":"app.example.com","id":"web","service":"app-pool","tls":true}},{"Service":"ingress","Name":"routes-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.","Method":"DELETE","Path":"/v1/ingress/routes/:id","Args":[{"Name":"id","Help":"ID is the object to act on, from the path."}],"Flags":null,"Example":{"id":"web"}},{"Service":"ingress","Name":"routes-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.","Method":"GET","Path":"/v1/ingress/routes/:id","Args":[{"Name":"id","Help":"ID is the object to act on, from the path."}],"Flags":null,"Example":{"id":"a1b2c3d4e5f60718"}},{"Service":"ingress","Name":"routes-list","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.","Method":"GET","Path":"/v1/ingress/routes","Args":[],"Flags":null,"Example":null},{"Service":"ingress","Name":"routes-update","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.","Method":"PUT","Path":"/v1/ingress/routes/:id","Args":[{"Name":"id","Help":"ID identifies the route within the org: [A-Za-z0-9-_.], at most 128 chars.\nA create that omits it gets a generated one."}],"Flags":[{"Name":"host","Field":"host","Type":"string","Help":"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.","Required":false},{"Name":"middlewares","Field":"middlewares","Type":"json","Help":"Middlewares are the ids of the edge transforms to apply, in this order,\nbefore the request reaches the service. At most 16.","Required":false},{"Name":"path-prefix","Field":"pathPrefix","Type":"string","Help":"PathPrefix narrows the match to requests under this path; it must start\nwith \"/\". Empty matches every path on the host.","Required":false},{"Name":"priority","Field":"priority","Type":"integer","Help":"Priority orders routes that share a host: higher wins, and equal priorities\nfall back to the longer PathPrefix.","Required":false},{"Name":"service","Field":"service","Type":"string","Help":"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.","Required":false},{"Name":"tls","Field":"tls","Type":"boolean","Help":"TLS asks the edge to terminate TLS for Host with an ACME-managed certificate.","Required":false}],"Example":{"host":"app.example.com","id":"web","service":"app-pool","tls":true}},{"Service":"ingress","Name":"services-create","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].","Method":"POST","Path":"/v1/ingress/services","Args":[],"Flags":[{"Name":"backends","Field":"backends","Type":"json","Help":"Backends are the upstream servers to balance across: 1..32 of them.","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"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.","Required":false},{"Name":"pass-host-header","Field":"passHostHeader","Type":"boolean","Help":"PassHostHeader forwards the client's original Host header upstream instead\nof rewriting it to the backend's.","Required":false}],"Example":{"backends":[{"url":"http://10.0.0.7:8000","weight":1}],"id":"app-pool"}},{"Service":"ingress","Name":"services-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.","Method":"DELETE","Path":"/v1/ingress/services/:id","Args":[{"Name":"id","Help":"ID is the object to act on, from the path."}],"Flags":null,"Example":{"id":"app-pool"}},{"Service":"ingress","Name":"services-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.","Method":"GET","Path":"/v1/ingress/services/:id","Args":[{"Name":"id","Help":"ID is the object to act on, from the path."}],"Flags":null,"Example":{"id":"app-pool"}},{"Service":"ingress","Name":"services-list","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.","Method":"GET","Path":"/v1/ingress/services","Args":[],"Flags":null,"Example":null},{"Service":"ingress","Name":"services-update","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].","Method":"PUT","Path":"/v1/ingress/services/:id","Args":[{"Name":"id","Help":"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."}],"Flags":[{"Name":"backends","Field":"backends","Type":"json","Help":"Backends are the upstream servers to balance across: 1..32 of them.","Required":false},{"Name":"pass-host-header","Field":"passHostHeader","Type":"boolean","Help":"PassHostHeader forwards the client's original Host header upstream instead\nof rewriting it to the backend's.","Required":false}],"Example":{"backends":[{"url":"http://10.0.0.7:8000","weight":1}],"id":"app-pool"}},{"Service":"ingress","Name":"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.","Method":"GET","Path":"/v1/ingress/status","Args":[],"Flags":null,"Example":null},{"Service":"ingress","Name":"tls-list","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.","Method":"GET","Path":"/v1/ingress/tls","Args":[],"Flags":null,"Example":null},{"Service":"ingress","Name":"tls-update","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.","Method":"PUT","Path":"/v1/ingress/tls","Args":[],"Flags":[{"Name":"acme-email","Field":"acmeEmail","Type":"string","Help":"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.","Required":false},{"Name":"extra-hosts","Field":"extraHosts","Type":"json","Help":"ExtraHosts get certificates without owning a route — at most 256. They feed\nthe ACME HostPolicy and hot-apply on the next reload.","Required":false},{"Name":"staging","Field":"staging","Type":"boolean","Help":"Staging issues from Let's Encrypt's staging directory (untrusted certs, high\nrate limits). Like ACMEEmail it applies only when the edge (re)starts.","Required":false}],"Example":{"extraHosts":["www.example.com"]}},{"Service":"kms","Name":"auth-login-create","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.","Method":"POST","Path":"/v1/kms/auth/login","Args":[],"Flags":[{"Name":"client-id","Field":"clientId","Type":"string","Help":"ClientID is the machine identity's id, as IAM issued it.","Required":false},{"Name":"client-secret","Field":"clientSecret","Type":"string","Help":"ClientSecret is that identity's secret. It is never logged, never echoed,\nand never carried in an error.","Required":false}],"Example":{"clientId":"kms-operator","clientSecret":"…"}},{"Service":"kms","Name":"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.","Method":"GET","Path":"/v1/kms/config","Args":[],"Flags":null,"Example":null},{"Service":"kms","Name":"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.","Method":"GET","Path":"/v1/kms/health","Args":[],"Flags":null,"Example":null},{"Service":"kms","Name":"secrets-create","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.","Method":"POST","Path":"/v1/kms/secrets","Args":[],"Flags":[{"Name":"env","Field":"env","Type":"string","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the secret's name. Required.","Required":false},{"Name":"path","Field":"path","Type":"string","Help":"Path is an optional subpath beneath the org root, e.g. \"/ci\".","Required":false},{"Name":"value","Field":"value","Type":"string","Help":"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.","Required":false}],"Example":{"env":"prod","name":"deploy-token","path":"/ci","value":"s3cr3t"}},{"Service":"kms","Name":"secrets-list","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.","Method":"GET","Path":"/v1/kms/secrets","Args":[],"Flags":[{"Name":"env","Field":"env","Type":"string","Help":"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.","Required":false},{"Name":"environment","Field":"environment","Type":"string","Help":"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.","Required":false},{"Name":"path","Field":"path","Type":"string","Help":"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.","Required":false},{"Name":"secret-path","Field":"secretPath","Type":"string","Help":"SecretPath is the KMS operator's spelling of Path. Path wins when both are\nsent.","Required":false}],"Example":null},{"Service":"knowledge","Name":"connectors-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.","Method":"GET","Path":"/v1/knowledge/connectors/:provider/callback","Args":[{"Name":"provider","Help":"Provider is the connector completing its flow, from the path."}],"Flags":[{"Name":"code","Field":"code","Type":"string","Help":"Code is the provider's authorization code, exchanged for a token.","Required":false},{"Name":"state","Field":"state","Type":"string","Help":"State is the org-bound value this server signed at connect time.","Required":false},{"Name":"error","Field":"error","Type":"string","Help":"Error is the provider's denial reason when the user refused consent.","Required":false}],"Example":null},{"Service":"knowledge","Name":"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.","Method":"GET","Path":"/v1/knowledge/connectors/catalog","Args":[],"Flags":null,"Example":null},{"Service":"knowledge","Name":"connectors-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.","Method":"GET","Path":"/v1/knowledge/connectors/:provider/connect","Args":[{"Name":"provider","Help":"Provider is the connector to act on: github, slack, google or notion."}],"Flags":null,"Example":null},{"Service":"knowledge","Name":"connectors-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.","Method":"DELETE","Path":"/v1/knowledge/connectors/:provider","Args":[{"Name":"provider","Help":"Provider is the connector to act on: github, slack, google or notion."}],"Flags":null,"Example":null},{"Service":"knowledge","Name":"connectors-list","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.","Method":"GET","Path":"/v1/knowledge/connectors","Args":[],"Flags":null,"Example":null},{"Service":"knowledge","Name":"connectors-sync","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.","Method":"POST","Path":"/v1/knowledge/connectors/:provider/sync","Args":[{"Name":"provider","Help":"Provider is the connector to act on: github, slack, google or notion."}],"Flags":null,"Example":null},{"Service":"knowledge","Name":"files-create","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.","Method":"POST","Path":"/v1/knowledge/files","Args":[],"Flags":[{"Name":"bucket","Field":"bucket","Type":"string","Help":"Bucket is one of the org's buckets, by the friendly name /v1/s3/buckets\nlists. Required.","Required":false},{"Name":"key","Field":"key","Type":"string","Help":"Key is the object's key in that bucket, as the upload wrote it. Required.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project indexes the file under one project scope. Empty is the org's own.","Required":false}],"Example":{"bucket":"hanzo","key":"chat/report.pdf"}},{"Service":"knowledge","Name":"files-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.","Method":"DELETE","Path":"/v1/knowledge/files/:id","Args":[{"Name":"id","Help":"ID is the file's id, as POST /v1/knowledge/files answered it."}],"Flags":null,"Example":null},{"Service":"knowledge","Name":"files-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.","Method":"GET","Path":"/v1/knowledge/files/:id","Args":[{"Name":"id","Help":"ID is the file's id, as POST /v1/knowledge/files answered it."}],"Flags":null,"Example":null},{"Service":"knowledge","Name":"files-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.","Method":"GET","Path":"/v1/knowledge/files/:id/sections/:section","Args":[{"Name":"id","Help":"ID is the file's id."},{"Name":"section","Help":"Section is the section's number in the file's table of contents."}],"Flags":null,"Example":null},{"Service":"knowledge","Name":"files-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.","Method":"GET","Path":"/v1/knowledge/files/:id/graph","Args":[{"Name":"id","Help":"ID is the file's id, as POST /v1/knowledge/files answered it."}],"Flags":null,"Example":null},{"Service":"knowledge","Name":"files-list","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.","Method":"GET","Path":"/v1/knowledge/files","Args":[],"Flags":[{"Name":"bucket","Field":"bucket","Type":"string","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"knowledge","Name":"files-retrieve-create","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.","Method":"POST","Path":"/v1/knowledge/files/retrieve","Args":[],"Flags":[{"Name":"files","Field":"files","Type":"json","Help":"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.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit bounds the passages drilled out of the chosen sections. Default 8,\nmaximum 24. The graph adds up to four more.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project restricts retrieval to files indexed under one project scope.","Required":false},{"Name":"query","Field":"query","Type":"string","Help":"Query is the question to answer. Required.","Required":false}],"Example":{"files":["f3a9c0d1e2b4f5a6b7c8"],"query":"how long are backups retained, and who audits that?"}},{"Service":"knowledge","Name":"files-search-create","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.","Method":"POST","Path":"/v1/knowledge/files/search","Args":[],"Flags":[{"Name":"files","Field":"files","Type":"json","Help":"Files restricts the search to these file ids. Empty searches every file\nthe org holds.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit bounds the passages returned. Default 8, maximum 50.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project restricts the search to files indexed under one project scope.","Required":false},{"Name":"query","Field":"query","Type":"string","Help":"Query is the question or phrase. Required.","Required":false}],"Example":{"limit":5,"query":"termination notice period"}},{"Service":"knowledge","Name":"files-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}.","Method":"GET","Path":"/v1/knowledge/files/:id/toc","Args":[{"Name":"id","Help":"ID is the file's id, as POST /v1/knowledge/files answered it."}],"Flags":null,"Example":null},{"Service":"knowledge","Name":"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.","Method":"GET","Path":"/v1/knowledge/graph","Args":[],"Flags":[{"Name":"project","Field":"project","Type":"string","Help":"Project narrows the graph to one project scope. Empty reads the whole org.","Required":false}],"Example":null},{"Service":"knowledge","Name":"import-create","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.","Method":"POST","Path":"/v1/knowledge/import","Args":[],"Flags":null,"Example":null},{"Service":"knowledge","Name":"reindex-create","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}","Method":"POST","Path":"/v1/knowledge/reindex","Args":[],"Flags":null,"Example":null},{"Service":"knowledge","Name":"search-create","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.","Method":"POST","Path":"/v1/knowledge/search","Args":[],"Flags":[{"Name":"doctypes","Field":"doctypes","Type":"json","Help":"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.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit bounds the hits returned. Default 10, maximum 50.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project narrows retrieval to one project scope.","Required":false},{"Name":"query","Field":"query","Type":"string","Help":"Query is the natural-language question. Required.","Required":false}],"Example":{"limit":5,"query":"how do we rotate the signing key"}},{"Service":"kv","Name":"create","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.","Method":"POST","Path":"/v1/kv/:bucket","Args":[{"Name":"bucket","Help":"Bucket is the bucket's name within the org, from the path: 1–64 of\n[A-Za-z0-9_], no dash."}],"Flags":[{"Name":"history","Field":"history","Type":"integer","Help":"History is how many revisions each key keeps, 1–64. 0 means 1.","Required":false},{"Name":"max-value","Field":"maxValue","Type":"integer","Help":"MaxValue caps one value's size in bytes. 0 or less means the server's\nceiling.","Required":false},{"Name":"ttl","Field":"ttl","Type":"integer","Help":"TTL expires entries after this many SECONDS. 0 means no expiry.","Required":false}],"Example":{"history":5,"ttl":3600}},{"Service":"kv","Name":"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.","Method":"DELETE","Path":"/v1/kv/:bucket","Args":[{"Name":"bucket","Help":"Bucket is the bucket's name, from the path."}],"Flags":null,"Example":null},{"Service":"kv","Name":"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.","Method":"DELETE","Path":"/v1/kv/:bucket/:key","Args":[{"Name":"bucket","Help":"Bucket is the bucket, from the path."},{"Name":"key","Help":"Key is the key, from the path."}],"Flags":null,"Example":null},{"Service":"kv","Name":"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.","Method":"GET","Path":"/v1/kv/:bucket/:key","Args":[{"Name":"bucket","Help":"Bucket is the bucket, from the path."},{"Name":"key","Help":"Key is the key, from the path."}],"Flags":null,"Example":null},{"Service":"kv","Name":"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.","Method":"GET","Path":"/v1/kv/:bucket/:key/history","Args":[{"Name":"bucket","Help":"Bucket is the bucket, from the path."},{"Name":"key","Help":"Key is the key, from the path."}],"Flags":null,"Example":null},{"Service":"kv","Name":"update","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.","Method":"PUT","Path":"/v1/kv/:bucket/:key","Args":[{"Name":"bucket","Help":"Bucket is the bucket, from the path."},{"Name":"key","Help":"Key is the key, from the path."}],"Flags":[{"Name":"value","Field":"value","Type":"string","Help":"Value is the value, carried verbatim as UTF-8 text (typically JSON).","Required":false}],"Example":{"value":"{\"theme\":\"dark\"}"}},{"Service":"label","Name":"risk-dispose-labels","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.","Method":"POST","Path":"/v1/label/dispose","Args":[],"Flags":[{"Name":"before","Field":"before","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"label","Name":"risk-hold-labels","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.","Method":"POST","Path":"/v1/label/hold","Args":[],"Flags":[{"Name":"hold","Field":"hold","Type":"boolean","Help":"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.","Required":false},{"Name":"ids","Field":"ids","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"label","Name":"risk-label","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.","Method":"POST","Path":"/v1/label","Args":[],"Flags":[{"Name":"labels","Field":"labels","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"label","Name":"risk-label-coverage","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.","Method":"GET","Path":"/v1/label/coverage","Args":[],"Flags":[{"Name":"from","Field":"from","Type":"string","Help":"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.","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"","Required":false},{"Name":"horizon","Field":"horizon","Type":"integer","Help":"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.","Required":false}],"Example":null},{"Service":"label","Name":"risk-label-vocabulary","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.","Method":"GET","Path":"/v1/label/vocabulary","Args":[],"Flags":null,"Example":null},{"Service":"label","Name":"risk-labels","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.","Method":"GET","Path":"/v1/label","Args":[],"Flags":[{"Name":"kind","Field":"kind","Type":"string","Help":"Kind and Subject narrow to one entity.","Required":false},{"Name":"subject","Field":"subject","Type":"string","Help":"","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source narrows to one asserter — the read that answers \"what has commerce\ntold us\", separately from \"what has an analyst told us\".","Required":false},{"Name":"from","Field":"from","Type":"string","Help":"From and To bound the EVENT time, half-open, RFC 3339.","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the page. Out of range takes the plane's own bound.","Required":false}],"Example":null},{"Service":"label","Name":"risk-resolve-labels","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.","Method":"POST","Path":"/v1/label/resolve","Args":[],"Flags":[{"Name":"horizon","Field":"horizon","Type":"integer","Help":"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.","Required":false},{"Name":"now","Field":"now","Type":"string","Help":"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.","Required":false},{"Name":"subjects","Field":"subjects","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"leaderboard","Name":"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.","Method":"GET","Path":"/v1/leaderboard/activity","Args":[],"Flags":[{"Name":"subject","Field":"subject","Type":"string","Help":"Subject is what the series is about: \"user\" (default), \"org\" or \"project\".","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"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.","Required":false},{"Name":"from","Field":"from","Type":"string","Help":"From is the first day of the range, \"2006-01-02\". Defaults to 90 days back.","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"To is the last day of the range, \"2006-01-02\". Defaults to today; the span is\nclamped to 366 days.","Required":false}],"Example":{"from":"2026-01-01","subject":"user","to":"2026-03-31"}},{"Service":"leaderboard","Name":"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.","Method":"GET","Path":"/v1/leaderboard/beta","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the rows, clamped to 1..100. Defaults to 25, which is also what a\nnon-positive value takes.","Required":false}],"Example":null},{"Service":"leaderboard","Name":"list","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.","Method":"GET","Path":"/v1/leaderboard","Args":[],"Flags":[{"Name":"scope","Field":"scope","Type":"string","Help":"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.","Required":false},{"Name":"metric","Field":"metric","Type":"string","Help":"Metric is the value ranked: tokens (default), requests, or cost.","Required":false},{"Name":"period","Field":"period","Type":"string","Help":"Period is the window ranked: day, week, month (default) or all.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the rows returned, clamped to 100. Defaults to 10, which is also\nwhat a non-positive or unparseable value takes.","Required":false}],"Example":{"limit":10,"metric":"tokens","period":"week","scope":"personal"}},{"Service":"leaderboard","Name":"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.","Method":"GET","Path":"/v1/leaderboard/optin","Args":[],"Flags":null,"Example":null},{"Service":"leaderboard","Name":"optin-org-update","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.","Method":"PUT","Path":"/v1/leaderboard/optin/org","Args":[],"Flags":[{"Name":"display","Field":"display","Type":"string","Help":"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.","Required":false},{"Name":"listed","Field":"listed","Type":"boolean","Help":"Listed publishes the org on the cross-org global board when true, and withdraws\nit when false.","Required":false}],"Example":{"display":"Acme","listed":true}},{"Service":"leaderboard","Name":"optin-update","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.","Method":"PUT","Path":"/v1/leaderboard/optin","Args":[],"Flags":[{"Name":"handle","Field":"handle","Type":"string","Help":"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.","Required":false},{"Name":"listed","Field":"listed","Type":"boolean","Help":"Listed publishes the caller's row to other viewers of the board when true, and\nanonymizes it when false.","Required":false}],"Example":{"handle":"ada","listed":true}},{"Service":"legal","Name":"documents-create","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.","Method":"POST","Path":"/v1/legal/documents","Args":[],"Flags":[{"Name":"data","Field":"data","Type":"json","Help":"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.","Required":false},{"Name":"template-id","Field":"templateId","Type":"string","Help":"TemplateID is the template to render. Required; resolved for the caller's\norg, so an override wins over the built-in.","Required":false}],"Example":{"data":{"counterparty":"AgentCo, LLC","date":"2026-07-30"},"templateId":"nda"}},{"Service":"legal","Name":"documents-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.","Method":"GET","Path":"/v1/legal/documents/:id","Args":[{"Name":"id","Help":"ID is the document's server-minted handle, \"doc_\"-prefixed."}],"Flags":null,"Example":null},{"Service":"legal","Name":"documents-list","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.","Method":"GET","Path":"/v1/legal/documents","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit bounds the page. Absent or unparseable means the store's own default.","Required":false}],"Example":null},{"Service":"legal","Name":"documents-sign","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.","Method":"POST","Path":"/v1/legal/documents/:id/sign","Args":[{"Name":"id","Help":"ID is the document to send for signature, from the path."}],"Flags":[{"Name":"signers","Field":"signers","Type":"json","Help":"Signers are the people who must sign, by name and email. At least one is\nrequired.","Required":false}],"Example":{"id":"doc_1f…","signers":[{"email":"ada@acme.com","name":"Ada"}]}},{"Service":"legal","Name":"documents-sign-complete","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.","Method":"POST","Path":"/v1/legal/documents/:id/sign/complete","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"legal","Name":"filings-create","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.","Method":"POST","Path":"/v1/legal/filings","Args":[],"Flags":[{"Name":"document-ids","Field":"documentIds","Type":"json","Help":"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.","Required":false},{"Name":"jurisdiction","Field":"jurisdiction","Type":"string","Help":"Jurisdiction is the state or agency the filing is for, e.g. \"DE\".","Required":false}],"Example":{"documentIds":["doc_1f…"],"jurisdiction":"DE"}},{"Service":"legal","Name":"filings-list","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.","Method":"GET","Path":"/v1/legal/filings","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit bounds the page. Absent or unparseable means the store's own default.","Required":false}],"Example":null},{"Service":"legal","Name":"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.","Method":"GET","Path":"/v1/legal/health","Args":[],"Flags":null,"Example":null},{"Service":"legal","Name":"templates-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.","Method":"GET","Path":"/v1/legal/templates/:id","Args":[{"Name":"id","Help":"ID is the template's stable id, e.g. \"nda\" or \"safe\"."}],"Flags":null,"Example":null},{"Service":"legal","Name":"templates-list","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.","Method":"GET","Path":"/v1/legal/templates","Args":[],"Flags":null,"Example":null},{"Service":"legal","Name":"templates-update","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.","Method":"PUT","Path":"/v1/legal/templates/:id","Args":[{"Name":"id","Help":"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."}],"Flags":[{"Name":"body","Field":"body","Type":"string","Help":"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.","Required":false},{"Name":"category","Field":"category","Type":"string","Help":"Category groups the template: formation, equity, ops or sales. Optional when\noverriding a built-in, which supplies its own.","Required":false},{"Name":"counsel-review","Field":"counselReview","Type":"boolean","Help":"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.","Required":false},{"Name":"fields","Field":"fields","Type":"json","Help":"Fields declares the merge fields the body consumes. Every declared field is\nREQUIRED at generation — the engine fails closed on a missing one.","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"Title is the template's display name. Required unless a built-in supplies it.","Required":false}],"Example":{"body":"…{{.counterparty}}…","fields":[{"key":"counterparty","label":"Counterparty"}],"id":"nda","title":"AgentCo Mutual NDA"}},{"Service":"library","Name":"create","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.","Method":"POST","Path":"/v1/library","Args":[],"Flags":[{"Name":"data","Field":"data","Type":"string","Help":"Data is the bytes, base64, at most 10 MiB. Required.","Required":false},{"Name":"height","Field":"height","Type":"integer","Help":"","Required":false},{"Name":"key","Field":"key","Type":"string","Help":"Key makes the save idempotent: the same source and key answer the item\nalready kept.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind is image, video, audio, document, slides, type, model, code or file;\nabsent derives it from mime.","Required":false},{"Name":"mime","Field":"mime","Type":"string","Help":"Mime is its media type. Required.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is what it is called, a file name. Required.","Required":false},{"Name":"origin","Field":"origin","Type":"string","Help":"Origin is the path on this site back to what made it, as /chat?thread=….","Required":false},{"Name":"pages","Field":"pages","Type":"integer","Help":"","Required":false},{"Name":"preview","Field":"preview","Type":"string","Help":"Preview is a still that shows it, base64, at most 2 MiB.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project is one of the organization's projects, by slug.","Required":false},{"Name":"ref","Field":"ref","Type":"string","Help":"Ref is what made it: the conversation, the run.","Required":false},{"Name":"seconds","Field":"seconds","Type":"number","Help":"","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source is the product it came from: chat, dev, studio or workflow. Required.","Required":false},{"Name":"width","Field":"width","Type":"integer","Help":"Width, Height, Seconds and Pages describe it when known.","Required":false}],"Example":{"data":"iVBORw0…","mime":"image/png","name":"poster.png","origin":"/chat?thread=conv_1","ref":"conv_1","source":"chat"}},{"Service":"library","Name":"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.","Method":"DELETE","Path":"/v1/library/:id","Args":[{"Name":"id","Help":"ID is the item, from the path."}],"Flags":null,"Example":{"id":"lib_0f3c…"}},{"Service":"library","Name":"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.","Method":"GET","Path":"/v1/library/:id","Args":[{"Name":"id","Help":"ID is the item, from the path."}],"Flags":null,"Example":{"id":"lib_0f3c…"}},{"Service":"library","Name":"list","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.","Method":"GET","Path":"/v1/library","Args":[],"Flags":[{"Name":"kind","Field":"kind","Type":"string","Help":"Kind keeps one kind: image, video, audio, document, slides, type, model, code or file.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source keeps what one product made: chat, dev, studio or workflow.","Required":false},{"Name":"ref","Field":"ref","Type":"string","Help":"Ref keeps what one conversation, run or Studio run made.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project keeps one project's items.","Required":false},{"Name":"q","Field":"q","Type":"string","Help":"Q keeps the items whose name contains it, ignoring case.","Required":false},{"Name":"since","Field":"since","Type":"string","Help":"Since and Until bound when it was made: RFC 3339, or a date (YYYY-MM-DD).","Required":false},{"Name":"until","Field":"until","Type":"string","Help":"","Required":false},{"Name":"scope","Field":"scope","Type":"string","Help":"Scope is all (yours and what your org shared, the default), mine, or shared.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit bounds the page: default 60, at most 200.","Required":false},{"Name":"cursor","Field":"cursor","Type":"string","Help":"Cursor continues a list from the page before's `next`.","Required":false}],"Example":{"kind":"image","limit":24,"source":"studio"}},{"Service":"library","Name":"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.","Method":"GET","Path":"/v1/library/unowned","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit bounds the page: default 60, at most 200.","Required":false}],"Example":null},{"Service":"library","Name":"update","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.","Method":"PATCH","Path":"/v1/library/:id","Args":[{"Name":"id","Help":"ID is the item, from the path."}],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"Name renames it.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project moves it to one of the organization's projects; \"\" moves it out.","Required":false},{"Name":"shared","Field":"shared","Type":"boolean","Help":"Shared shows it to every member of your organization, or stops.","Required":false}],"Example":{"id":"lib_0f3c…","shared":true}},{"Service":"licensing","Name":"download-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.","Method":"GET","Path":"/v1/licensing/download/:release","Args":[{"Name":"release","Help":""}],"Flags":[{"Name":"token","Field":"token","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"licensing","Name":"fingerprint-create","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.","Method":"POST","Path":"/v1/licensing/fingerprint","Args":[],"Flags":[{"Name":"signals","Field":"signals","Type":"json","Help":"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.","Required":false}],"Example":{"signals":{"arch":"arm64","cpuid":"…","machine_id":"…","os":"linux"}}},{"Service":"licensing","Name":"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.","Method":"GET","Path":"/v1/licensing/healthz","Args":[],"Flags":null,"Example":null},{"Service":"licensing","Name":"issue-create","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.","Method":"POST","Path":"/v1/licensing/issue","Args":[],"Flags":[{"Name":"fingerprint","Field":"fingerprint","Type":"string","Help":"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.","Required":false},{"Name":"holder","Field":"holder","Type":"string","Help":"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.","Required":false},{"Name":"product","Field":"product","Type":"string","Help":"Product is the licensed commerce product the caller wants a token for.","Required":true},{"Name":"release","Field":"release","Type":"string","Help":"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.","Required":false},{"Name":"signals","Field":"signals","Type":"json","Help":"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.","Required":false},{"Name":"ttl-seconds","Field":"ttl_seconds","Type":"integer","Help":"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.","Required":false}],"Example":{"product":"engine","signals":{"machine_id":"…","os":"linux"}}},{"Service":"licensing","Name":"jwks-list","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.","Method":"GET","Path":"/v1/licensing/jwks","Args":[],"Flags":null,"Example":null},{"Service":"licensing","Name":"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.","Method":"GET","Path":"/v1/licensing/pubkey","Args":[],"Flags":null,"Example":null},{"Service":"licensing","Name":"releases-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.","Method":"GET","Path":"/v1/licensing/releases/:release","Args":[{"Name":"release","Help":""}],"Flags":null,"Example":null},{"Service":"licensing","Name":"releases-list","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.","Method":"GET","Path":"/v1/licensing/releases","Args":[],"Flags":null,"Example":null},{"Service":"licensing","Name":"verify-create","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.","Method":"POST","Path":"/v1/licensing/verify","Args":[],"Flags":[{"Name":"app","Field":"app","Type":"string","Help":"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.","Required":false},{"Name":"token","Field":"token","Type":"string","Help":"Token is the license token to check.","Required":true}],"Example":{"token":"eyJ2Ijox….Ab3…"}},{"Service":"link","Name":"create","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.","Method":"POST","Path":"/v1/link","Args":[],"Flags":[{"Name":"account","Field":"account","Type":"string","Help":"Account is the provider-side account identifier.","Required":false},{"Name":"host","Field":"host","Type":"string","Help":"Host is the machine's human hostname label.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"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.","Required":false},{"Name":"machine","Field":"machine","Type":"string","Help":"Machine is the stable machine identifier. Required, length-bounded.","Required":false},{"Name":"os","Field":"os","Type":"string","Help":"OS is the machine's operating system label.","Required":false},{"Name":"plan","Field":"plan","Type":"string","Help":"Plan is the provider plan label (e.g. \"Claude Max\").","Required":false},{"Name":"provider","Field":"provider","Type":"string","Help":"Provider is the AI provider the account belongs to. Required, length-bounded.","Required":false},{"Name":"usage","Field":"usage","Type":"json","Help":"Usage is an optional usage snapshot, clamped and re-serialized to known\nfields; omitting it keeps the last good one.","Required":false}],"Example":null},{"Service":"link","Name":"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.","Method":"DELETE","Path":"/v1/link/:id","Args":[{"Name":"id","Help":"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."}],"Flags":null,"Example":null},{"Service":"link","Name":"devices-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.","Method":"GET","Path":"/v1/link/devices/:machine","Args":[{"Name":"machine","Help":"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."}],"Flags":null,"Example":null},{"Service":"link","Name":"devices-revoke","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.","Method":"POST","Path":"/v1/link/devices/:machine/revoke","Args":[{"Name":"machine","Help":"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."}],"Flags":null,"Example":null},{"Service":"link","Name":"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.","Method":"GET","Path":"/v1/link/:id","Args":[{"Name":"id","Help":"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."}],"Flags":null,"Example":null},{"Service":"link","Name":"list","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.","Method":"GET","Path":"/v1/link","Args":[],"Flags":null,"Example":null},{"Service":"link","Name":"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.","Method":"GET","Path":"/v1/link/route","Args":[],"Flags":null,"Example":null},{"Service":"link","Name":"usage-accounts-list","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.","Method":"GET","Path":"/v1/link/usage/accounts","Args":[],"Flags":null,"Example":null},{"Service":"link","Name":"usage-create","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.","Method":"POST","Path":"/v1/link/usage","Args":[],"Flags":[{"Name":"account","Field":"account","Type":"string","Help":"Account is the provider-side account the sample belongs to.","Required":false},{"Name":"cached-input-tokens","Field":"cachedInputTokens","Type":"integer","Help":"CachedInputTokens is the window's cached-prompt-token count.","Required":false},{"Name":"confidence","Field":"confidence","Type":"string","Help":"Confidence says how real the counters are, as the meter graded itself.","Required":false},{"Name":"cost-cents","Field":"costCents","Type":"integer","Help":"CostCents is the window's spend in cents, as the provider's meter states it.","Required":false},{"Name":"cost-limit-cents","Field":"costLimitCents","Type":"integer","Help":"CostLimitCents is the window's spend cap in cents, when the meter knows one.","Required":false},{"Name":"currency","Field":"currency","Type":"string","Help":"Currency is the ISO currency the cost fields are stated in.","Required":false},{"Name":"input-tokens","Field":"inputTokens","Type":"integer","Help":"InputTokens is the window's prompt-token count.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind is subscription or apikey; anything else is refused.","Required":false},{"Name":"lane","Field":"lane","Type":"string","Help":"Lane names the meter's own lane label for this measurement.","Required":false},{"Name":"machine","Field":"machine","Type":"string","Help":"Machine is the machine the collector observed the account on. Required.","Required":false},{"Name":"output-tokens","Field":"outputTokens","Type":"integer","Help":"OutputTokens is the window's completion-token count.","Required":false},{"Name":"plan","Field":"plan","Type":"string","Help":"Plan is the provider plan label the account is on.","Required":false},{"Name":"provider","Field":"provider","Type":"string","Help":"Provider is the AI provider whose meter reported this sample. Required.","Required":false},{"Name":"requests","Field":"requests","Type":"integer","Help":"Requests is the window's request count.","Required":false},{"Name":"resets-at","Field":"resetsAt","Type":"string","Help":"ResetsAt is when the window resets, RFC 3339, bounded.","Required":false},{"Name":"samples","Field":"samples","Type":"json","Help":"Samples is the batch form, up to 256 samples; leave it empty to send one\nsample inline on the same fields.","Required":false},{"Name":"synthetic","Field":"synthetic","Type":"boolean","Help":"Synthetic marks a sample the collector derived rather than observed.","Required":false},{"Name":"total-tokens","Field":"totalTokens","Type":"integer","Help":"TotalTokens is the window's total token count.","Required":false},{"Name":"used-pct","Field":"usedPct","Type":"number","Help":"UsedPct is how much of the window's allowance is consumed, clamped 0..100.","Required":false},{"Name":"window","Field":"window","Type":"string","Help":"Window is the window class, one of 6h, day, week, month; anything else is\nrefused rather than silently reclassified.","Required":false},{"Name":"window-minutes","Field":"windowMinutes","Type":"integer","Help":"WindowMinutes is the window's length as the meter reported it.","Required":false},{"Name":"window-start","Field":"windowStart","Type":"string","Help":"WindowStart is when the measured window opened, RFC 3339, bounded to a\nsane interval around now.","Required":false}],"Example":null},{"Service":"link","Name":"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.","Method":"GET","Path":"/v1/link/usage","Args":[],"Flags":[{"Name":"provider","Field":"provider","Type":"string","Help":"Provider is the provider whose meter to read. Required.","Required":false},{"Name":"account","Field":"account","Type":"string","Help":"Account narrows to one account when a user has several with the provider.","Required":false},{"Name":"window","Field":"window","Type":"string","Help":"Window selects a window class: 6h, day, week or month. Empty reads all.","Required":false},{"Name":"range","Field":"range","Type":"string","Help":"Range is the period, one of 1h, 24h, 7d or 30d; empty means 24h, and an\nunknown label is 400, never a quiet fallback.","Required":false}],"Example":null},{"Service":"link","Name":"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\".","Method":"GET","Path":"/v1/link/usage/summary","Args":[],"Flags":[{"Name":"range","Field":"range","Type":"string","Help":"Range is the period, one of 1h, 24h, 7d or 30d; empty means 24h, and an\nunknown label is 400, never a silent substitution.","Required":false}],"Example":null},{"Service":"lsp","Name":"complete-create","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.","Method":"POST","Path":"/v1/lsp/complete","Args":[],"Flags":[{"Name":"character","Field":"character","Type":"integer","Help":"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.","Required":false},{"Name":"line","Field":"line","Type":"integer","Help":"Line is 0-based, per the LSP specification.","Required":false},{"Name":"path","Field":"path","Type":"string","Help":"Path is the repo-relative file, e.g. \"apps/lsp/lsp.go\".","Required":false},{"Name":"relation","Field":"relation","Type":"string","Help":"Relation refines locate: definition, reference, type or implementation.\nEmpty means definition. Every other op ignores it.","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"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.","Required":false},{"Name":"rev","Field":"rev","Type":"string","Help":"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.","Required":false}],"Example":{"character":18,"line":120,"path":"apps/lsp/lsp.go","repo":"cloud"}},{"Service":"lsp","Name":"diagnostics-create","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.","Method":"POST","Path":"/v1/lsp/diagnostics","Args":[],"Flags":[{"Name":"character","Field":"character","Type":"integer","Help":"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.","Required":false},{"Name":"line","Field":"line","Type":"integer","Help":"Line is 0-based, per the LSP specification.","Required":false},{"Name":"path","Field":"path","Type":"string","Help":"Path is the repo-relative file, e.g. \"apps/lsp/lsp.go\".","Required":false},{"Name":"relation","Field":"relation","Type":"string","Help":"Relation refines locate: definition, reference, type or implementation.\nEmpty means definition. Every other op ignores it.","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"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.","Required":false},{"Name":"rev","Field":"rev","Type":"string","Help":"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.","Required":false}],"Example":{"path":"apps/lsp/lsp.go","repo":"cloud"}},{"Service":"lsp","Name":"hover-create","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.","Method":"POST","Path":"/v1/lsp/hover","Args":[],"Flags":[{"Name":"character","Field":"character","Type":"integer","Help":"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.","Required":false},{"Name":"line","Field":"line","Type":"integer","Help":"Line is 0-based, per the LSP specification.","Required":false},{"Name":"path","Field":"path","Type":"string","Help":"Path is the repo-relative file, e.g. \"apps/lsp/lsp.go\".","Required":false},{"Name":"relation","Field":"relation","Type":"string","Help":"Relation refines locate: definition, reference, type or implementation.\nEmpty means definition. Every other op ignores it.","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"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.","Required":false},{"Name":"rev","Field":"rev","Type":"string","Help":"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.","Required":false}],"Example":{"character":18,"line":120,"path":"apps/lsp/lsp.go","repo":"cloud"}},{"Service":"lsp","Name":"locate-create","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.","Method":"POST","Path":"/v1/lsp/locate","Args":[],"Flags":[{"Name":"character","Field":"character","Type":"integer","Help":"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.","Required":false},{"Name":"line","Field":"line","Type":"integer","Help":"Line is 0-based, per the LSP specification.","Required":false},{"Name":"path","Field":"path","Type":"string","Help":"Path is the repo-relative file, e.g. \"apps/lsp/lsp.go\".","Required":false},{"Name":"relation","Field":"relation","Type":"string","Help":"Relation refines locate: definition, reference, type or implementation.\nEmpty means definition. Every other op ignores it.","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"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.","Required":false},{"Name":"rev","Field":"rev","Type":"string","Help":"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.","Required":false}],"Example":{"character":18,"line":120,"path":"apps/lsp/lsp.go","relation":"definition","repo":"cloud"}},{"Service":"lsp","Name":"symbols-create","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.","Method":"POST","Path":"/v1/lsp/symbols","Args":[],"Flags":[{"Name":"character","Field":"character","Type":"integer","Help":"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.","Required":false},{"Name":"line","Field":"line","Type":"integer","Help":"Line is 0-based, per the LSP specification.","Required":false},{"Name":"path","Field":"path","Type":"string","Help":"Path is the repo-relative file, e.g. \"apps/lsp/lsp.go\".","Required":false},{"Name":"relation","Field":"relation","Type":"string","Help":"Relation refines locate: definition, reference, type or implementation.\nEmpty means definition. Every other op ignores it.","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"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.","Required":false},{"Name":"rev","Field":"rev","Type":"string","Help":"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.","Required":false}],"Example":{"path":"apps/lsp/lsp.go","repo":"cloud"}},{"Service":"market","Name":"chains-list","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.","Method":"GET","Path":"/v1/market/chains","Args":[],"Flags":null,"Example":null},{"Service":"market","Name":"pools-list","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.","Method":"GET","Path":"/v1/market/pools","Args":[],"Flags":[{"Name":"chain","Field":"chain","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"market","Name":"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.","Method":"GET","Path":"/v1/market/survey","Args":[],"Flags":[{"Name":"chain","Field":"chain","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"market","Name":"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\".","Method":"GET","Path":"/v1/market/token","Args":[],"Flags":[{"Name":"chain","Field":"chain","Type":"string","Help":"","Required":false},{"Name":"at","Field":"at","Type":"string","Help":"At is the token's contract address.","Required":false}],"Example":null},{"Service":"market","Name":"tokens-list","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.","Method":"GET","Path":"/v1/market/tokens","Args":[],"Flags":[{"Name":"chain","Field":"chain","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"marketing","Name":"audiences-create","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.","Method":"POST","Path":"/v1/marketing/audiences","Args":[],"Flags":[{"Name":"created-at","Field":"createdAt","Type":"integer","Help":"CreatedAt is unix seconds when the filter was saved, server-assigned.","Required":false},{"Name":"event","Field":"event","Type":"string","Help":"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.","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"ID is the server-assigned audience id (\"aud_\" + 128 random bits).","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the audience's label. Required, trimmed, capped at 1024 bytes.","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"integer","Help":"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.","Required":false},{"Name":"window-days","Field":"windowDays","Type":"integer","Help":"WindowDays is how far back the event counts, ending now. 0 means 30 and\nnothing above 3650 is honoured. Ignored when Event is empty.","Required":false}],"Example":{"event":"model.invoked","name":"Model users, last 30d","windowDays":30}},{"Service":"marketing","Name":"audiences-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.","Method":"DELETE","Path":"/v1/marketing/audiences/:id","Args":[{"Name":"id","Help":"ID is the audience id from the path, as returned by create."}],"Flags":null,"Example":{"id":"aud_4c1e9b7a2d6f0538e4a7c9b1d3f5027a"}},{"Service":"marketing","Name":"audiences-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.","Method":"GET","Path":"/v1/marketing/audiences/:id","Args":[{"Name":"id","Help":"ID is the audience id from the path, as returned by create."}],"Flags":null,"Example":{"id":"aud_4c1e9b7a2d6f0538e4a7c9b1d3f5027a"}},{"Service":"marketing","Name":"audiences-list","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.","Method":"GET","Path":"/v1/marketing/audiences","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the rows returned; 0 means 200 and nothing above 1000 is honoured.","Required":false}],"Example":{"limit":50}},{"Service":"marketing","Name":"audiences-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.","Method":"GET","Path":"/v1/marketing/audiences/:id/preview","Args":[{"Name":"id","Help":"ID is the audience id from the path, as returned by create."}],"Flags":null,"Example":{"id":"aud_4c1e9b7a2d6f0538e4a7c9b1d3f5027a"}},{"Service":"marketing","Name":"beta-actions-create","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.","Method":"POST","Path":"/v1/marketing/beta/actions","Args":[],"Flags":[{"Name":"action","Field":"action","Type":"string","Help":"Action is star or follow.","Required":false},{"Name":"github","Field":"github","Type":"string","Help":"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.","Required":false},{"Name":"target","Field":"target","Type":"string","Help":"Target is the repository starred (hanzoai/\u003cname\u003e) or the founder's link\nfollowed (antje or zach, then github, linkedin or x: zach/github).","Required":false}],"Example":null},{"Service":"marketing","Name":"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.","Method":"GET","Path":"/v1/marketing/beta","Args":[],"Flags":null,"Example":null},{"Service":"marketing","Name":"beta-invites-create","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.","Method":"POST","Path":"/v1/marketing/beta/invites","Args":[],"Flags":[{"Name":"to","Field":"to","Type":"json","Help":"To is the addresses to invite, at most 50. Each is trimmed and lower-cased;\none named twice is one.","Required":false}],"Example":{"to":["grace@example.com","alan@example.com"]}},{"Service":"marketing","Name":"beta-invites-list","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.","Method":"GET","Path":"/v1/marketing/beta/invites","Args":[],"Flags":null,"Example":null},{"Service":"marketing","Name":"beta-invites-sent-create","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.","Method":"POST","Path":"/v1/marketing/beta/invites/sent","Args":[],"Flags":[{"Name":"failed","Field":"failed","Type":"json","Help":"Failed are the invites that did not go out.","Required":false},{"Name":"ids","Field":"ids","Type":"json","Help":"IDs are the invites sent.","Required":false}],"Example":{"failed":[{"id":"inv_0d9e8c7b6a5f4e3d2c1b0a9f","why":"Gmail refused the recipient"}],"ids":["inv_4f1a9c2e7b3d5a6c8e0f1a2b"]}},{"Service":"marketing","Name":"beta-request-create","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.","Method":"POST","Path":"/v1/marketing/beta/request","Args":[],"Flags":[{"Name":"betas","Field":"betas","Type":"json","Help":"Betas are the ids of the unreleased products to add.","Required":false}],"Example":null},{"Service":"marketing","Name":"beta-update","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.","Method":"PUT","Path":"/v1/marketing/beta","Args":[],"Flags":[{"Name":"answers","Field":"answers","Type":"json","Help":"Answers replace the record's answers.","Required":false},{"Name":"betas","Field":"betas","Type":"json","Help":"Betas replace the ids of the unreleased products the account asked for.","Required":false},{"Name":"lead","Field":"lead","Type":"string","Help":"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.","Required":false},{"Name":"program","Field":"program","Type":"string","Help":"Program is the program applied to: beta, research or partner.","Required":false}],"Example":null},{"Service":"marketing","Name":"calendar-create","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.","Method":"POST","Path":"/v1/marketing/calendar","Args":[],"Flags":[{"Name":"body","Field":"body","Type":"string","Help":"Body is the post text. Required.","Required":false},{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is the target network: x, facebook, instagram, linkedin, tiktok,\nyoutube or threads. Required — a post must name where it goes.","Required":false},{"Name":"created-at","Field":"createdAt","Type":"integer","Help":"CreatedAt is unix seconds when the post was added, server-assigned and\nnever rewritten.","Required":false},{"Name":"error","Field":"error","Type":"string","Help":"Error is the exact reason the last publish attempt failed — the honest\nrecord behind a \"failed\" status, never a faked success.","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"ID is the server-assigned post id (\"cal_\" + 128 random bits).","Required":false},{"Name":"published-at","Field":"publishedAt","Type":"integer","Help":"PublishedAt is when the publish succeeded; 0 until it does.","Required":false},{"Name":"scheduled-at","Field":"scheduledAt","Type":"integer","Help":"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.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status is draft, scheduled, published, failed or canceled. Server-owned.","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"Title is the post's internal label, capped at 1024 bytes.","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"integer","Help":"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.","Required":false}],"Example":{"body":"Hanzo Cloud is live.","channel":"x","scheduledAt":1780000000,"title":"Launch day"}},{"Service":"marketing","Name":"calendar-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.","Method":"DELETE","Path":"/v1/marketing/calendar/:id","Args":[{"Name":"id","Help":"ID is the post id from the path, as returned by create."}],"Flags":null,"Example":{"id":"cal_1d7f3b9e5a2c8046f1b3d5a7c9e02468"}},{"Service":"marketing","Name":"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.","Method":"GET","Path":"/v1/marketing/calendar","Args":[],"Flags":[{"Name":"status","Field":"status","Type":"string","Help":"Status keeps only posts in that state (draft, scheduled, published,\nfailed, canceled). Empty means every post.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the rows returned; 0 means 200 and nothing above 1000 is honoured.","Required":false}],"Example":{"limit":50,"status":"scheduled"}},{"Service":"marketing","Name":"calendar-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.","Method":"GET","Path":"/v1/marketing/calendar/:id","Args":[{"Name":"id","Help":"ID is the post id from the path, as returned by create."}],"Flags":null,"Example":{"id":"cal_1d7f3b9e5a2c8046f1b3d5a7c9e02468"}},{"Service":"marketing","Name":"calendar-update","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.","Method":"PUT","Path":"/v1/marketing/calendar/:id","Args":[{"Name":"id","Help":"ID is the server-assigned post id (\"cal_\" + 128 random bits)."}],"Flags":[{"Name":"body","Field":"body","Type":"string","Help":"Body is the post text. Required.","Required":false},{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is the target network: x, facebook, instagram, linkedin, tiktok,\nyoutube or threads. Required — a post must name where it goes.","Required":false},{"Name":"created-at","Field":"createdAt","Type":"integer","Help":"CreatedAt is unix seconds when the post was added, server-assigned and\nnever rewritten.","Required":false},{"Name":"error","Field":"error","Type":"string","Help":"Error is the exact reason the last publish attempt failed — the honest\nrecord behind a \"failed\" status, never a faked success.","Required":false},{"Name":"published-at","Field":"publishedAt","Type":"integer","Help":"PublishedAt is when the publish succeeded; 0 until it does.","Required":false},{"Name":"scheduled-at","Field":"scheduledAt","Type":"integer","Help":"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.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status is draft, scheduled, published, failed or canceled. Server-owned.","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"Title is the post's internal label, capped at 1024 bytes.","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"integer","Help":"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.","Required":false}],"Example":{"body":"Hanzo Cloud is live — try it free.","channel":"x","scheduledAt":1780003600,"title":"Launch day"}},{"Service":"marketing","Name":"campaigns-create","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.","Method":"POST","Path":"/v1/marketing/campaigns","Args":[],"Flags":[{"Name":"budget","Field":"budget","Type":"integer","Help":"Budget is what the campaign is allowed to cost, in USD cents. A negative\nvalue is clamped to 0; nothing enforces the ceiling here.","Required":false},{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is the delivery surface: email, sms, social, meta, google or\ntiktok. Empty means email.","Required":false},{"Name":"created-at","Field":"createdAt","Type":"integer","Help":"CreatedAt is unix seconds when the campaign was registered. Server-assigned\nand never rewritten — an update leaves it as it was.","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"ID is the server-assigned campaign id (\"camp_\" + 128 random bits).","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the campaign's label. Required, trimmed, capped at 1024 bytes.","Required":false},{"Name":"objective","Field":"objective","Type":"string","Help":"Objective is the free-text goal (\"signups\"), capped at 1024 bytes.","Required":false},{"Name":"scheduled-at","Field":"scheduledAt","Type":"integer","Help":"ScheduledAt is the unix send time; 0 means unscheduled. Setting it on a\ncampaign with no explicit status makes that status \"scheduled\".","Required":false},{"Name":"spend","Field":"spend","Type":"integer","Help":"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.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status is the lifecycle: draft, scheduled, active, paused or completed.\nEmpty means draft.","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"integer","Help":"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.","Required":false}],"Example":{"budget":50000,"channel":"meta","name":"Spring Launch","objective":"signups","scheduledAt":1780000000}},{"Service":"marketing","Name":"campaigns-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.","Method":"DELETE","Path":"/v1/marketing/campaigns/:id","Args":[{"Name":"id","Help":"ID is the campaign id from the path, as returned by create."}],"Flags":null,"Example":{"id":"camp_9f2a1c7d4e8b0a6f3d2c5b1e7a9f4c60"}},{"Service":"marketing","Name":"campaigns-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.","Method":"GET","Path":"/v1/marketing/campaigns/:id","Args":[{"Name":"id","Help":"ID is the campaign id from the path, as returned by create."}],"Flags":null,"Example":{"id":"camp_9f2a1c7d4e8b0a6f3d2c5b1e7a9f4c60"}},{"Service":"marketing","Name":"campaigns-list","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.","Method":"GET","Path":"/v1/marketing/campaigns","Args":[],"Flags":[{"Name":"status","Field":"status","Type":"string","Help":"Status keeps only campaigns in that lifecycle state (draft, scheduled,\nactive, paused, completed). Empty means every campaign.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the rows returned; 0 means 200 and nothing above 1000 is honoured.","Required":false}],"Example":{"limit":25,"status":"active"}},{"Service":"marketing","Name":"campaigns-schedule","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\".","Method":"POST","Path":"/v1/marketing/campaigns/:id/schedule","Args":[{"Name":"id","Help":"ID is the campaign id from the path."}],"Flags":[{"Name":"scheduled-at","Field":"scheduledAt","Type":"integer","Help":"ScheduledAt is the unix send time. 0 clears the schedule.","Required":false}],"Example":{"id":"camp_9f2a1c7d4e8b0a6f3d2c5b1e7a9f4c60","scheduledAt":1780000000}},{"Service":"marketing","Name":"campaigns-update","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.","Method":"PUT","Path":"/v1/marketing/campaigns/:id","Args":[{"Name":"id","Help":"ID is the server-assigned campaign id (\"camp_\" + 128 random bits)."}],"Flags":[{"Name":"budget","Field":"budget","Type":"integer","Help":"Budget is what the campaign is allowed to cost, in USD cents. A negative\nvalue is clamped to 0; nothing enforces the ceiling here.","Required":false},{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is the delivery surface: email, sms, social, meta, google or\ntiktok. Empty means email.","Required":false},{"Name":"created-at","Field":"createdAt","Type":"integer","Help":"CreatedAt is unix seconds when the campaign was registered. Server-assigned\nand never rewritten — an update leaves it as it was.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the campaign's label. Required, trimmed, capped at 1024 bytes.","Required":false},{"Name":"objective","Field":"objective","Type":"string","Help":"Objective is the free-text goal (\"signups\"), capped at 1024 bytes.","Required":false},{"Name":"scheduled-at","Field":"scheduledAt","Type":"integer","Help":"ScheduledAt is the unix send time; 0 means unscheduled. Setting it on a\ncampaign with no explicit status makes that status \"scheduled\".","Required":false},{"Name":"spend","Field":"spend","Type":"integer","Help":"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.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status is the lifecycle: draft, scheduled, active, paused or completed.\nEmpty means draft.","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"integer","Help":"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.","Required":false}],"Example":{"budget":50000,"channel":"meta","name":"Spring Launch","objective":"signups","spend":12500,"status":"active"}},{"Service":"marketing","Name":"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.","Method":"GET","Path":"/v1/marketing/click","Args":[],"Flags":[{"Name":"t","Field":"t","Type":"string","Help":"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.","Required":false}],"Example":{"t":"AQGAgICAAQVoYW56bw…"}},{"Service":"marketing","Name":"leads-create","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.","Method":"POST","Path":"/v1/marketing/leads","Args":[],"Flags":[{"Name":"address","Field":"address","Type":"json","Help":"Address is where an investor lives, or where the entity they invest\nthrough is: street, city and country required, each at most 200 characters.","Required":false},{"Name":"amount","Field":"amount","Type":"json","Help":"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.","Required":false},{"Name":"answers","Field":"answers","Type":"json","Help":"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.","Required":false},{"Name":"campaign","Field":"campaign","Type":"json","Help":"Campaign is the utm_* tags of the link the visit arrived on, recorded on\nthe lead. Optional.","Required":false},{"Name":"company","Field":"company","Type":"string","Help":"Company is the person's company. Optional; clipped at 200 characters.","Required":false},{"Name":"consent","Field":"consent","Type":"boolean","Help":"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.","Required":false},{"Name":"country","Field":"country","Type":"string","Help":"Country is where the person is. Optional; clipped at 200 characters.","Required":false},{"Name":"coupon","Field":"coupon","Type":"string","Help":"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.","Required":false},{"Name":"department","Field":"department","Type":"string","Help":"Department is the opening's department. Read only with Job.","Required":false},{"Name":"email","Field":"email","Type":"string","Help":"Email is where sales replies: the person's work email. Required, and it\nmust look like an address. It is not verified.","Required":false},{"Name":"entity","Field":"entity","Type":"string","Help":"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.","Required":false},{"Name":"job","Field":"job","Type":"string","Help":"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.","Required":false},{"Name":"links","Field":"links","Type":"json","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the person's name. Optional, and clipped at 200 characters, except\nfor an investor, who must give it, in at most 200.","Required":false},{"Name":"need","Field":"need","Type":"string","Help":"Need is what the person wants from sales, in their own words. Optional;\nclipped at 4 KiB.","Required":false},{"Name":"phone","Field":"phone","Type":"string","Help":"Phone is an investor's phone number: 3 to 20 digits, an optional leading +,\nand any spaces, dots, dashes or brackets between them. Optional.","Required":false},{"Name":"program","Field":"program","Type":"string","Help":"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.","Required":false},{"Name":"resume","Field":"resume","Type":"string","Help":"Resume is an https address the applicant gave for their resume. Read only\nwith Job; any other value is recorded as none.","Required":false},{"Name":"resume-file","Field":"resume_file","Type":"string","Help":"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.","Required":false},{"Name":"role","Field":"role","Type":"string","Help":"Role is the person's job title. Optional; clipped at 200 characters.","Required":false},{"Name":"size","Field":"size","Type":"string","Help":"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.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source is the page the form was filed from, such as hanzo.ai/contact-sales.\nOptional; clipped at 200 characters.","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"Title is the investor's title at Entity, as the SAFE's signature block\nnames it. At most 200 characters; read only with Entity.","Required":false},{"Name":"visit","Field":"visit","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"marketing","Name":"leads-esign-create","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.","Method":"POST","Path":"/v1/marketing/leads/esign","Args":[],"Flags":[{"Name":"event","Field":"event","Type":"string","Help":"Event is what happened: DOCUMENT_SIGNED (a recipient signed),\nDOCUMENT_COMPLETED, DOCUMENT_REJECTED or DOCUMENT_CANCELLED. Any other event\nchanges nothing.","Required":false},{"Name":"payload","Field":"payload","Type":"json","Help":"Payload is the document as it stands after the event.","Required":false}],"Example":{"event":"DOCUMENT_SIGNED","payload":{"externalId":"lead_0123456789abcdef01234567","id":42,"recipients":[{"signingOrder":1,"signingStatus":"SIGNED"},{"signingOrder":2,"signingStatus":"NOT_SIGNED"}]}}},{"Service":"marketing","Name":"leads-resume-create","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.","Method":"POST","Path":"/v1/marketing/leads/resume","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"Name is the file's name; its extension must be .pdf, .doc or .docx.","Required":false},{"Name":"size","Field":"size","Type":"integer","Help":"Size is the file's size in bytes, at most 10 MB.","Required":false},{"Name":"type","Field":"type","Type":"string","Help":"Type is the file's content type, which must be that extension's.","Required":false}],"Example":{"name":"ada.pdf","size":120000,"type":"application/pdf"}},{"Service":"marketing","Name":"mail-create","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.","Method":"POST","Path":"/v1/marketing/mail","Args":[],"Flags":[{"Name":"body","Field":"body","Type":"string","Help":"Body is the mail as plain text, at most 20000 characters; a blank line\nseparates paragraphs.","Required":false},{"Name":"person","Field":"person","Type":"string","Help":"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.","Required":false},{"Name":"subject","Field":"subject","Type":"string","Help":"Subject is the subject line, at most 200 characters on one line.","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"To is the one address the mail goes to.","Required":false}],"Example":null},{"Service":"marketing","Name":"promos-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.","Method":"GET","Path":"/v1/marketing/promos/:code/eligibility","Args":[{"Name":"code","Help":"Code is the promo code from the path."}],"Flags":[{"Name":"plan","Field":"plan","Type":"string","Help":"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.","Required":false},{"Name":"seats","Field":"seats","Type":"integer","Help":"Seats is the Team seat count; 0 means 1, and it is ignored for the\nsingle-seat plans.","Required":false}],"Example":{"code":"first1000","plan":"team","seats":12}},{"Service":"marketing","Name":"promos-list","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.","Method":"GET","Path":"/v1/marketing/promos","Args":[],"Flags":null,"Example":null},{"Service":"marketing","Name":"promos-redeem","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.","Method":"POST","Path":"/v1/marketing/promos/:code/redeem","Args":[{"Name":"code","Help":"Code is the promo code from the path."}],"Flags":[{"Name":"instrument","Field":"instrument","Type":"string","Help":"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.","Required":false}],"Example":{"code":"first1000","instrument":"pm_1QxYz2AbCdEf"}},{"Service":"marketing","Name":"promos-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.","Method":"GET","Path":"/v1/marketing/promos/:code/redemption","Args":[{"Name":"code","Help":"Code is the promo code from the path, e.g. \"first1000\"."}],"Flags":null,"Example":{"code":"first1000"}},{"Service":"marketing","Name":"sequences-cancel","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.","Method":"POST","Path":"/v1/marketing/sequences/:id/enrollments/:eid/cancel","Args":[{"Name":"id","Help":"ID is the sequence id from the path."},{"Name":"eid","Help":"EID is the enrollment id from the path, as returned by a single-address\nenroll."}],"Flags":null,"Example":{"eid":"enr_2a8d6f0b4c1e9375a0d2f6b8c4e19f73","id":"seq_7b3e5a1c9d024f68b0a3e7c5d9f1a248"}},{"Service":"marketing","Name":"sequences-create","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.","Method":"POST","Path":"/v1/marketing/sequences","Args":[],"Flags":[{"Name":"created-at","Field":"createdAt","Type":"integer","Help":"CreatedAt is unix seconds when the sequence was registered, server-assigned\nand never rewritten.","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"ID is the server-assigned sequence id (\"seq_\" + 128 random bits).","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the sequence's label. Required, trimmed, capped at 1024 bytes.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status is the lifecycle: draft, active or archived. Empty means draft, and\nONLY an active sequence accepts enrollments.","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"integer","Help":"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.","Required":false}],"Example":{"name":"Trial onboarding","status":"draft"}},{"Service":"marketing","Name":"sequences-enroll","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.","Method":"POST","Path":"/v1/marketing/sequences/:id/enroll","Args":[{"Name":"id","Help":"ID is the sequence id from the path."}],"Flags":[{"Name":"address","Field":"address","Type":"string","Help":"Address is a single recipient, normalized (lower-cased, trimmed) before\nuse. Give this OR audienceId, never both and never neither.","Required":false},{"Name":"audience-id","Field":"audienceId","Type":"string","Help":"AudienceID fans the sequence out over a saved audience, resolved live to\nthe org's mailable customers. Email only.","Required":false},{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is the delivery surface; empty means email. An audience resolves\nmailboxes, so an audience enroll must be email.","Required":false}],"Example":{"audienceId":"aud_4c1e9b7a2d6f0538e4a7c9b1d3f5027a","channel":"email"}},{"Service":"marketing","Name":"sequences-enrollments-list","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.","Method":"GET","Path":"/v1/marketing/sequences/:id/enrollments","Args":[{"Name":"id","Help":"ID is the sequence id from the path."}],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the rows returned; 0 means 200 and nothing above 1000 is honoured.","Required":false}],"Example":{"id":"seq_7b3e5a1c9d024f68b0a3e7c5d9f1a248","limit":100}},{"Service":"marketing","Name":"sequences-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.","Method":"GET","Path":"/v1/marketing/sequences/:id","Args":[{"Name":"id","Help":"ID is the sequence id from the path, as returned by create."}],"Flags":null,"Example":{"id":"seq_7b3e5a1c9d024f68b0a3e7c5d9f1a248"}},{"Service":"marketing","Name":"sequences-list","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.","Method":"GET","Path":"/v1/marketing/sequences","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the rows returned; 0 means 200 and nothing above 1000 is honoured.","Required":false}],"Example":{"limit":50}},{"Service":"marketing","Name":"sequences-status","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.","Method":"POST","Path":"/v1/marketing/sequences/:id/status","Args":[{"Name":"id","Help":"ID is the sequence id from the path."}],"Flags":[{"Name":"status","Field":"status","Type":"string","Help":"Status is draft, active or archived. Required; there is no default here,\nunlike on create. Only an active sequence accepts enrollments.","Required":false}],"Example":{"id":"seq_7b3e5a1c9d024f68b0a3e7c5d9f1a248","status":"active"}},{"Service":"marketing","Name":"sequences-steps","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.","Method":"POST","Path":"/v1/marketing/sequences/:id/steps","Args":[{"Name":"id","Help":"SequenceID is the sequence id from the path (the route's :id)."}],"Flags":[{"Name":"body","Field":"body","Type":"string","Help":"Body is the message text. Required.","Required":false},{"Name":"delay-seconds","Field":"delaySeconds","Type":"integer","Help":"DelaySeconds is how long after the previous step this one sends (after\nenrollment, for the first step). Must be \u003e= 0.","Required":false},{"Name":"subject","Field":"subject","Type":"string","Help":"Subject is the email subject line, capped at 1024 bytes.","Required":false}],"Example":{"body":"Here is how to make your first request…","delaySeconds":86400,"subject":"Day 1: your first model call"}},{"Service":"marketing","Name":"sequences-steps-list","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.","Method":"GET","Path":"/v1/marketing/sequences/:id/steps","Args":[{"Name":"id","Help":"ID is the sequence id from the path, as returned by create."}],"Flags":null,"Example":{"id":"seq_7b3e5a1c9d024f68b0a3e7c5d9f1a248"}},{"Service":"marketing","Name":"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.","Method":"GET","Path":"/v1/marketing/summary","Args":[],"Flags":null,"Example":null},{"Service":"marketing","Name":"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.","Method":"GET","Path":"/v1/marketing/suppressions/check","Args":[],"Flags":[{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is the surface the entry opts out of; empty is email.","Required":false},{"Name":"address","Field":"address","Type":"string","Help":"Address is the entry: an address, or \"@example.com\" for a company.","Required":false}],"Example":{"address":"person@example.com"}},{"Service":"marketing","Name":"suppressions-create","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.","Method":"POST","Path":"/v1/marketing/suppressions","Args":[],"Flags":[{"Name":"address","Field":"address","Type":"string","Help":"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.","Required":false},{"Name":"channel","Field":"channel","Type":"string","Help":"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.","Required":false},{"Name":"created-at","Field":"createdAt","Type":"integer","Help":"CreatedAt is unix seconds, server-assigned.","Required":false},{"Name":"reason","Field":"reason","Type":"string","Help":"Reason is a free-text note, capped at 1024 bytes. The public one-click\nendpoint records \"one-click unsubscribe\".","Required":false}],"Example":{"address":"person@example.com","channel":"email","reason":"asked support to stop"}},{"Service":"marketing","Name":"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.","Method":"DELETE","Path":"/v1/marketing/suppressions","Args":[],"Flags":[{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is the surface the entry opts out of; empty is email.","Required":false},{"Name":"address","Field":"address","Type":"string","Help":"Address is the entry: an address, or \"@example.com\" for a company.","Required":false}],"Example":{"address":"person@example.com","channel":"email"}},{"Service":"marketing","Name":"suppressions-list","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.","Method":"GET","Path":"/v1/marketing/suppressions","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the rows returned; 0 means 200 and nothing above 1000 is honoured.","Required":false}],"Example":{"limit":100}},{"Service":"marketing","Name":"unsubscribe-create","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.","Method":"POST","Path":"/v1/marketing/unsubscribe","Args":[],"Flags":[{"Name":"org","Field":"org","Type":"string","Help":"Org is the org the link was minted for.","Required":false},{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is the surface to opt out of.","Required":false},{"Name":"address","Field":"address","Type":"string","Help":"Address is the recipient to opt out.","Required":false},{"Name":"token","Field":"token","Type":"string","Help":"Token is the HMAC over (org, channel, address), the only authority here.","Required":false},{"Name":"list-unsubscribe","Field":"List-Unsubscribe","Type":"string","Help":"OneClick is the form's List-Unsubscribe field, \"One-Click\" from a mail\nclient. The token decides; this field only names the form.","Required":false,"In":"form"}],"Example":{"address":"person@example.com","channel":"email","org":"acme","token":"9f2a…"},"Consumes":["application/x-www-form-urlencoded","multipart/form-data"]},{"Service":"marketing","Name":"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.","Method":"GET","Path":"/v1/marketing/unsubscribe","Args":[],"Flags":[{"Name":"org","Field":"org","Type":"string","Help":"Org is the org the link was minted for.","Required":false},{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is the surface to opt out of.","Required":false},{"Name":"address","Field":"address","Type":"string","Help":"Address is the recipient to opt out.","Required":false},{"Name":"token","Field":"token","Type":"string","Help":"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.","Required":false},{"Name":"company","Field":"company","Type":"boolean","Help":"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.","Required":false}],"Example":{"address":"person@example.com","channel":"email","org":"acme","token":"9f2a…"}},{"Service":"marketplace","Name":"install-create","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.","Method":"POST","Path":"/v1/marketplace/install","Args":[],"Flags":[{"Name":"tool","Field":"tool","Type":"string","Help":"Tool is the registry name of the capability to activate (or deactivate) for\nthe caller's own org and project. Required.","Required":false}],"Example":{"tool":"summarize"}},{"Service":"marketplace","Name":"jobs-accept","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.","Method":"POST","Path":"/v1/marketplace/jobs/:id/accept","Args":[{"Name":"id","Help":"ID is the job, from the path."}],"Flags":null,"Example":{"id":"job_9a1f"}},{"Service":"marketplace","Name":"jobs-cancel","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.","Method":"POST","Path":"/v1/marketplace/jobs/:id/cancel","Args":[{"Name":"id","Help":"ID is the job, from the path."}],"Flags":null,"Example":{"id":"job_9a1f"}},{"Service":"marketplace","Name":"jobs-create","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.","Method":"POST","Path":"/v1/marketplace/jobs","Args":[],"Flags":[{"Name":"amount","Field":"amount","Type":"string","Help":"Amount is what the job pays, U.S. dollars to the cent: \"250.00\".","Required":false},{"Name":"attempt","Field":"attempt","Type":"string","Help":"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.","Required":false},{"Name":"brief","Field":"brief","Type":"string","Help":"Brief is what the buyer asks for, and what delivered looks like. Required,\nat most 4096 characters.","Required":false},{"Name":"category","Field":"category","Type":"string","Help":"Category is what the payment is for: service (the default), goods,\ntransfer or royalty.","Required":false},{"Name":"deadline","Field":"deadline","Type":"integer","Help":"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.","Required":false},{"Name":"listing","Field":"listing","Type":"string","Help":"Listing is the public listing the job is hired through. Empty for a direct\noffer, which names Seller instead.","Required":false},{"Name":"payment","Field":"payment","Type":"string","Help":"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.","Required":false},{"Name":"performed","Field":"performed","Type":"string","Help":"Performed is where the work is performed, ISO 3166-1 alpha-2. It decides\nwhether a foreign seller's pay is U.S.-source.","Required":false},{"Name":"rail","Field":"rail","Type":"string","Help":"Rail is x402 (the default) or chain.","Required":false},{"Name":"review","Field":"review","Type":"integer","Help":"Review is how many seconds the buyer has after delivery to release or\ndispute: three days by default, thirty at most.","Required":false},{"Name":"seller","Field":"seller","Type":"string","Help":"Seller is the org offered the job directly; only without a listing.","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"Title names a direct offer; a listing's job takes the listing's title.","Required":false},{"Name":"wallet","Field":"wallet","Type":"string","Help":"Wallet is the buyer's wallet the payment is signed from. When named, the\nauthorization must be signed by its address.","Required":false}],"Example":{"amount":"250.00","attempt":"8f14e45f-ea8d-4c4e-9c1b-0f3b2b1a7d6e","brief":"Summarize our Q3 filings","listing":"lst_4f1c"}},{"Service":"marketplace","Name":"jobs-decline","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.","Method":"POST","Path":"/v1/marketplace/jobs/:id/decline","Args":[{"Name":"id","Help":"ID is the job, from the path."}],"Flags":[{"Name":"reason","Field":"reason","Type":"string","Help":"Reason is the seller's words to the buyer, at most 4096 characters.","Required":false}],"Example":{"id":"job_9a1f","reason":"Booked through March"}},{"Service":"marketplace","Name":"jobs-deliver","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.","Method":"POST","Path":"/v1/marketplace/jobs/:id/deliver","Args":[{"Name":"id","Help":"ID is the job, from the path."}],"Flags":[{"Name":"hash","Field":"hash","Type":"string","Help":"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.","Required":false},{"Name":"note","Field":"note","Type":"string","Help":"Note says what was delivered. Required, at most 4096 characters.","Required":false},{"Name":"url","Field":"url","Type":"string","Help":"URL is where it is, https.","Required":false}],"Example":{"id":"job_9a1f","note":"Summary attached","url":"https://files.example.com/q3.pdf"}},{"Service":"marketplace","Name":"jobs-dispute","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.","Method":"POST","Path":"/v1/marketplace/jobs/:id/dispute","Args":[{"Name":"id","Help":"ID is the job, from the path."}],"Flags":[{"Name":"reason","Field":"reason","Type":"string","Help":"Reason is the disputing party's words. Required, at most 4096 characters.","Required":false}],"Example":{"id":"job_9a1f","reason":"The summary covers Q2, not Q3"}},{"Service":"marketplace","Name":"jobs-feedback","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.","Method":"POST","Path":"/v1/marketplace/jobs/:id/feedback","Args":[{"Name":"id","Help":"ID is the job, from the path."}],"Flags":[{"Name":"comment","Field":"comment","Type":"string","Help":"Comment is the party's words, at most 4096 characters.","Required":false},{"Name":"rating","Field":"rating","Type":"integer","Help":"Rating is 1 to 5 stars. Required.","Required":false}],"Example":{"comment":"Thorough and on time","id":"job_9a1f","rating":5}},{"Service":"marketplace","Name":"jobs-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.","Method":"GET","Path":"/v1/marketplace/jobs/:id","Args":[{"Name":"id","Help":"ID is the job, from the path."}],"Flags":null,"Example":{"id":"job_9a1f"}},{"Service":"marketplace","Name":"jobs-list","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.","Method":"GET","Path":"/v1/marketplace/jobs","Args":[],"Flags":[{"Name":"role","Field":"role","Type":"string","Help":"Role is buyer — the jobs the caller's org hired for — or seller, the jobs it\nwas hired for. Buyer when empty.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status keeps one state.","Required":false}],"Example":{"role":"seller","status":"open"}},{"Service":"marketplace","Name":"jobs-refund","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.","Method":"POST","Path":"/v1/marketplace/jobs/:id/refund","Args":[{"Name":"id","Help":"ID is the job, from the path."}],"Flags":null,"Example":{"id":"job_9a1f"}},{"Service":"marketplace","Name":"jobs-release","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.","Method":"POST","Path":"/v1/marketplace/jobs/:id/release","Args":[{"Name":"id","Help":"ID is the job, from the path."}],"Flags":null,"Example":{"id":"job_9a1f"}},{"Service":"marketplace","Name":"list","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.","Method":"GET","Path":"/v1/marketplace","Args":[],"Flags":null,"Example":null},{"Service":"marketplace","Name":"listings-create","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.","Method":"POST","Path":"/v1/marketplace/listings","Args":[],"Flags":[{"Name":"category","Field":"category","Type":"string","Help":"Category groups the listing in the shop window.","Required":false},{"Name":"currency","Field":"currency","Type":"string","Help":"Currency denominates Price.","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"Description is the long copy, at most 4096 characters.","Required":false},{"Name":"docs","Field":"docs","Type":"string","Help":"Docs is where the listing's documentation lives: an https URL or a path on\ndocs.hanzo.ai.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"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.","Required":false},{"Name":"price","Field":"price","Type":"string","Help":"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.","Required":false},{"Name":"public","Field":"public","Type":"boolean","Help":"Public makes the listing discoverable by other orgs. Private otherwise.","Required":false},{"Name":"recipient","Field":"recipient","Type":"string","Help":"Recipient is the seller's payout wallet id, in the publishing org — the\nwallet x402 pays. Required for a monetized listing.","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"Title is the shop-window name, 1-200 characters. Required.","Required":false},{"Name":"tool","Field":"tool","Type":"string","Help":"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.","Required":false}],"Example":{"kind":"agent","price":"250","public":true,"recipient":"wal_9f2","title":"Research analyst","tool":"researcher"}},{"Service":"marketplace","Name":"listings-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.","Method":"DELETE","Path":"/v1/marketplace/listings/:id","Args":[{"Name":"id","Help":"ID is the listing, from the path."}],"Flags":null,"Example":{"id":"lst_1"}},{"Service":"marketplace","Name":"listings-list","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.","Method":"GET","Path":"/v1/marketplace/listings","Args":[],"Flags":null,"Example":null},{"Service":"marketplace","Name":"listings-update","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.","Method":"PATCH","Path":"/v1/marketplace/listings/:id","Args":[{"Name":"id","Help":"ID is the listing to edit, from the path."}],"Flags":[{"Name":"category","Field":"category","Type":"string","Help":"Category groups the listing in the shop window.","Required":false},{"Name":"currency","Field":"currency","Type":"string","Help":"Currency denominates Price.","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"Description is the long copy, at most 4096 characters.","Required":false},{"Name":"docs","Field":"docs","Type":"string","Help":"Docs is where the listing's documentation lives; empty clears it.","Required":false},{"Name":"price","Field":"price","Type":"string","Help":"Price is the decimal USD price, exact to 18 places; \"0\" makes it free.","Required":false},{"Name":"public","Field":"public","Type":"boolean","Help":"Public makes the listing discoverable by other orgs, or withdraws it.","Required":false},{"Name":"recipient","Field":"recipient","Type":"string","Help":"Recipient is the payout wallet id, in the publishing org.","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"Title is the shop-window name, 1-200 characters.","Required":false}],"Example":{"id":"lst_4f1c","price":"300","public":true}},{"Service":"marketplace","Name":"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.","Method":"GET","Path":"/v1/marketplace/seller","Args":[],"Flags":[{"Name":"year","Field":"year","Type":"integer","Help":"Year is the calendar year (UTC); the current one when zero.","Required":false}],"Example":{"year":2026}},{"Service":"marketplace","Name":"seller-payout-create","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.","Method":"POST","Path":"/v1/marketplace/seller/payout","Args":[],"Flags":[{"Name":"wallet","Field":"wallet","Type":"string","Help":"Wallet is one of the caller org's wallets. Required.","Required":false}],"Example":{"wallet":"wal_9f2"}},{"Service":"marketplace","Name":"seller-payout-verify-create","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.","Method":"POST","Path":"/v1/marketplace/seller/payout/verify","Args":[],"Flags":[{"Name":"signature","Field":"signature","Type":"string","Help":"Signature is the wallet's 65-byte signature over the challenge's message\n(EIP-191), 0x hex. Required.","Required":false}],"Example":{"signature":"0x5f1c…1b"}},{"Service":"marketplace","Name":"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.","Method":"GET","Path":"/v1/marketplace/shop","Args":[],"Flags":[{"Name":"q","Field":"q","Type":"string","Help":"Q keeps listings whose title, description, category, thing or seller\ncontains every word of it, case-insensitively.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind keeps one kind: agent, persona, app, skill, mcp or tool.","Required":false},{"Name":"category","Field":"category","Type":"string","Help":"Category keeps one category, exactly.","Required":false},{"Name":"price","Field":"price","Type":"string","Help":"Price keeps free listings or priced ones.","Required":false},{"Name":"rating","Field":"rating","Type":"integer","Help":"Rating keeps listings rated at least this many stars, 1 to 5.","Required":false},{"Name":"seller","Field":"seller","Type":"string","Help":"Seller keeps one seller org's listings.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit is the page size: 48 by default, 200 at most.","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset is where the page starts.","Required":false}],"Example":{"kind":"agent","limit":48,"q":"research"}},{"Service":"marketplace","Name":"shop-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.","Method":"GET","Path":"/v1/marketplace/shop/:id","Args":[{"Name":"id","Help":"ID is the listing, from the path."}],"Flags":null,"Example":{"id":"lst_4f1c"}},{"Service":"marketplace","Name":"uninstall-create","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.","Method":"POST","Path":"/v1/marketplace/uninstall","Args":[],"Flags":[{"Name":"tool","Field":"tool","Type":"string","Help":"Tool is the registry name of the capability to activate (or deactivate) for\nthe caller's own org and project. Required.","Required":false}],"Example":{"tool":"summarize"}},{"Service":"mcp","Name":"create","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.","Method":"POST","Path":"/v1/mcp","Args":[],"Flags":[{"Name":"id","Field":"id","Type":"json","Help":"","Required":false},{"Name":"jsonrpc","Field":"jsonrpc","Type":"string","Help":"","Required":false},{"Name":"method","Field":"method","Type":"string","Help":"","Required":false},{"Name":"params","Field":"params","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"meet","Name":"call","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.","Method":"GET","Path":"/v1/meet/call","Args":[],"Flags":[{"Name":"space","Field":"space","Type":"string","Help":"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.","Required":true},{"Name":"room","Field":"room","Type":"string","Help":"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.","Required":true}],"Example":null},{"Service":"meet","Name":"get-token-create","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.","Method":"POST","Path":"/v1/meet/getToken","Args":[],"Flags":null,"Example":null},{"Service":"meet","Name":"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.","Method":"GET","Path":"/v1/meet/health","Args":[],"Flags":null,"Example":null},{"Service":"meet","Name":"record-read","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.","Method":"GET","Path":"/v1/meet/record","Args":[],"Flags":[{"Name":"room","Field":"room","Type":"string","Help":"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.","Required":true}],"Example":null},{"Service":"meet","Name":"record-start","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.","Method":"POST","Path":"/v1/meet/record","Args":[],"Flags":[{"Name":"room","Field":"room","Type":"string","Help":"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.","Required":true}],"Example":null},{"Service":"meet","Name":"record-stop","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.","Method":"DELETE","Path":"/v1/meet/record","Args":[],"Flags":[{"Name":"room","Field":"room","Type":"string","Help":"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.","Required":true}],"Example":null},{"Service":"meet","Name":"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.","Method":"GET","Path":"/v1/meet/session","Args":[],"Flags":null,"Example":null},{"Service":"messages","Name":"count-tokens-create","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.","Method":"POST","Path":"/v1/messages/count_tokens","Args":[],"Flags":null,"Example":null},{"Service":"messages","Name":"create","OperationID":"post_messages","Summary":"Implements the Anthropic Messages API.","Description":"Implements the Anthropic Messages API.","Method":"POST","Path":"/v1/messages","Args":[],"Flags":[{"Name":"max-tokens","Field":"max_tokens","Type":"integer","Help":"","Required":false},{"Name":"messages","Field":"messages","Type":"json","Help":"","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"","Required":false},{"Name":"stream","Field":"stream","Type":"boolean","Help":"","Required":false},{"Name":"system","Field":"system","Type":"json","Help":"","Required":false},{"Name":"temperature","Field":"temperature","Type":"number","Help":"","Required":false},{"Name":"thinking","Field":"thinking","Type":"json","Help":"","Required":false},{"Name":"tool-choice","Field":"tool_choice","Type":"json","Help":"","Required":false},{"Name":"tools","Field":"tools","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"metrics","Name":"batch-create","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.","Method":"POST","Path":"/v1/metrics/batch","Args":[],"Flags":null,"Example":null},{"Service":"metrics","Name":"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.","Method":"GET","Path":"/v1/metrics/health","Args":[],"Flags":null,"Example":null},{"Service":"metrics","Name":"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`.","Method":"GET","Path":"/v1/metrics/logs/health","Args":[],"Flags":null,"Example":null},{"Service":"metrics","Name":"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.","Method":"GET","Path":"/v1/metrics/logs/query","Args":[],"Flags":null,"Example":null},{"Service":"metrics","Name":"logs-write-create","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.","Method":"POST","Path":"/v1/metrics/logs/write","Args":[],"Flags":null,"Example":null},{"Service":"metrics","Name":"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.","Method":"GET","Path":"/v1/metrics/query","Args":[],"Flags":null,"Example":null},{"Service":"metrics","Name":"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`.","Method":"GET","Path":"/v1/metrics/traces/health","Args":[],"Flags":null,"Example":null},{"Service":"metrics","Name":"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`.","Method":"GET","Path":"/v1/metrics/traces/query","Args":[],"Flags":null,"Example":null},{"Service":"metrics","Name":"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.","Method":"GET","Path":"/v1/metrics/traces/trace","Args":[],"Flags":null,"Example":null},{"Service":"metrics","Name":"traces-write-create","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.","Method":"POST","Path":"/v1/metrics/traces/write","Args":[],"Flags":null,"Example":null},{"Service":"metrics","Name":"write-create","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.","Method":"POST","Path":"/v1/metrics/write","Args":[],"Flags":null,"Example":null},{"Service":"ml","Name":"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.","Method":"GET","Path":"/v1/ml/health","Args":[],"Flags":null,"Example":null},{"Service":"ml","Name":"models-create","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.","Method":"POST","Path":"/v1/ml/models","Args":[],"Flags":[{"Name":"labels","Field":"labels","Type":"json","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false},{"Name":"spec","Field":"spec","Type":"json","Help":"Spec is the resource's own spec, passed to Kubernetes unchanged. Required —\nan empty spec is 400 rather than an empty resource.","Required":false}],"Example":{"name":"sentiment","spec":{"predictor":{"model":{"modelFormat":{"name":"sklearn"},"storageUri":"s3://models/sentiment"}}}}},{"Service":"ml","Name":"models-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.","Method":"DELETE","Path":"/v1/ml/models/:name","Args":[{"Name":"name","Help":"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."}],"Flags":null,"Example":{"name":"sentiment"}},{"Service":"ml","Name":"models-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.","Method":"GET","Path":"/v1/ml/models/:name","Args":[{"Name":"name","Help":"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."}],"Flags":null,"Example":{"name":"sentiment"}},{"Service":"ml","Name":"models-list","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.","Method":"GET","Path":"/v1/ml/models","Args":[],"Flags":null,"Example":null},{"Service":"ml","Name":"models-predict","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.","Method":"POST","Path":"/v1/ml/models/:name/predict","Args":[{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"ml","Name":"models-update","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.","Method":"PATCH","Path":"/v1/ml/models/:name","Args":[{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"models","Name":"access","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.","Method":"POST","Path":"/v1/models/:model/access","Args":[{"Name":"model","Help":""}],"Flags":null,"Example":null},{"Service":"models","Name":"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.","Method":"GET","Path":"/v1/models/:model/access","Args":[{"Name":"model","Help":""}],"Flags":null,"Example":null},{"Service":"models","Name":"list","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.","Method":"GET","Path":"/v1/models","Args":[],"Flags":null,"Example":null},{"Service":"models","Name":"providers-list","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.","Method":"GET","Path":"/v1/models/providers","Args":[],"Flags":null,"Example":null},{"Service":"models","Name":"vendors-events-list","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).","Method":"GET","Path":"/v1/models/vendors/:vendor/events","Args":[{"Name":"vendor","Help":""}],"Flags":null,"Example":null},{"Service":"models","Name":"vendors-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.","Method":"GET","Path":"/v1/models/vendors/:vendor","Args":[{"Name":"vendor","Help":""}],"Flags":null,"Example":null},{"Service":"mq","Name":"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.","Method":"GET","Path":"/v1/mq/health","Args":[],"Flags":null,"Example":null},{"Service":"mq","Name":"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.","Method":"GET","Path":"/v1/mq/info","Args":[],"Flags":null,"Example":null},{"Service":"mq","Name":"stream-consumer","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.","Method":"POST","Path":"/v1/mq/stream/:stream/consumer","Args":[{"Name":"stream","Help":"Stream is the stream name, from the path."}],"Flags":[{"Name":"ack-policy","Field":"ack_policy","Type":"string","Help":"Ack is the acknowledgment policy: explicit (default), all, or none.","Required":false},{"Name":"ack-wait","Field":"ack_wait","Type":"string","Help":"AckWait is how long the broker waits for an ack before redelivering, e.g. \"30s\" (default).","Required":false},{"Name":"deliver-policy","Field":"deliver_policy","Type":"string","Help":"Deliver is where delivery starts: all (default), last, new, by_start_sequence, by_start_time, or last_per_subject.","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"Description says what this consumer is for.","Required":false},{"Name":"durable-name","Field":"durable_name","Type":"string","Help":"Name is the durable consumer name (alphanumeric, hyphens, underscores).","Required":false},{"Name":"filter-subject","Field":"filter_subject","Type":"string","Help":"Filter delivers only messages on this org-relative subject (wildcards supported).","Required":false},{"Name":"max-ack-pending","Field":"max_ack_pending","Type":"integer","Help":"MaxAckPending caps unacknowledged messages in flight (default 1000).","Required":false},{"Name":"max-deliver","Field":"max_deliver","Type":"integer","Help":"MaxDeliver caps delivery attempts per message; -1 (default) is unlimited.","Required":false},{"Name":"opt-start-seq","Field":"opt_start_seq","Type":"integer","Help":"StartSeq is the starting sequence for deliver_policy by_start_sequence.","Required":false},{"Name":"opt-start-time","Field":"opt_start_time","Type":"string","Help":"StartTime is the starting instant for deliver_policy by_start_time.","Required":false},{"Name":"replay-policy","Field":"replay_policy","Type":"string","Help":"Replay is the replay pacing: instant (default) or original.","Required":false}],"Example":null},{"Service":"mq","Name":"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.","Method":"GET","Path":"/v1/mq/stream/:stream/consumer","Args":[{"Name":"stream","Help":"Stream is the stream name, from the path."}],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the consumers returned (1–1000, default 100).","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset skips that many consumers, name-ordered.","Required":false}],"Example":null},{"Service":"mq","Name":"stream-create","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.","Method":"POST","Path":"/v1/mq/stream","Args":[],"Flags":[{"Name":"max-age","Field":"max_age","Type":"string","Help":"MaxAge caps message age, e.g. \"24h\" or \"7d\"; \"0\" (default) is unlimited.","Required":false},{"Name":"max-bytes","Field":"max_bytes","Type":"integer","Help":"MaxBytes caps the stream's total stored bytes; -1 (default) is unlimited.","Required":false},{"Name":"max-msg-size","Field":"max_msg_size","Type":"integer","Help":"MaxMsgSize caps one message's size in bytes; -1 (default) is the broker's limit.","Required":false},{"Name":"max-msgs","Field":"max_msgs","Type":"integer","Help":"MaxMsgs caps the number of stored messages; -1 (default) is unlimited.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the stream name, unique within the org (alphanumeric, hyphens, underscores).","Required":false},{"Name":"num-replicas","Field":"num_replicas","Type":"integer","Help":"Replicas is the number of stream replicas (1–5); this plane runs 1.","Required":false},{"Name":"retention","Field":"retention","Type":"string","Help":"Retention is the retention policy: limits (default), interest, or workqueue.","Required":false},{"Name":"storage","Field":"storage","Type":"string","Help":"Storage is the storage backend: file (default) or memory.","Required":false},{"Name":"subjects","Field":"subjects","Type":"json","Help":"Subjects are the org-relative subjects bound to this stream (wildcards supported). Default: the stream name.","Required":false}],"Example":null},{"Service":"mq","Name":"stream-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.","Method":"DELETE","Path":"/v1/mq/stream/:name","Args":[{"Name":"name","Help":"Name is the stream name, from the path."}],"Flags":null,"Example":null},{"Service":"mq","Name":"stream-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.","Method":"DELETE","Path":"/v1/mq/stream/:name/message/:seq","Args":[{"Name":"name","Help":"Name is the stream name, from the path."},{"Name":"seq","Help":"Seq is the message's stream sequence, from the path."}],"Flags":null,"Example":null},{"Service":"mq","Name":"stream-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.","Method":"DELETE","Path":"/v1/mq/stream/:stream/consumer/:name","Args":[{"Name":"stream","Help":"Stream is the stream name, from the path."},{"Name":"name","Help":"Name is the consumer name, from the path."}],"Flags":null,"Example":null},{"Service":"mq","Name":"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.","Method":"GET","Path":"/v1/mq/stream","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the streams returned (1–1000, default 100).","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset skips that many streams, name-ordered.","Required":false}],"Example":null},{"Service":"mq","Name":"stream-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.","Method":"GET","Path":"/v1/mq/stream/:name","Args":[{"Name":"name","Help":"Name is the stream name, from the path."}],"Flags":null,"Example":null},{"Service":"mq","Name":"stream-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.","Method":"GET","Path":"/v1/mq/stream/:stream/consumer/:name","Args":[{"Name":"stream","Help":"Stream is the stream name, from the path."},{"Name":"name","Help":"Name is the consumer name, from the path."}],"Flags":null,"Example":null},{"Service":"mq","Name":"stream-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.","Method":"GET","Path":"/v1/mq/stream/:name/message","Args":[{"Name":"name","Help":"Name is the stream name, from the path."}],"Flags":[{"Name":"seq","Field":"seq","Type":"integer","Help":"Seq reads the message at this sequence (with next_by_subject: the walk's start).","Required":false},{"Name":"last-by-subject","Field":"last_by_subject","Type":"string","Help":"LastBySubject reads the newest message on this org-relative subject.","Required":false},{"Name":"next-by-subject","Field":"next_by_subject","Type":"string","Help":"NextBySubject walks forward from seq collecting messages on this org-relative subject (wildcards supported).","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps a next_by_subject walk (1–1000, default 100).","Required":false}],"Example":null},{"Service":"mq","Name":"stream-next","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.","Method":"POST","Path":"/v1/mq/stream/:stream/consumer/:name/next","Args":[{"Name":"stream","Help":"Stream is the stream name, from the path."},{"Name":"name","Help":"Name is the consumer name, from the path."}],"Flags":[{"Name":"batch","Field":"batch","Type":"integer","Help":"Batch is how many messages to pull (1–1000, default 1).","Required":false},{"Name":"expires","Field":"expires","Type":"string","Help":"Expires is how long to wait for messages, e.g. \"5s\" (default \"30s\", max \"60s\").","Required":false},{"Name":"no-wait","Field":"no_wait","Type":"boolean","Help":"NoWait answers immediately with whatever is available instead of waiting.","Required":false}],"Example":null},{"Service":"mq","Name":"stream-purge","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.","Method":"POST","Path":"/v1/mq/stream/:name/purge","Args":[{"Name":"name","Help":"Name is the stream name, from the path."}],"Flags":[{"Name":"filter","Field":"filter","Type":"string","Help":"Filter purges only messages on this org-relative subject (wildcards supported).","Required":false},{"Name":"keep","Field":"keep","Type":"integer","Help":"Keep retains that many newest messages.","Required":false}],"Example":null},{"Service":"mq","Name":"stream-update","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.","Method":"PUT","Path":"/v1/mq/stream/:name","Args":[{"Name":"name","Help":"Name is the stream name, unique within the org (alphanumeric, hyphens, underscores)."}],"Flags":[{"Name":"max-age","Field":"max_age","Type":"string","Help":"MaxAge caps message age, e.g. \"24h\" or \"7d\"; \"0\" (default) is unlimited.","Required":false},{"Name":"max-bytes","Field":"max_bytes","Type":"integer","Help":"MaxBytes caps the stream's total stored bytes; -1 (default) is unlimited.","Required":false},{"Name":"max-msg-size","Field":"max_msg_size","Type":"integer","Help":"MaxMsgSize caps one message's size in bytes; -1 (default) is the broker's limit.","Required":false},{"Name":"max-msgs","Field":"max_msgs","Type":"integer","Help":"MaxMsgs caps the number of stored messages; -1 (default) is unlimited.","Required":false},{"Name":"num-replicas","Field":"num_replicas","Type":"integer","Help":"Replicas is the number of stream replicas (1–5); this plane runs 1.","Required":false},{"Name":"retention","Field":"retention","Type":"string","Help":"Retention is the retention policy: limits (default), interest, or workqueue.","Required":false},{"Name":"storage","Field":"storage","Type":"string","Help":"Storage is the storage backend: file (default) or memory.","Required":false},{"Name":"subjects","Field":"subjects","Type":"json","Help":"Subjects are the org-relative subjects bound to this stream (wildcards supported). Default: the stream name.","Required":false}],"Example":null},{"Service":"network","Name":"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.","Method":"GET","Path":"/v1/network/:id","Args":[{"Name":"id","Help":"ID is the network id from the path. The URL is the addressing authority, so\nit binds from there whatever else the request carries."}],"Flags":null,"Example":null},{"Service":"network","Name":"identities-create","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.","Method":"POST","Path":"/v1/network/identities","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false},{"Name":"roles","Field":"roles","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"network","Name":"identities-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.","Method":"DELETE","Path":"/v1/network/identities/:id","Args":[{"Name":"id","Help":"ID is the identity id from the path. The URL is the addressing authority,\nso it binds from there whatever else the request carries."}],"Flags":null,"Example":null},{"Service":"network","Name":"identities-list","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.","Method":"GET","Path":"/v1/network/identities","Args":[],"Flags":null,"Example":null},{"Service":"network","Name":"list","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.","Method":"GET","Path":"/v1/network","Args":[],"Flags":null,"Example":null},{"Service":"network","Name":"routers-list","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.","Method":"GET","Path":"/v1/network/routers","Args":[],"Flags":null,"Example":null},{"Service":"network","Name":"services-create","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.","Method":"POST","Path":"/v1/network/services","Args":[],"Flags":[{"Name":"host","Field":"host","Type":"string","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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\".","Required":false},{"Name":"port","Field":"port","Type":"integer","Help":"Port is the port beside Host, and the one the DNS name intercepts.","Required":false}],"Example":null},{"Service":"network","Name":"services-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.","Method":"DELETE","Path":"/v1/network/services/:id","Args":[{"Name":"id","Help":"ID is the service id from the path. The URL is the addressing authority,\nso it binds from there whatever else the request carries."}],"Flags":null,"Example":null},{"Service":"network","Name":"services-list","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.","Method":"GET","Path":"/v1/network/services","Args":[],"Flags":null,"Example":null},{"Service":"node","Name":"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.","Method":"GET","Path":"/v1/node/connect","Args":[],"Flags":null,"Example":null},{"Service":"node","Name":"invoke","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.","Method":"POST","Path":"/v1/node/:id/invoke","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"node","Name":"list","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.","Method":"GET","Path":"/v1/node","Args":[],"Flags":null,"Example":null},{"Service":"node","Name":"peer-invoke-create","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.","Method":"POST","Path":"/v1/node/peer/invoke","Args":[],"Flags":null,"Example":null},{"Service":"notify","Name":"credentials-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.","Method":"DELETE","Path":"/v1/notify/credentials/:provider/:key","Args":[{"Name":"provider","Help":"Provider is the delivery provider the credential is for."},{"Name":"key","Help":"Key is the credential's name within that provider."}],"Flags":null,"Example":null},{"Service":"notify","Name":"credentials-update","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.","Method":"PUT","Path":"/v1/notify/credentials/:provider/:key","Args":[{"Name":"provider","Help":"Provider is the delivery provider the credential is for: twilio, plivo,\ntwilio_email or mail."},{"Name":"key","Help":"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."}],"Flags":[{"Name":"value","Field":"value","Type":"string","Help":"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.","Required":false}],"Example":{"key":"auth-token","provider":"twilio","value":"…"}},{"Service":"notify","Name":"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.","Method":"GET","Path":"/v1/notify/health","Args":[],"Flags":null,"Example":null},{"Service":"notify","Name":"send-create","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.","Method":"POST","Path":"/v1/notify/send","Args":[],"Flags":[{"Name":"body","Field":"body","Type":"string","Help":"Body is the message text, sent verbatim when present — the no-template path.","Required":false},{"Name":"channel","Field":"channel","Type":"string","Help":"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.","Required":false},{"Name":"event","Field":"event","Type":"string","Help":"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.","Required":false},{"Name":"provider","Field":"provider","Type":"string","Help":"Provider pins a provider service name (twilio, plivo, twilio_email, mail).\nEmpty picks the one whose org credentials are actually configured in KMS.","Required":false},{"Name":"subject","Field":"subject","Type":"string","Help":"Subject is the message subject, carried on the email channel only.","Required":false},{"Name":"sync","Field":"sync","Type":"string","Help":"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.","Required":false},{"Name":"template-id","Field":"template_id","Type":"string","Help":"TemplateID selects a built-in template when Body is empty.","Required":false},{"Name":"template-vars","Field":"template_vars","Type":"json","Help":"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.","Required":false},{"Name":"to","Field":"to","Type":"json","Help":"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).","Required":false}],"Example":null},{"Service":"notify","Name":"send-email-create","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.","Method":"POST","Path":"/v1/notify/send/email","Args":[],"Flags":[{"Name":"body","Field":"body","Type":"string","Help":"Body is the message text, sent verbatim when present — the no-template path.","Required":false},{"Name":"channel","Field":"channel","Type":"string","Help":"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.","Required":false},{"Name":"event","Field":"event","Type":"string","Help":"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.","Required":false},{"Name":"provider","Field":"provider","Type":"string","Help":"Provider pins a provider service name (twilio, plivo, twilio_email, mail).\nEmpty picks the one whose org credentials are actually configured in KMS.","Required":false},{"Name":"subject","Field":"subject","Type":"string","Help":"Subject is the message subject, carried on the email channel only.","Required":false},{"Name":"sync","Field":"sync","Type":"string","Help":"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.","Required":false},{"Name":"template-id","Field":"template_id","Type":"string","Help":"TemplateID selects a built-in template when Body is empty.","Required":false},{"Name":"template-vars","Field":"template_vars","Type":"json","Help":"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.","Required":false},{"Name":"to","Field":"to","Type":"json","Help":"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).","Required":false}],"Example":null},{"Service":"notify","Name":"send-sms-create","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.","Method":"POST","Path":"/v1/notify/send/sms","Args":[],"Flags":[{"Name":"body","Field":"body","Type":"string","Help":"Body is the message text, sent verbatim when present — the no-template path.","Required":false},{"Name":"channel","Field":"channel","Type":"string","Help":"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.","Required":false},{"Name":"event","Field":"event","Type":"string","Help":"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.","Required":false},{"Name":"provider","Field":"provider","Type":"string","Help":"Provider pins a provider service name (twilio, plivo, twilio_email, mail).\nEmpty picks the one whose org credentials are actually configured in KMS.","Required":false},{"Name":"subject","Field":"subject","Type":"string","Help":"Subject is the message subject, carried on the email channel only.","Required":false},{"Name":"sync","Field":"sync","Type":"string","Help":"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.","Required":false},{"Name":"template-id","Field":"template_id","Type":"string","Help":"TemplateID selects a built-in template when Body is empty.","Required":false},{"Name":"template-vars","Field":"template_vars","Type":"json","Help":"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.","Required":false},{"Name":"to","Field":"to","Type":"json","Help":"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).","Required":false}],"Example":null},{"Service":"o11y","Name":"agent-check-in","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.","Method":"POST","Path":"/v1/o11y/cloud_integrations/:cloud_provider/accounts/check_in","Args":[{"Name":"cloud_provider","Help":""}],"Flags":[{"Name":"account-id","Field":"account_id","Type":"string","Help":"following are backward compatible fields for older running agents, hence snake case JSON keys.\nWhich get mapped to new fields in AgentCheckInRequest","Required":false},{"Name":"cloud-integration-id","Field":"cloudIntegrationId","Type":"json","Help":"","Required":false},{"Name":"cloud-account-id","Field":"cloud_account_id","Type":"string","Help":"=\u003e ProviderAccountID","Required":false},{"Name":"data","Field":"data","Type":"json","Help":"","Required":false},{"Name":"provider-account-id","Field":"providerAccountId","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"agent-check-in-deprecated","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.","Method":"POST","Path":"/v1/o11y/cloud-integrations/:cloud_provider/agent-check-in","Args":[{"Name":"cloud_provider","Help":""}],"Flags":[{"Name":"account-id","Field":"account_id","Type":"string","Help":"following are backward compatible fields for older running agents, hence snake case JSON keys.\nWhich get mapped to new fields in AgentCheckInRequest","Required":false},{"Name":"cloud-integration-id","Field":"cloudIntegrationId","Type":"json","Help":"","Required":false},{"Name":"cloud-account-id","Field":"cloud_account_id","Type":"string","Help":"=\u003e ProviderAccountID","Required":false},{"Name":"data","Field":"data","Type":"json","Help":"","Required":false},{"Name":"provider-account-id","Field":"providerAccountId","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"alerts-create","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.","Method":"POST","Path":"/v1/o11y/alerts/:receiver","Args":[{"Name":"receiver","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/alerts/heartbeat","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/alerts/last","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"authz-check","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.","Method":"POST","Path":"/v1/o11y/authz/check","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"auto-complete-attribute-values-create","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.","Method":"POST","Path":"/v1/o11y/auto_complete/attribute_values","Args":[],"Flags":[{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"","Required":false},{"Name":"data-source","Field":"dataSource","Type":"string","Help":"","Required":false},{"Name":"end-time-millis","Field":"endTimeMillis","Type":"integer","Help":"","Required":false},{"Name":"existing-filter-items","Field":"existingFilterItems","Type":"json","Help":"","Required":false},{"Name":"filter-attribute-key","Field":"filterAttributeKey","Type":"string","Help":"","Required":false},{"Name":"filter-attribute-key-data-type","Field":"filterAttributeKeyDataType","Type":"string","Help":"","Required":false},{"Name":"include-related","Field":"includeRelated","Type":"boolean","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"metric-names","Field":"metricNames","Type":"json","Help":"","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"","Required":false},{"Name":"start-time-millis","Field":"startTimeMillis","Type":"integer","Help":"","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"autocomplete-aggregate-attributes-list","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.","Method":"GET","Path":"/v1/o11y/autocomplete/aggregate_attributes","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the attributes come from — traces, logs,\nmetrics or meter. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the attribute will be used under, e.g.\ncount, avg, sum. The runtime requires it for non-metrics sources.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the attributes to those containing it.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many attributes come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"autocomplete-attribute-keys-list","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.","Method":"GET","Path":"/v1/o11y/autocomplete/attribute_keys","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the keys come from — traces, logs, metrics or\nmeter. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the keys will be used under. The\nruntime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the keys must appear on.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the keys to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many keys come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"autocomplete-attribute-values-list","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.","Method":"GET","Path":"/v1/o11y/autocomplete/attribute_values","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the values come from — traces, logs or\nmetrics. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the values will be used under. The\nruntime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the values must appear on.","Required":false},{"Name":"attribute-key","Field":"attributeKey","Type":"string","Help":"AttributeKey is the key whose values to list.","Required":false},{"Name":"filter-attribute-key-data-type","Field":"filterAttributeKeyDataType","Type":"string","Help":"FilterAttributeKeyDataType is the key's data type — string, int64, float64\nor bool. Empty means unspecified.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the values to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the search to one kind of key — tag or resource.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many values come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"clone-dashboard-v2","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.","Method":"POST","Path":"/v1/o11y/dashboards/:id/clone","Args":[{"Name":"id","Help":"ID is the resource id from the path."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"clusters-attribute-keys-list","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.","Method":"GET","Path":"/v1/o11y/clusters/attribute_keys","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the keys must appear on.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the keys to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many keys come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"clusters-attribute-values-list","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.","Method":"GET","Path":"/v1/o11y/clusters/attribute_values","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the values must appear on.","Required":false},{"Name":"attribute-key","Field":"attributeKey","Type":"string","Help":"AttributeKey is the key whose values to list.","Required":false},{"Name":"filter-attribute-key-data-type","Field":"filterAttributeKeyDataType","Type":"string","Help":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the values to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the search to one kind of key — tag or resource.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many values come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"clusters-list-create","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.","Method":"POST","Path":"/v1/o11y/clusters/list","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"epoch time in ms","Required":false},{"Name":"filters","Field":"filters","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"epoch time in ms","Required":false}],"Example":null},{"Service":"o11y","Name":"count-errors-create","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.","Method":"POST","Path":"/v1/o11y/countErrors","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"string","Help":"End is the window end, as a nanosecond epoch spelled as a string.","Required":false},{"Name":"exception-type","Field":"exceptionType","Type":"string","Help":"ExceptionType narrows to one exception type.","Required":false},{"Name":"service-name","Field":"serviceName","Type":"string","Help":"ServiceName narrows to one reporting service.","Required":false},{"Name":"start","Field":"start","Type":"string","Help":"Start is the window start, as a nanosecond epoch spelled as a string.","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"Tags narrow the scan to spans carrying the given tag values.","Required":false}],"Example":null},{"Service":"o11y","Name":"create-account","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.","Method":"POST","Path":"/v1/o11y/cloud_integrations/:cloud_provider/accounts","Args":[{"Name":"cloud_provider","Help":""}],"Flags":[{"Name":"config","Field":"config","Type":"json","Help":"","Required":false},{"Name":"credentials","Field":"credentials","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"create-channel","OperationID":"CreateChannel","Summary":"Creates a notification channel, answering with the stored channel.","Description":"Creates a notification channel, answering with the stored\nchannel. Admin gate.","Method":"POST","Path":"/v1/o11y/channels","Args":[],"Flags":[{"Name":"receiver","Field":"Receiver","Type":"json","Help":"","Required":false},{"Name":"googlechat-configs","Field":"googlechat_configs","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"create-dashboard-v2","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.","Method":"POST","Path":"/v1/o11y/dashboards","Args":[],"Flags":[{"Name":"generate-name","Field":"generateName","Type":"boolean","Help":"GenerateName derives a fresh unique name from spec.display.name instead of\ntaking Name.","Required":false},{"Name":"image","Field":"image","Type":"string","Help":"Image is an optional cover image reference.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the dashboard's unique internal name (a DNS-1123 label). Omit it\nwith generateName to derive one from the display name.","Required":false},{"Name":"schema-version","Field":"schemaVersion","Type":"string","Help":"SchemaVersion is the dashboard schema version; must be the current v6.","Required":false},{"Name":"spec","Field":"spec","Type":"json","Help":"Spec is the Perses dashboard spec (display, variables, panels, layouts,\ndatasources). Its plugin-defined leaves are open JSON, carried verbatim.","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"Tags are the dashboard's tags; at most ten, and none may use a reserved DSL\nkey.","Required":false}],"Example":null},{"Service":"o11y","Name":"create-dashboard-view","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.","Method":"POST","Path":"/v1/o11y/dashboard_views","Args":[],"Flags":[{"Name":"data","Field":"data","Type":"json","Help":"Data is the listing state the view captures.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the saved view's name; at most 32 characters, no surrounding space.","Required":false}],"Example":null},{"Service":"o11y","Name":"create-downtime-schedule","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.","Method":"POST","Path":"/v1/o11y/downtime_schedules","Args":[],"Flags":[{"Name":"alert-ids","Field":"alertIds","Type":"json","Help":"","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"schedule","Field":"schedule","Type":"json","Help":"","Required":false},{"Name":"scope","Field":"scope","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"create-ingestion-key","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.","Method":"POST","Path":"/v1/o11y/gateway/ingestion_keys","Args":[],"Flags":[{"Name":"expires-at","Field":"expires_at","Type":"string","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"create-ingestion-key-limit","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.","Method":"POST","Path":"/v1/o11y/gateway/ingestion_keys/:keyId/limits","Args":[{"Name":"keyId","Help":""}],"Flags":[{"Name":"config","Field":"config","Type":"json","Help":"","Required":false},{"Name":"signal","Field":"signal","Type":"string","Help":"","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"create-llm-annotation","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.","Method":"POST","Path":"/v1/o11y/llm/annotation","Args":[],"Flags":[{"Name":"content","Field":"content","Type":"string","Help":"Content is the note itself. Required.","Required":false},{"Name":"observation-id","Field":"observationId","Type":"string","Help":"ObservationID is the single observation the annotation attaches to, when\nnarrowed to one.","Required":false},{"Name":"queue","Field":"queue","Type":"string","Help":"Queue is the review queue to file the annotation in.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status is the annotation's initial review status. Defaults to PENDING.","Required":false},{"Name":"trace-id","Field":"traceId","Type":"string","Help":"TraceID is the trace the annotation attaches to. Required.","Required":false}],"Example":null},{"Service":"o11y","Name":"create-llm-score","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.","Method":"POST","Path":"/v1/o11y/llm/scores","Args":[],"Flags":[{"Name":"comment","Field":"comment","Type":"string","Help":"Comment is a free-text note.","Required":false},{"Name":"data-type","Field":"dataType","Type":"string","Help":"DataType is the score's kind — NUMERIC or CATEGORICAL. Defaults from the\nvalue when empty.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the score's name, e.g. helpfulness. Required.","Required":false},{"Name":"observation-id","Field":"observationId","Type":"string","Help":"ObservationID is the single observation the score attaches to, when\nnarrowed to one.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source is where the score came from, e.g. API, EVAL. Defaults to API.","Required":false},{"Name":"string-value","Field":"stringValue","Type":"string","Help":"StringValue is the categorical score, when the score is categorical.","Required":false},{"Name":"trace-id","Field":"traceId","Type":"string","Help":"TraceID is the trace the score attaches to. Required.","Required":false},{"Name":"value","Field":"value","Type":"number","Help":"Value is the numeric score.","Required":false}],"Example":null},{"Service":"o11y","Name":"create-metric-reduction-rule","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.","Method":"POST","Path":"/v1/o11y/metric_reduction_rules","Args":[],"Flags":[{"Name":"labels","Field":"labels","Type":"json","Help":"Labels are the label names the rule matches. Required, at least one.","Required":true},{"Name":"match-type","Field":"matchType","Type":"string","Help":"MatchType is drop or keep: drop the named labels, or keep only them. Required.","Required":true},{"Name":"metric-name","Field":"metricName","Type":"string","Help":"MetricName is the metric the rule governs; one rule per metric. Required.","Required":true}],"Example":null},{"Service":"o11y","Name":"create-or-update-llm-pricing-rules","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.","Method":"PUT","Path":"/v1/o11y/llm_pricing_rules","Args":[],"Flags":[{"Name":"rules","Field":"rules","Type":"json","Help":"Rules are the rules to create or update, matched per rule.","Required":false}],"Example":null},{"Service":"o11y","Name":"create-public-dashboard","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.","Method":"POST","Path":"/v1/o11y/dashboards/:id/public","Args":[{"Name":"id","Help":"ID is the dashboard id from the path."}],"Flags":[{"Name":"default-time-range","Field":"defaultTimeRange","Type":"string","Help":"DefaultTimeRange is the fixed window as a Go duration, e.g. 1h, 30m.","Required":false},{"Name":"time-range-enabled","Field":"timeRangeEnabled","Type":"boolean","Help":"TimeRangeEnabled lets the public page pick its own time range; when false\nthe share fixes DefaultTimeRange.","Required":false}],"Example":null},{"Service":"o11y","Name":"create-role","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.","Method":"POST","Path":"/v1/o11y/roles","Args":[],"Flags":[{"Name":"description","Field":"description","Type":"string","Help":"Description says what the role is for.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the role's name: lowercase letters and hyphens, at most 50\ncharacters, not starting with the reserved managed-role prefix. Required.","Required":false},{"Name":"transaction-groups","Field":"transactionGroups","Type":"json","Help":"TransactionGroups are the grants the role carries.","Required":false}],"Example":null},{"Service":"o11y","Name":"create-route-policy","OperationID":"CreateRoutePolicy","Summary":"Creates a route policy, answering with the stored policy.","Description":"Creates a route policy, answering with the stored policy. Admin gate.","Method":"POST","Path":"/v1/o11y/route_policies","Args":[],"Flags":[{"Name":"channels","Field":"channels","Type":"json","Help":"","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"expression","Field":"expression","Type":"string","Help":"","Required":false},{"Name":"kind","Field":"kind","Type":"json","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"create-rule","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.","Method":"POST","Path":"/v1/o11y/rules","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"create-service-account","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.","Method":"POST","Path":"/v1/o11y/service_accounts","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"Name is the account's name: a lowercase letter followed by lowercase\nletters, digits or hyphens, at most 50 characters. Required.","Required":false}],"Example":null},{"Service":"o11y","Name":"create-service-account-key","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.","Method":"POST","Path":"/v1/o11y/service_accounts/:id/keys","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"expires-at","Field":"expiresAt","Type":"integer","Help":"ExpiresAt is when the key stops working, as a unix timestamp in seconds.\nZero means it never expires; a past timestamp is refused.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the key's name: a lowercase letter followed by lowercase letters,\ndigits or hyphens, at most 80 characters. Required.","Required":false}],"Example":null},{"Service":"o11y","Name":"create-service-account-role","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.","Method":"POST","Path":"/v1/o11y/service_accounts/:id/roles","Args":[{"Name":"id","Help":"RoleID is the id of the role to assign. Required."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"create-span-mapper","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.","Method":"POST","Path":"/v1/o11y/span_mapper_groups/:groupId/span_mappers","Args":[{"Name":"groupId","Help":""}],"Flags":[{"Name":"config","Field":"config","Type":"json","Help":"","Required":false},{"Name":"enabled","Field":"enabled","Type":"boolean","Help":"","Required":false},{"Name":"field-context","Field":"fieldContext","Type":"json","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"create-span-mapper-group","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.","Method":"POST","Path":"/v1/o11y/span_mapper_groups","Args":[],"Flags":[{"Name":"condition","Field":"condition","Type":"json","Help":"","Required":false},{"Name":"enabled","Field":"enabled","Type":"boolean","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"create-trace-funnel","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.","Method":"POST","Path":"/v1/o11y/trace-funnels/new","Args":[],"Flags":[{"Name":"funnel-name","Field":"funnel_name","Type":"string","Help":"Name is the funnel's name.","Required":false},{"Name":"timestamp","Field":"timestamp","Type":"integer","Help":"Timestamp is when the funnel was created, as a millisecond epoch. Zero\ntakes the runtime's own clock.","Required":false}],"Example":null},{"Service":"o11y","Name":"daemonsets-attribute-keys-list","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.","Method":"GET","Path":"/v1/o11y/daemonsets/attribute_keys","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the keys must appear on.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the keys to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many keys come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"daemonsets-attribute-values-list","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.","Method":"GET","Path":"/v1/o11y/daemonsets/attribute_values","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the values must appear on.","Required":false},{"Name":"attribute-key","Field":"attributeKey","Type":"string","Help":"AttributeKey is the key whose values to list.","Required":false},{"Name":"filter-attribute-key-data-type","Field":"filterAttributeKeyDataType","Type":"string","Help":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the values to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the search to one kind of key — tag or resource.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many values come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"daemonsets-list-create","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.","Method":"POST","Path":"/v1/o11y/daemonsets/list","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"epoch time in ms","Required":false},{"Name":"filters","Field":"filters","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"epoch time in ms","Required":false}],"Example":null},{"Service":"o11y","Name":"delete-channel-by-id","OperationID":"DeleteChannelByID","Summary":"Removes a notification channel, by id.","Description":"Removes a notification channel, by id. Admin gate.","Method":"DELETE","Path":"/v1/o11y/channels/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"delete-dashboard-v2","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.","Method":"DELETE","Path":"/v1/o11y/dashboards/:id","Args":[{"Name":"id","Help":"ID is the resource id from the path."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"delete-dashboard-view","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.","Method":"DELETE","Path":"/v1/o11y/dashboard_views/:id","Args":[{"Name":"id","Help":"ID is the resource id from the path."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"delete-downtime-schedule-by-id","OperationID":"DeleteDowntimeScheduleByID","Summary":"Removes a planned maintenance window, by id.","Description":"Removes a planned maintenance window, by id. Editor gate.","Method":"DELETE","Path":"/v1/o11y/downtime_schedules/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"delete-ingestion-key","OperationID":"DeleteIngestionKey","Summary":"Removes an ingestion key, by id.","Description":"Removes an ingestion key, by id. Editor gate.","Method":"DELETE","Path":"/v1/o11y/gateway/ingestion_keys/:keyId","Args":[{"Name":"keyId","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"delete-ingestion-key-limit","OperationID":"DeleteIngestionKeyLimit","Summary":"Removes an ingestion key limit, by limit id.","Description":"Removes an ingestion key limit, by limit id. Editor\ngate.","Method":"DELETE","Path":"/v1/o11y/gateway/ingestion_keys/limits/:limitId","Args":[{"Name":"limitId","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"delete-llm-pricing-rule","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.","Method":"DELETE","Path":"/v1/o11y/llm_pricing_rules/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"delete-llm-score","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.","Method":"DELETE","Path":"/v1/o11y/llm/score/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"delete-metric-reduction-rule-by-id","OperationID":"DeleteMetricReductionRuleByID","Summary":"Deletes a volume-control rule by its id.","Description":"Deletes a volume-control rule by its id.","Method":"DELETE","Path":"/v1/o11y/metric_reduction_rules/:id","Args":[{"Name":"id","Help":"ID is the rule's id."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"delete-public-dashboard","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.","Method":"DELETE","Path":"/v1/o11y/dashboards/:id/public","Args":[{"Name":"id","Help":"ID is the resource id from the path."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"delete-role","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.","Method":"DELETE","Path":"/v1/o11y/roles/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"delete-route-policy-by-id","OperationID":"DeleteRoutePolicyByID","Summary":"Removes a route policy, by id.","Description":"Removes a route policy, by id. Admin gate.","Method":"DELETE","Path":"/v1/o11y/route_policies/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"delete-rule-by-id","OperationID":"DeleteRuleByID","Summary":"Removes an alert rule, by id.","Description":"Removes an alert rule, by id. Editor gate.","Method":"DELETE","Path":"/v1/o11y/rules/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"delete-service-account","OperationID":"DeleteServiceAccount","Summary":"Deletes a service account and revokes every key it holds.","Description":"Deletes a service account and revokes every key it\nholds.","Method":"DELETE","Path":"/v1/o11y/service_accounts/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"delete-service-account-role","OperationID":"DeleteServiceAccountRole","Summary":"Removes a role from a service account.","Description":"Removes a role from a service account.","Method":"DELETE","Path":"/v1/o11y/service_accounts/:id/roles/:rid","Args":[{"Name":"id","Help":""},{"Name":"rid","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"delete-span-mapper","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.","Method":"DELETE","Path":"/v1/o11y/span_mapper_groups/:groupId/span_mappers/:mapperId","Args":[{"Name":"groupId","Help":""},{"Name":"mapperId","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"delete-span-mapper-group","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.","Method":"DELETE","Path":"/v1/o11y/span_mapper_groups/:groupId","Args":[{"Name":"groupId","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"delete-trace-funnel","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.","Method":"DELETE","Path":"/v1/o11y/trace-funnels/:funnel_id","Args":[{"Name":"funnel_id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"dependency-graph-create","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.","Method":"POST","Path":"/v1/o11y/dependency_graph","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"string","Help":"End is the window end, as epoch nanoseconds. Required.","Required":true},{"Name":"start","Field":"start","Type":"string","Help":"Start is the window start, as epoch nanoseconds. Required.","Required":true},{"Name":"tags","Field":"tags","Type":"json","Help":"Tags narrow the graph to spans matching every condition.","Required":false}],"Example":null},{"Service":"o11y","Name":"deployments-attribute-keys-list","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.","Method":"GET","Path":"/v1/o11y/deployments/attribute_keys","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the keys must appear on.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the keys to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many keys come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"deployments-attribute-values-list","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.","Method":"GET","Path":"/v1/o11y/deployments/attribute_values","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the values must appear on.","Required":false},{"Name":"attribute-key","Field":"attributeKey","Type":"string","Help":"AttributeKey is the key whose values to list.","Required":false},{"Name":"filter-attribute-key-data-type","Field":"filterAttributeKeyDataType","Type":"string","Help":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the values to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the search to one kind of key — tag or resource.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many values come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"deployments-list-create","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.","Method":"POST","Path":"/v1/o11y/deployments/list","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"epoch time in ms","Required":false},{"Name":"filters","Field":"filters","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"epoch time in ms","Required":false}],"Example":null},{"Service":"o11y","Name":"disconnect-account","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.","Method":"DELETE","Path":"/v1/o11y/cloud_integrations/:cloud_provider/accounts/:id","Args":[{"Name":"cloud_provider","Help":""},{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"disks-list","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.","Method":"GET","Path":"/v1/o11y/disks","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"error-from-error-id-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.","Method":"GET","Path":"/v1/o11y/errorFromErrorID","Args":[],"Flags":[{"Name":"timestamp","Field":"timestamp","Type":"string","Help":"Timestamp is the instance's time as a nanosecond epoch spelled as a\nstring. Required.","Required":true},{"Name":"group-id","Field":"groupID","Type":"string","Help":"GroupID is the exception group the instance belongs to. Required.","Required":true},{"Name":"error-id","Field":"errorID","Type":"string","Help":"ErrorID is the exception instance id. Required by errorFromErrorID and\nnextPrevErrorIDs; unused by errorFromGroupID.","Required":false}],"Example":null},{"Service":"o11y","Name":"error-from-group-id-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.","Method":"GET","Path":"/v1/o11y/errorFromGroupID","Args":[],"Flags":[{"Name":"timestamp","Field":"timestamp","Type":"string","Help":"Timestamp is the instance's time as a nanosecond epoch spelled as a\nstring. Required.","Required":true},{"Name":"group-id","Field":"groupID","Type":"string","Help":"GroupID is the exception group the instance belongs to. Required.","Required":true},{"Name":"error-id","Field":"errorID","Type":"string","Help":"ErrorID is the exception instance id. Required by errorFromErrorID and\nnextPrevErrorIDs; unused by errorFromGroupID.","Required":false}],"Example":null},{"Service":"o11y","Name":"errortracking-issues-create","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.","Method":"POST","Path":"/v1/o11y/errortracking/issues/:id","Args":[{"Name":"id","Help":"ID is the issue id."}],"Flags":[{"Name":"assignee","Field":"assignee","Type":"string","Help":"Assignee is who the issue is assigned to.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status is the new lifecycle state: unresolved, resolved or ignored.","Required":false}],"Example":null},{"Service":"o11y","Name":"errortracking-issues-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.","Method":"GET","Path":"/v1/o11y/errortracking/issues/:id","Args":[{"Name":"id","Help":"ID is the issue id."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"errortracking-issues-list","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.","Method":"GET","Path":"/v1/o11y/errortracking/issues","Args":[],"Flags":[{"Name":"status","Field":"status","Type":"string","Help":"Status narrows to one lifecycle state: unresolved, resolved or ignored.","Required":false},{"Name":"level","Field":"level","Type":"string","Help":"Level narrows to one severity, e.g. error, warning, info.","Required":false},{"Name":"environment","Field":"environment","Type":"string","Help":"Environment narrows to one deployment environment.","Required":false},{"Name":"service-name","Field":"serviceName","Type":"string","Help":"ServiceName narrows to one reporting service.","Required":false},{"Name":"query","Field":"query","Type":"string","Help":"Query narrows to issues whose text contains it.","Required":false},{"Name":"sort","Field":"sort","Type":"string","Help":"Sort orders the page, e.g. lastSeen, firstSeen, count.","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset is how many issues to skip. Zero starts at the first.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many issues come back. Zero means the default.","Required":false}],"Example":null},{"Service":"o11y","Name":"event-create","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.","Method":"POST","Path":"/v1/o11y/event","Args":[],"Flags":[{"Name":"attributes","Field":"attributes","Type":"json","Help":"Attributes are free-form event properties.","Required":false},{"Name":"event-name","Field":"eventName","Type":"string","Help":"EventName names the event; required for track events.","Required":false},{"Name":"event-type","Field":"eventType","Type":"string","Help":"EventType is the kind of event — track, identify or group. Required.","Required":true},{"Name":"rate-limited","Field":"rateLimited","Type":"boolean","Help":"RateLimited marks an event the reporting client rate-limited.","Required":false}],"Example":null},{"Service":"o11y","Name":"explorer-views-create","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.","Method":"POST","Path":"/v1/o11y/explorer/views","Args":[],"Flags":[{"Name":"category","Field":"category","Type":"string","Help":"","Required":false},{"Name":"composite-query","Field":"compositeQuery","Type":"json","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"string","Help":"","Required":false},{"Name":"created-by","Field":"createdBy","Type":"string","Help":"","Required":false},{"Name":"extra-data","Field":"extraData","Type":"string","Help":"ExtraData is JSON encoded data used by frontend to store additional data","Required":false},{"Name":"id","Field":"id","Type":"json","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"source-page","Field":"sourcePage","Type":"string","Help":"","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"string","Help":"","Required":false},{"Name":"updated-by","Field":"updatedBy","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"explorer-views-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.","Method":"DELETE","Path":"/v1/o11y/explorer/views/:viewId","Args":[{"Name":"viewId","Help":"ViewID is the view's id."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"explorer-views-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.","Method":"GET","Path":"/v1/o11y/explorer/views/:viewId","Args":[{"Name":"viewId","Help":"ViewID is the view's id."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"explorer-views-list","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.","Method":"GET","Path":"/v1/o11y/explorer/views","Args":[],"Flags":[{"Name":"source-page","Field":"sourcePage","Type":"string","Help":"SourcePage narrows the views to one source page, e.g. traces, logs.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name narrows the views to one name.","Required":false},{"Name":"category","Field":"category","Type":"string","Help":"Category narrows the views to one category.","Required":false}],"Example":null},{"Service":"o11y","Name":"explorer-views-update","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.","Method":"PUT","Path":"/v1/o11y/explorer/views/:viewId","Args":[{"Name":"viewId","Help":"ViewID is the id of the view to replace, taken from the URL."}],"Flags":[{"Name":"category","Field":"category","Type":"string","Help":"","Required":false},{"Name":"composite-query","Field":"compositeQuery","Type":"json","Help":"","Required":false},{"Name":"created-at","Field":"createdAt","Type":"string","Help":"","Required":false},{"Name":"created-by","Field":"createdBy","Type":"string","Help":"","Required":false},{"Name":"extra-data","Field":"extraData","Type":"string","Help":"ExtraData is JSON encoded data used by frontend to store additional data","Required":false},{"Name":"id","Field":"id","Type":"json","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"source-page","Field":"sourcePage","Type":"string","Help":"","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"string","Help":"","Required":false},{"Name":"updated-by","Field":"updatedBy","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"export-raw-data-create","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.","Method":"POST","Path":"/v1/o11y/export_raw_data","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"features-list","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.","Method":"GET","Path":"/v1/o11y/features","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"fields-keys-list","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.","Method":"GET","Path":"/v1/o11y/fields/keys","Args":[],"Flags":[{"Name":"signal","Field":"signal","Type":"string","Help":"Signal is the telemetry to read the fields of — traces, logs or metrics.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source narrows the fields to one source within the signal.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many keys come back.","Required":false},{"Name":"start-unix-milli","Field":"startUnixMilli","Type":"integer","Help":"StartUnixMilli is the window start as a unix millisecond epoch. Zero reads\nas unset.","Required":false},{"Name":"end-unix-milli","Field":"endUnixMilli","Type":"integer","Help":"EndUnixMilli is the window end as a unix millisecond epoch. Zero reads as\nunset.","Required":false},{"Name":"field-context","Field":"fieldContext","Type":"string","Help":"FieldContext narrows the keys to one context — resource, scope, attribute,\nspan, log or metric.","Required":false},{"Name":"field-data-type","Field":"fieldDataType","Type":"string","Help":"FieldDataType narrows the keys to one data type.","Required":false},{"Name":"metric-name","Field":"metricName","Type":"string","Help":"MetricName narrows the keys to those on one metric.","Required":false},{"Name":"metric-namespace","Field":"metricNamespace","Type":"string","Help":"MetricNamespace narrows the keys to one metric namespace.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the keys to those containing it.","Required":false}],"Example":null},{"Service":"o11y","Name":"fields-values-list","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.","Method":"GET","Path":"/v1/o11y/fields/values","Args":[],"Flags":[{"Name":"signal","Field":"signal","Type":"string","Help":"Signal is the telemetry to read the field of — traces, logs or metrics.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source narrows the field to one source within the signal.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many values come back.","Required":false},{"Name":"start-unix-milli","Field":"startUnixMilli","Type":"integer","Help":"StartUnixMilli is the window start as a unix millisecond epoch. Zero reads\nas unset.","Required":false},{"Name":"end-unix-milli","Field":"endUnixMilli","Type":"integer","Help":"EndUnixMilli is the window end as a unix millisecond epoch. Zero reads as\nunset.","Required":false},{"Name":"field-context","Field":"fieldContext","Type":"string","Help":"FieldContext narrows the field to one context.","Required":false},{"Name":"field-data-type","Field":"fieldDataType","Type":"string","Help":"FieldDataType narrows the field to one data type.","Required":false},{"Name":"metric-name","Field":"metricName","Type":"string","Help":"MetricName narrows the field to one metric.","Required":false},{"Name":"metric-namespace","Field":"metricNamespace","Type":"string","Help":"MetricNamespace narrows the field to one metric namespace.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the values to those containing it.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the field whose values to read.","Required":false},{"Name":"existing-query","Field":"existingQuery","Type":"string","Help":"ExistingQuery is the query the field appears in, so related values can be\nsuggested for it.","Required":false}],"Example":null},{"Service":"o11y","Name":"filter-suggestions-list","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.","Method":"GET","Path":"/v1/o11y/filter_suggestions","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the signal suggestions are drawn from; only logs is\nsupported today. Required.","Required":true},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows attribute suggestions to keys containing it.","Required":false},{"Name":"existing-filter","Field":"existingFilter","Type":"string","Help":"ExistingFilter is the current filter set, JSON base64url-encoded, so\nexample queries build on it rather than repeat it.","Required":false},{"Name":"attributes-limit","Field":"attributesLimit","Type":"integer","Help":"AttributesLimit caps how many attribute keys come back.","Required":false},{"Name":"examples-limit","Field":"examplesLimit","Type":"integer","Help":"ExamplesLimit caps how many example queries come back.","Required":false}],"Example":null},{"Service":"o11y","Name":"get-account","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.","Method":"GET","Path":"/v1/o11y/cloud_integrations/:cloud_provider/accounts/:id","Args":[{"Name":"cloud_provider","Help":""},{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-account-service","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.","Method":"GET","Path":"/v1/o11y/cloud_integrations/:cloud_provider/accounts/:id/services/:service_id","Args":[{"Name":"cloud_provider","Help":""},{"Name":"id","Help":""},{"Name":"service_id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-alerts","OperationID":"GetAlerts","Summary":"Returns the org's current alerts.","Description":"Returns the org's current alerts. Viewer gate.","Method":"GET","Path":"/v1/o11y/alerts","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-all-route-policies","OperationID":"GetAllRoutePolicies","Summary":"Lists the org's route policies.","Description":"Lists the org's route policies. Viewer gate.","Method":"GET","Path":"/v1/o11y/route_policies","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-channel-by-id","OperationID":"GetChannelByID","Summary":"Returns one notification channel, by id.","Description":"Returns one notification channel, by id. Viewer gate.","Method":"GET","Path":"/v1/o11y/channels/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-connection-credentials","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.","Method":"GET","Path":"/v1/o11y/cloud_integrations/:cloud_provider/credentials","Args":[{"Name":"cloud_provider","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-dashboard-v2","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.","Method":"GET","Path":"/v1/o11y/dashboards/:id","Args":[{"Name":"id","Help":"ID is the resource id from the path."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-downtime-schedule-by-id","OperationID":"GetDowntimeScheduleByID","Summary":"Returns one planned maintenance window, by id.","Description":"Returns one planned maintenance window, by id. Viewer gate.","Method":"GET","Path":"/v1/o11y/downtime_schedules/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-draft-funnel-error-traces","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.","Method":"POST","Path":"/v1/o11y/trace-funnels/analytics/error-traces","Args":[],"Flags":[{"Name":"end-time","Field":"end_time","Type":"integer","Help":"EndTime is the end of the window, as a millisecond epoch.","Required":false},{"Name":"start-time","Field":"start_time","Type":"integer","Help":"StartTime is the start of the window, as a millisecond epoch.","Required":false},{"Name":"step-end","Field":"step_end","Type":"integer","Help":"StepEnd is the step the transition runs to, 1-based.","Required":false},{"Name":"step-start","Field":"step_start","Type":"integer","Help":"StepStart is the step the transition runs from, 1-based. Ignored by the\nreads that span the whole funnel.","Required":false},{"Name":"steps","Field":"steps","Type":"json","Help":"Steps are the funnel's steps, in order. At least two are needed.","Required":false}],"Example":null},{"Service":"o11y","Name":"get-draft-funnel-overview","OperationID":"GetDraftFunnelOverview","Summary":"Returns the conversion overview of a funnel described inline.","Description":"Returns the conversion overview of a funnel described\ninline.","Method":"POST","Path":"/v1/o11y/trace-funnels/analytics/overview","Args":[],"Flags":[{"Name":"end-time","Field":"end_time","Type":"integer","Help":"EndTime is the end of the window, as a millisecond epoch.","Required":false},{"Name":"start-time","Field":"start_time","Type":"integer","Help":"StartTime is the start of the window, as a millisecond epoch.","Required":false},{"Name":"step-end","Field":"step_end","Type":"integer","Help":"StepEnd is the step the transition runs to, 1-based.","Required":false},{"Name":"step-start","Field":"step_start","Type":"integer","Help":"StepStart is the step the transition runs from, 1-based. Ignored by the\nreads that span the whole funnel.","Required":false},{"Name":"steps","Field":"steps","Type":"json","Help":"Steps are the funnel's steps, in order. At least two are needed.","Required":false}],"Example":null},{"Service":"o11y","Name":"get-draft-funnel-slow-traces","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.","Method":"POST","Path":"/v1/o11y/trace-funnels/analytics/slow-traces","Args":[],"Flags":[{"Name":"end-time","Field":"end_time","Type":"integer","Help":"EndTime is the end of the window, as a millisecond epoch.","Required":false},{"Name":"start-time","Field":"start_time","Type":"integer","Help":"StartTime is the start of the window, as a millisecond epoch.","Required":false},{"Name":"step-end","Field":"step_end","Type":"integer","Help":"StepEnd is the step the transition runs to, 1-based.","Required":false},{"Name":"step-start","Field":"step_start","Type":"integer","Help":"StepStart is the step the transition runs from, 1-based. Ignored by the\nreads that span the whole funnel.","Required":false},{"Name":"steps","Field":"steps","Type":"json","Help":"Steps are the funnel's steps, in order. At least two are needed.","Required":false}],"Example":null},{"Service":"o11y","Name":"get-draft-funnel-step-metrics","OperationID":"GetDraftFunnelStepMetrics","Summary":"Returns the per-step metrics of a funnel described inline.","Description":"Returns the per-step metrics of a funnel described inline.","Method":"POST","Path":"/v1/o11y/trace-funnels/analytics/steps","Args":[],"Flags":[{"Name":"end-time","Field":"end_time","Type":"integer","Help":"EndTime is the end of the window, as a millisecond epoch.","Required":false},{"Name":"start-time","Field":"start_time","Type":"integer","Help":"StartTime is the start of the window, as a millisecond epoch.","Required":false},{"Name":"step-end","Field":"step_end","Type":"integer","Help":"StepEnd is the step the transition runs to, 1-based.","Required":false},{"Name":"step-start","Field":"step_start","Type":"integer","Help":"StepStart is the step the transition runs from, 1-based. Ignored by the\nreads that span the whole funnel.","Required":false},{"Name":"steps","Field":"steps","Type":"json","Help":"Steps are the funnel's steps, in order. At least two are needed.","Required":false}],"Example":null},{"Service":"o11y","Name":"get-draft-funnel-step-overview","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.","Method":"POST","Path":"/v1/o11y/trace-funnels/analytics/steps/overview","Args":[],"Flags":[{"Name":"end-time","Field":"end_time","Type":"integer","Help":"EndTime is the end of the window, as a millisecond epoch.","Required":false},{"Name":"start-time","Field":"start_time","Type":"integer","Help":"StartTime is the start of the window, as a millisecond epoch.","Required":false},{"Name":"step-end","Field":"step_end","Type":"integer","Help":"StepEnd is the step the transition runs to, 1-based.","Required":false},{"Name":"step-start","Field":"step_start","Type":"integer","Help":"StepStart is the step the transition runs from, 1-based. Ignored by the\nreads that span the whole funnel.","Required":false},{"Name":"steps","Field":"steps","Type":"json","Help":"Steps are the funnel's steps, in order. At least two are needed.","Required":false}],"Example":null},{"Service":"o11y","Name":"get-flamegraph","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.","Method":"POST","Path":"/v1/o11y/traces/:traceId/flamegraph","Args":[{"Name":"traceId","Help":""}],"Flags":[{"Name":"select-fields","Field":"selectFields","Type":"json","Help":"","Required":false},{"Name":"selected-span-id","Field":"selectedSpanId","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"get-hosts","OperationID":"GetHosts","Summary":"Returns the deployment's host info from Zeus.","Description":"Returns the deployment's host info from Zeus. Viewer gate.","Method":"GET","Path":"/v1/o11y/zeus/hosts","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-ingestion-keys","OperationID":"GetIngestionKeys","Summary":"Lists the workspace's ingestion keys, paginated.","Description":"Lists the workspace's ingestion keys, paginated. Editor\ngate.","Method":"GET","Path":"/v1/o11y/gateway/ingestion_keys","Args":[],"Flags":[{"Name":"page","Field":"page","Type":"integer","Help":"Page is the 1-based page number.","Required":false},{"Name":"per-page","Field":"per_page","Type":"integer","Help":"PerPage is the page size.","Required":false}],"Example":null},{"Service":"o11y","Name":"get-integration","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.","Method":"GET","Path":"/v1/o11y/integrations/:integrationId","Args":[{"Name":"integrationId","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-integration-connection-status","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.","Method":"GET","Path":"/v1/o11y/integrations/:integrationId/connection_status","Args":[{"Name":"integrationId","Help":""}],"Flags":[{"Name":"lookback-seconds","Field":"lookback_seconds","Type":"integer","Help":"LookbackSeconds is how far back to look for received telemetry, in\nseconds.","Required":false}],"Example":null},{"Service":"o11y","Name":"get-llm-pricing-rule","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.","Method":"GET","Path":"/v1/o11y/llm_pricing_rules/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-llm-score","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.","Method":"GET","Path":"/v1/o11y/llm/score/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-metric-alerts","OperationID":"GetMetricAlerts","Summary":"Lists the alert rules that reference a metric.","Description":"Lists the alert rules that reference a metric.","Method":"GET","Path":"/v1/o11y/metrics/alerts","Args":[],"Flags":[{"Name":"metric-name","Field":"metricName","Type":"string","Help":"MetricName is the metric's name; it may contain slashes, e.g.\nrun.googleapis.com/request_latencies. Required.","Required":true}],"Example":null},{"Service":"o11y","Name":"get-metric-attributes","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.","Method":"GET","Path":"/v1/o11y/metrics/attributes","Args":[],"Flags":[{"Name":"metric-name","Field":"metricName","Type":"string","Help":"MetricName is the metric's name; it may contain slashes. Required.","Required":true},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the start of the window as a Unix timestamp in milliseconds.","Required":false},{"Name":"end","Field":"end","Type":"integer","Help":"End is the end of the window as a Unix timestamp in milliseconds.","Required":false}],"Example":null},{"Service":"o11y","Name":"get-metric-dashboards-v2","OperationID":"GetMetricDashboardsV2","Summary":"Lists the dashboard panels that reference a metric.","Description":"Lists the dashboard panels that reference a metric.","Method":"GET","Path":"/v1/o11y/metrics/dashboards","Args":[],"Flags":[{"Name":"metric-name","Field":"metricName","Type":"string","Help":"MetricName is the metric's name; it may contain slashes, e.g.\nrun.googleapis.com/request_latencies. Required.","Required":true}],"Example":null},{"Service":"o11y","Name":"get-metric-highlights","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.","Method":"GET","Path":"/v1/o11y/metrics/highlights","Args":[],"Flags":[{"Name":"metric-name","Field":"metricName","Type":"string","Help":"MetricName is the metric's name; it may contain slashes, e.g.\nrun.googleapis.com/request_latencies. Required.","Required":true}],"Example":null},{"Service":"o11y","Name":"get-metric-metadata","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.","Method":"GET","Path":"/v1/o11y/metrics/metadata","Args":[],"Flags":[{"Name":"metric-name","Field":"metricName","Type":"string","Help":"MetricName is the metric's name; it may contain slashes, e.g.\nrun.googleapis.com/request_latencies. Required.","Required":true}],"Example":null},{"Service":"o11y","Name":"get-metric-reduction-rule-by-id","OperationID":"GetMetricReductionRuleByID","Summary":"Returns one volume-control rule by its id.","Description":"Returns one volume-control rule by its id.","Method":"GET","Path":"/v1/o11y/metric_reduction_rules/:id","Args":[{"Name":"id","Help":"ID is the rule's id."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-metric-reduction-rule-stats","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.","Method":"GET","Path":"/v1/o11y/metric_reduction_rules/stats","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-metric-reduction-rule-timeseries","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.","Method":"GET","Path":"/v1/o11y/metric_reduction_rules/timeseries","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-metrics-onboarding-status","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.","Method":"GET","Path":"/v1/o11y/metrics/onboarding","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-metrics-stats","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.","Method":"POST","Path":"/v1/o11y/metrics/stats","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"End is the end of the window as a Unix timestamp in milliseconds. Required.","Required":true},{"Name":"filter","Field":"filter","Type":"json","Help":"Filter narrows the metrics counted.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many metrics come back, between 1 and 5000. Required.","Required":true},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset is how many metrics to skip, for paging.","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"OrderBy sorts the page, by samples or timeseries.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the start of the window as a Unix timestamp in milliseconds. Required.","Required":true}],"Example":null},{"Service":"o11y","Name":"get-metrics-treemap","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.","Method":"POST","Path":"/v1/o11y/metrics/treemap","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"End is the end of the window as a Unix timestamp in milliseconds. Required.","Required":true},{"Name":"filter","Field":"filter","Type":"json","Help":"Filter narrows the metrics counted.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many entries come back, between 1 and 5000. Required.","Required":true},{"Name":"mode","Field":"mode","Type":"string","Help":"Mode picks the measure: timeseries or samples. Required.","Required":true},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the start of the window as a Unix timestamp in milliseconds. Required.","Required":true}],"Example":null},{"Service":"o11y","Name":"get-my-organization","OperationID":"GetMyOrganization","Summary":"Returns the caller's own organization.","Description":"Returns the caller's own organization. Admin gate.","Method":"GET","Path":"/v1/o11y/orgs/me","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-my-service-account","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.","Method":"GET","Path":"/v1/o11y/service_accounts/me","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-my-user","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.","Method":"GET","Path":"/v1/o11y/users/me","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-org-preference","OperationID":"GetOrgPreference","Summary":"Returns one org-scoped preference, by name.","Description":"Returns one org-scoped preference, by name. Admin gate.","Method":"GET","Path":"/v1/o11y/org/preferences/:name","Args":[{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-overall-state-transitions","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.","Method":"POST","Path":"/v1/o11y/rules/:id/history/overall_status","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"","Required":false},{"Name":"filters","Field":"filters","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order","Field":"order","Type":"string","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"","Required":false},{"Name":"state","Field":"state","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"get-public-dashboard","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.","Method":"GET","Path":"/v1/o11y/dashboards/:id/public","Args":[{"Name":"id","Help":"ID is the resource id from the path."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-public-dashboard-data","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.","Method":"GET","Path":"/v1/o11y/public/dashboards/:id","Args":[{"Name":"id","Help":"ID is the resource id from the path."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-public-dashboard-widget-query-range","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.","Method":"GET","Path":"/v1/o11y/public/dashboards/:id/widgets/:idx/query_range","Args":[{"Name":"id","Help":"ID is the public dashboard id from the path."},{"Name":"idx","Help":"Idx is the widget's index from the path."}],"Flags":[{"Name":"start-time","Field":"startTime","Type":"string","Help":"StartTime is the window start as a millisecond epoch. Used only when the\nshare enables a caller-chosen time range.","Required":false},{"Name":"end-time","Field":"endTime","Type":"string","Help":"EndTime is the window end as a millisecond epoch. Used only when the share\nenables a caller-chosen time range.","Required":false}],"Example":null},{"Service":"o11y","Name":"get-quick-filters","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.","Method":"GET","Path":"/v1/o11y/orgs/me/filters","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-role","OperationID":"GetRole","Summary":"Returns one role with the transaction groups it grants.","Description":"Returns one role with the transaction groups it grants.","Method":"GET","Path":"/v1/o11y/roles/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-route-policy-by-id","OperationID":"GetRoutePolicyByID","Summary":"Returns one route policy, by id.","Description":"Returns one route policy, by id. Viewer gate.","Method":"GET","Path":"/v1/o11y/route_policies/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-rule-by-id","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.","Method":"GET","Path":"/v1/o11y/rules/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-rule-history-filter-keys","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.","Method":"GET","Path":"/v1/o11y/rules/:id/history/filter_keys","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"start-unix-milli","Field":"startUnixMilli","Type":"integer","Help":"StartUnixMilli is the window start, unix milliseconds.","Required":false},{"Name":"end-unix-milli","Field":"endUnixMilli","Type":"integer","Help":"EndUnixMilli is the window end, unix milliseconds.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the keys to those containing it.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many keys come back. Absent means 50, capped at 200.","Required":false}],"Example":null},{"Service":"o11y","Name":"get-rule-history-filter-values","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.","Method":"GET","Path":"/v1/o11y/rules/:id/history/filter_values","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"start-unix-milli","Field":"startUnixMilli","Type":"integer","Help":"StartUnixMilli is the window start, unix milliseconds.","Required":false},{"Name":"end-unix-milli","Field":"endUnixMilli","Type":"integer","Help":"EndUnixMilli is the window end, unix milliseconds.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the keys to those containing it.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many keys come back. Absent means 50, capped at 200.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the label key whose values to list. Required.","Required":true},{"Name":"existing-query","Field":"existingQuery","Type":"string","Help":"ExistingQuery is a filter expression scoping which values appear.","Required":false}],"Example":null},{"Service":"o11y","Name":"get-rule-history-overall-status","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.","Method":"GET","Path":"/v1/o11y/rules/:id/history/overall_status","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window start, unix milliseconds. Required by the runtime.","Required":false},{"Name":"end","Field":"end","Type":"integer","Help":"End is the window end, unix milliseconds. Required by the runtime.","Required":false}],"Example":null},{"Service":"o11y","Name":"get-rule-history-stats","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.","Method":"GET","Path":"/v1/o11y/rules/:id/history/stats","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window start, unix milliseconds. Required by the runtime.","Required":false},{"Name":"end","Field":"end","Type":"integer","Help":"End is the window end, unix milliseconds. Required by the runtime.","Required":false}],"Example":null},{"Service":"o11y","Name":"get-rule-history-timeline","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.","Method":"GET","Path":"/v1/o11y/rules/:id/history/timeline","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window start, unix milliseconds. Required by the runtime.","Required":false},{"Name":"end","Field":"end","Type":"integer","Help":"End is the window end, unix milliseconds. Required by the runtime.","Required":false},{"Name":"state","Field":"state","Type":"string","Help":"State keeps only entries in one alert state, e.g. firing or normal.","Required":false},{"Name":"filter-expression","Field":"filterExpression","Type":"string","Help":"FilterExpression narrows entries to those whose labels match it.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many entries come back. Absent means 50.","Required":false},{"Name":"order","Field":"order","Type":"string","Help":"Order sorts by time, asc or desc.","Required":false},{"Name":"cursor","Field":"cursor","Type":"string","Help":"Cursor resumes a previous page; opaque, returned as nextCursor.","Required":false}],"Example":null},{"Service":"o11y","Name":"get-rule-history-top-contributors","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.","Method":"GET","Path":"/v1/o11y/rules/:id/history/top_contributors","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window start, unix milliseconds. Required by the runtime.","Required":false},{"Name":"end","Field":"end","Type":"integer","Help":"End is the window end, unix milliseconds. Required by the runtime.","Required":false}],"Example":null},{"Service":"o11y","Name":"get-rule-state-history","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.","Method":"POST","Path":"/v1/o11y/rules/:id/history/timeline","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"","Required":false},{"Name":"filters","Field":"filters","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order","Field":"order","Type":"string","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"","Required":false},{"Name":"state","Field":"state","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"get-rule-state-history-top-contributors","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.","Method":"POST","Path":"/v1/o11y/rules/:id/history/top_contributors","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"","Required":false},{"Name":"filters","Field":"filters","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order","Field":"order","Type":"string","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"","Required":false},{"Name":"state","Field":"state","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"get-rule-stats","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.","Method":"POST","Path":"/v1/o11y/rules/:id/history/stats","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"","Required":false},{"Name":"filters","Field":"filters","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order","Field":"order","Type":"string","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"","Required":false},{"Name":"state","Field":"state","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"get-service","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.","Method":"GET","Path":"/v1/o11y/cloud_integrations/:cloud_provider/services/:service_id","Args":[{"Name":"cloud_provider","Help":""},{"Name":"service_id","Help":""}],"Flags":[{"Name":"cloud-integration-id","Field":"cloud_integration_id","Type":"string","Help":"CloudIntegrationID, when set, scopes the service to one cloud integration.","Required":false}],"Example":null},{"Service":"o11y","Name":"get-service-account","OperationID":"GetServiceAccount","Summary":"Returns one service account with the roles it holds.","Description":"Returns one service account with the roles it holds.","Method":"GET","Path":"/v1/o11y/service_accounts/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-service-account-roles","OperationID":"GetServiceAccountRoles","Summary":"Lists the roles a service account holds.","Description":"Lists the roles a service account holds.","Method":"GET","Path":"/v1/o11y/service_accounts/:id/roles","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-signal-filters","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.","Method":"GET","Path":"/v1/o11y/orgs/me/filters/:signal","Args":[{"Name":"signal","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-trace-aggregations","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.","Method":"POST","Path":"/v1/o11y/traces/:traceId/aggregations","Args":[{"Name":"traceId","Help":""}],"Flags":[{"Name":"aggregations","Field":"aggregations","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"get-trace-fields","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.","Method":"GET","Path":"/v1/o11y/traces/fields","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-trace-funnel","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.","Method":"GET","Path":"/v1/o11y/trace-funnels/:funnel_id","Args":[{"Name":"funnel_id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-trace-funnel-error-traces","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\".","Method":"POST","Path":"/v1/o11y/trace-funnels/:funnel_id/analytics/error-traces","Args":[{"Name":"funnel_id","Help":""}],"Flags":[{"Name":"end-time","Field":"end_time","Type":"integer","Help":"","Required":false},{"Name":"start-time","Field":"start_time","Type":"integer","Help":"","Required":false},{"Name":"step-end","Field":"step_end","Type":"integer","Help":"","Required":false},{"Name":"step-start","Field":"step_start","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"get-trace-funnel-overview","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.","Method":"POST","Path":"/v1/o11y/trace-funnels/:funnel_id/analytics/overview","Args":[{"Name":"funnel_id","Help":""}],"Flags":[{"Name":"end-time","Field":"end_time","Type":"integer","Help":"","Required":false},{"Name":"start-time","Field":"start_time","Type":"integer","Help":"","Required":false},{"Name":"step-end","Field":"step_end","Type":"integer","Help":"","Required":false},{"Name":"step-start","Field":"step_start","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"get-trace-funnel-slow-traces","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\".","Method":"POST","Path":"/v1/o11y/trace-funnels/:funnel_id/analytics/slow-traces","Args":[{"Name":"funnel_id","Help":""}],"Flags":[{"Name":"end-time","Field":"end_time","Type":"integer","Help":"","Required":false},{"Name":"start-time","Field":"start_time","Type":"integer","Help":"","Required":false},{"Name":"step-end","Field":"step_end","Type":"integer","Help":"","Required":false},{"Name":"step-start","Field":"step_start","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"get-trace-funnel-step-metrics","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.","Method":"POST","Path":"/v1/o11y/trace-funnels/:funnel_id/analytics/steps","Args":[{"Name":"funnel_id","Help":""}],"Flags":[{"Name":"end-time","Field":"end_time","Type":"integer","Help":"","Required":false},{"Name":"start-time","Field":"start_time","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"get-trace-funnel-step-overview","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.","Method":"POST","Path":"/v1/o11y/trace-funnels/:funnel_id/analytics/steps/overview","Args":[{"Name":"funnel_id","Help":""}],"Flags":[{"Name":"end-time","Field":"end_time","Type":"integer","Help":"","Required":false},{"Name":"start-time","Field":"start_time","Type":"integer","Help":"","Required":false},{"Name":"step-end","Field":"step_end","Type":"integer","Help":"","Required":false},{"Name":"step-start","Field":"step_start","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"get-user-preference","OperationID":"GetUserPreference","Summary":"Returns one preference of the calling user, by name.","Description":"Returns one preference of the calling user, by name.\nViewer gate.","Method":"GET","Path":"/v1/o11y/user/preferences/:name","Args":[{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"get-waterfall-v4","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.","Method":"POST","Path":"/v1/o11y/traces/:traceId/waterfall","Args":[{"Name":"traceId","Help":""}],"Flags":[{"Name":"selected-span-id","Field":"selectedSpanId","Type":"string","Help":"","Required":false},{"Name":"uncollapsed-spans","Field":"uncollapsedSpans","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/global/config","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/health","Args":[],"Flags":[{"Name":"live","Field":"live","Type":"boolean","Help":"Live also checks the datastore connection; an unreachable store refuses\nwith 503.","Required":false}],"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/healthz","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"hosts-attribute-keys-list","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.","Method":"GET","Path":"/v1/o11y/hosts/attribute_keys","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the keys must appear on.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the keys to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many keys come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"hosts-attribute-values-list","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.","Method":"GET","Path":"/v1/o11y/hosts/attribute_values","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the values must appear on.","Required":false},{"Name":"attribute-key","Field":"attributeKey","Type":"string","Help":"AttributeKey is the key whose values to list.","Required":false},{"Name":"filter-attribute-key-data-type","Field":"filterAttributeKeyDataType","Type":"string","Help":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the values to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the search to one kind of key — tag or resource.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many values come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"hosts-list-create","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.","Method":"POST","Path":"/v1/o11y/hosts/list","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"epoch time in ms","Required":false},{"Name":"filters","Field":"filters","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"epoch time in ms","Required":false}],"Example":null},{"Service":"o11y","Name":"infra-monitoring-checks-list","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.","Method":"GET","Path":"/v1/o11y/infra_monitoring/checks","Args":[],"Flags":[{"Name":"type","Field":"type","Type":"string","Help":"Type is the section to check — hosts, processes, pods, nodes,\ndeployments, daemonsets, statefulsets, jobs, namespaces, clusters or\nvolumes. Required.","Required":true}],"Example":null},{"Service":"o11y","Name":"infra-monitoring-clusters-create","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.","Method":"POST","Path":"/v1/o11y/infra_monitoring/clusters","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"","Required":false},{"Name":"filter","Field":"filter","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"infra-monitoring-daemonsets-create","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.","Method":"POST","Path":"/v1/o11y/infra_monitoring/daemonsets","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"","Required":false},{"Name":"filter","Field":"filter","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"infra-monitoring-deployments-create","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.","Method":"POST","Path":"/v1/o11y/infra_monitoring/deployments","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"","Required":false},{"Name":"filter","Field":"filter","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"infra-monitoring-hosts-create","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.","Method":"POST","Path":"/v1/o11y/infra_monitoring/hosts","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"","Required":false},{"Name":"filter","Field":"filter","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"infra-monitoring-jobs-create","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.","Method":"POST","Path":"/v1/o11y/infra_monitoring/jobs","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"","Required":false},{"Name":"filter","Field":"filter","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"infra-monitoring-namespaces-create","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.","Method":"POST","Path":"/v1/o11y/infra_monitoring/namespaces","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"","Required":false},{"Name":"filter","Field":"filter","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"infra-monitoring-nodes-create","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.","Method":"POST","Path":"/v1/o11y/infra_monitoring/nodes","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"","Required":false},{"Name":"filter","Field":"filter","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"infra-monitoring-pods-create","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.","Method":"POST","Path":"/v1/o11y/infra_monitoring/pods","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"","Required":false},{"Name":"filter","Field":"filter","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"infra-monitoring-pvcs-create","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.","Method":"POST","Path":"/v1/o11y/infra_monitoring/pvcs","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"","Required":false},{"Name":"filter","Field":"filter","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"infra-monitoring-statefulsets-create","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.","Method":"POST","Path":"/v1/o11y/infra_monitoring/statefulsets","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"","Required":false},{"Name":"filter","Field":"filter","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/infra_onboarding/k8s/status","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"inspect-metrics","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.","Method":"POST","Path":"/v1/o11y/metrics/inspect","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"End is the end of the window as a Unix timestamp in milliseconds, at most\nthirty minutes after start. Required.","Required":true},{"Name":"filter","Field":"filter","Type":"json","Help":"Filter narrows the series returned.","Required":false},{"Name":"metric-name","Field":"metricName","Type":"string","Help":"MetricName is the metric to inspect. Required.","Required":true},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the start of the window as a Unix timestamp in milliseconds. Required.","Required":true}],"Example":null},{"Service":"o11y","Name":"install-integration","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.","Method":"POST","Path":"/v1/o11y/integrations/install","Args":[],"Flags":[{"Name":"config","Field":"config","Type":"json","Help":"","Required":false},{"Name":"integration-id","Field":"integration_id","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"jobs-attribute-keys-list","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.","Method":"GET","Path":"/v1/o11y/jobs/attribute_keys","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the keys must appear on.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the keys to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many keys come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"jobs-attribute-values-list","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.","Method":"GET","Path":"/v1/o11y/jobs/attribute_values","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the values must appear on.","Required":false},{"Name":"attribute-key","Field":"attributeKey","Type":"string","Help":"AttributeKey is the key whose values to list.","Required":false},{"Name":"filter-attribute-key-data-type","Field":"filterAttributeKeyDataType","Type":"string","Help":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the values to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the search to one kind of key — tag or resource.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many values come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"jobs-list-create","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.","Method":"POST","Path":"/v1/o11y/jobs/list","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"epoch time in ms","Required":false},{"Name":"filters","Field":"filters","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"epoch time in ms","Required":false}],"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/licenses/active","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"licenses-list","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.","Method":"GET","Path":"/v1/o11y/licenses","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"list-account-services-metadata","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.","Method":"GET","Path":"/v1/o11y/cloud_integrations/:cloud_provider/accounts/:id/services","Args":[{"Name":"cloud_provider","Help":""},{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"list-accounts","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.","Method":"GET","Path":"/v1/o11y/cloud_integrations/:cloud_provider/accounts","Args":[{"Name":"cloud_provider","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"list-channels","OperationID":"ListChannels","Summary":"Lists the org's notification channels.","Description":"Lists the org's notification channels. Viewer gate.","Method":"GET","Path":"/v1/o11y/channels","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"list-dashboard-views","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.","Method":"GET","Path":"/v1/o11y/dashboard_views","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"list-dashboards-for-user-v2","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.","Method":"GET","Path":"/v1/o11y/users/me/dashboards","Args":[],"Flags":[{"Name":"query","Field":"query","Type":"string","Help":"Query is the filter DSL over dashboard columns and tags, e.g.\n`name:cpu source:user`. Empty lists everything.","Required":false},{"Name":"sort","Field":"sort","Type":"string","Help":"Sort is the sort field: updated_at, created_at or name. Empty sorts by\nupdated_at.","Required":false},{"Name":"order","Field":"order","Type":"string","Help":"Order is the sort direction: asc or desc. Empty orders desc.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many dashboards come back. Zero means the default of 20;\nthe runtime caps it at 200.","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset is how many dashboards to skip for pagination.","Required":false}],"Example":null},{"Service":"o11y","Name":"list-dashboards-v2","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.","Method":"GET","Path":"/v1/o11y/dashboards","Args":[],"Flags":[{"Name":"query","Field":"query","Type":"string","Help":"Query is the filter DSL over dashboard columns and tags, e.g.\n`name:cpu source:user`. Empty lists everything.","Required":false},{"Name":"sort","Field":"sort","Type":"string","Help":"Sort is the sort field: updated_at, created_at or name. Empty sorts by\nupdated_at.","Required":false},{"Name":"order","Field":"order","Type":"string","Help":"Order is the sort direction: asc or desc. Empty orders desc.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many dashboards come back. Zero means the default of 20;\nthe runtime caps it at 200.","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset is how many dashboards to skip for pagination.","Required":false}],"Example":null},{"Service":"o11y","Name":"list-downtime-schedules","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.","Method":"GET","Path":"/v1/o11y/downtime_schedules","Args":[],"Flags":[{"Name":"active","Field":"active","Type":"string","Help":"Active, when \"true\" or \"false\", keeps only the active or inactive windows.\nAbsent lists all.","Required":false},{"Name":"recurring","Field":"recurring","Type":"string","Help":"Recurring, when \"true\" or \"false\", keeps only the recurring or one-off\nwindows. Absent lists all.","Required":false}],"Example":null},{"Service":"o11y","Name":"list-errors-create","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.","Method":"POST","Path":"/v1/o11y/listErrors","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"string","Help":"End is the window end, as a nanosecond epoch spelled as a string.","Required":false},{"Name":"exception-type","Field":"exceptionType","Type":"string","Help":"ExceptionType narrows to one exception type.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many exception groups come back. Required, non-zero.","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset is how many groups to skip.","Required":false},{"Name":"order","Field":"order","Type":"string","Help":"Order is the direction: ascending or descending.","Required":false},{"Name":"order-param","Field":"orderParam","Type":"string","Help":"OrderParam is the column to order by, e.g. exceptionCount, lastSeen.","Required":false},{"Name":"service-name","Field":"serviceName","Type":"string","Help":"ServiceName narrows to one reporting service.","Required":false},{"Name":"start","Field":"start","Type":"string","Help":"Start is the window start, as a nanosecond epoch spelled as a string.","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"Tags narrow the scan to spans carrying the given tag values.","Required":false}],"Example":null},{"Service":"o11y","Name":"list-integrations","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.","Method":"GET","Path":"/v1/o11y/integrations","Args":[],"Flags":[{"Name":"is-installed","Field":"is_installed","Type":"string","Help":"IsInstalled, when \"true\" or \"false\", keeps only integrations in that\ninstalled state; empty lists them all.","Required":false}],"Example":null},{"Service":"o11y","Name":"list-llm-annotations","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.","Method":"GET","Path":"/v1/o11y/llm/annotation","Args":[],"Flags":[{"Name":"trace-id","Field":"traceId","Type":"string","Help":"TraceID narrows to annotations on one trace.","Required":false},{"Name":"queue","Field":"queue","Type":"string","Help":"Queue narrows to one review queue.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status narrows to one review status, e.g. PENDING.","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset is how many rows to skip, for paging.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many rows come back.","Required":false}],"Example":null},{"Service":"o11y","Name":"list-llm-observations","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.","Method":"GET","Path":"/v1/o11y/llm/observations","Args":[],"Flags":[{"Name":"start","Field":"start","Type":"integer","Help":"Start is the start of the window as a unix-millisecond epoch. Zero means\n24h before the end.","Required":false},{"Name":"end","Field":"end","Type":"integer","Help":"End is the end of the window as a unix-millisecond epoch. Zero means now.","Required":false},{"Name":"trace-id","Field":"traceId","Type":"string","Help":"TraceID narrows the view to one trace.","Required":false},{"Name":"session-id","Field":"sessionId","Type":"string","Help":"SessionID narrows the view to one conversation.","Required":false},{"Name":"user-id","Field":"userId","Type":"string","Help":"UserID narrows the view to one end user.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name narrows the view to observations of one name.","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"Model narrows the view to one model.","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset is how many rows to skip, for paging.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many rows come back.","Required":false}],"Example":null},{"Service":"o11y","Name":"list-llm-pricing-rules","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.","Method":"GET","Path":"/v1/o11y/llm_pricing_rules","Args":[],"Flags":[{"Name":"q","Field":"q","Type":"string","Help":"Search matches rules by model or provider.","Required":false},{"Name":"is-override","Field":"isOverride","Type":"string","Help":"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\".","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset is how many rows to skip, for paging.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many rows come back.","Required":false}],"Example":null},{"Service":"o11y","Name":"list-llm-scores","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.","Method":"GET","Path":"/v1/o11y/llm/scores","Args":[],"Flags":[{"Name":"trace-id","Field":"traceId","Type":"string","Help":"TraceID narrows to scores on one trace.","Required":false},{"Name":"observation-id","Field":"observationId","Type":"string","Help":"ObservationID narrows to scores on one observation.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name narrows to scores of one name.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source narrows to scores from one source, e.g. API, EVAL.","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset is how many rows to skip, for paging.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many rows come back.","Required":false}],"Example":null},{"Service":"o11y","Name":"list-llm-sessions","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.","Method":"GET","Path":"/v1/o11y/llm/sessions","Args":[],"Flags":[{"Name":"start","Field":"start","Type":"integer","Help":"Start is the start of the window as a unix-millisecond epoch. Zero means\n24h before the end.","Required":false},{"Name":"end","Field":"end","Type":"integer","Help":"End is the end of the window as a unix-millisecond epoch. Zero means now.","Required":false},{"Name":"trace-id","Field":"traceId","Type":"string","Help":"TraceID narrows the view to one trace.","Required":false},{"Name":"session-id","Field":"sessionId","Type":"string","Help":"SessionID narrows the view to one conversation.","Required":false},{"Name":"user-id","Field":"userId","Type":"string","Help":"UserID narrows the view to one end user.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name narrows the view to observations of one name.","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"Model narrows the view to one model.","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset is how many rows to skip, for paging.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many rows come back.","Required":false}],"Example":null},{"Service":"o11y","Name":"list-llm-traces","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.","Method":"GET","Path":"/v1/o11y/llm/traces","Args":[],"Flags":[{"Name":"start","Field":"start","Type":"integer","Help":"Start is the start of the window as a unix-millisecond epoch. Zero means\n24h before the end.","Required":false},{"Name":"end","Field":"end","Type":"integer","Help":"End is the end of the window as a unix-millisecond epoch. Zero means now.","Required":false},{"Name":"trace-id","Field":"traceId","Type":"string","Help":"TraceID narrows the view to one trace.","Required":false},{"Name":"session-id","Field":"sessionId","Type":"string","Help":"SessionID narrows the view to one conversation.","Required":false},{"Name":"user-id","Field":"userId","Type":"string","Help":"UserID narrows the view to one end user.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name narrows the view to observations of one name.","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"Model narrows the view to one model.","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset is how many rows to skip, for paging.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many rows come back.","Required":false}],"Example":null},{"Service":"o11y","Name":"list-llm-users","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.","Method":"GET","Path":"/v1/o11y/llm/users","Args":[],"Flags":[{"Name":"start","Field":"start","Type":"integer","Help":"Start is the start of the window as a unix-millisecond epoch. Zero means\n24h before the end.","Required":false},{"Name":"end","Field":"end","Type":"integer","Help":"End is the end of the window as a unix-millisecond epoch. Zero means now.","Required":false},{"Name":"trace-id","Field":"traceId","Type":"string","Help":"TraceID narrows the view to one trace.","Required":false},{"Name":"session-id","Field":"sessionId","Type":"string","Help":"SessionID narrows the view to one conversation.","Required":false},{"Name":"user-id","Field":"userId","Type":"string","Help":"UserID narrows the view to one end user.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name narrows the view to observations of one name.","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"Model narrows the view to one model.","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset is how many rows to skip, for paging.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many rows come back.","Required":false}],"Example":null},{"Service":"o11y","Name":"list-metric-reduction-rules","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.","Method":"GET","Path":"/v1/o11y/metric_reduction_rules","Args":[],"Flags":[{"Name":"order-by","Field":"orderBy","Type":"string","Help":"OrderBy sorts the page: metric, ingested_volume, reduced_volume or\nlast_updated. Unset means ingested_volume.","Required":false},{"Name":"order","Field":"order","Type":"string","Help":"Order is asc or desc. Unset means desc.","Required":false},{"Name":"search","Field":"search","Type":"string","Help":"Search narrows the page to rules whose metric name contains it.","Required":false},{"Name":"metric-name","Field":"metricName","Type":"string","Help":"MetricName narrows the page to one metric's rule.","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset is how many rules to skip, for paging.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many rules come back, at most 1000. Unset means 10.","Required":false}],"Example":null},{"Service":"o11y","Name":"list-metrics","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.","Method":"GET","Path":"/v1/o11y/metrics","Args":[],"Flags":[{"Name":"start","Field":"start","Type":"integer","Help":"Start is the start of the window as a Unix timestamp in milliseconds.","Required":false},{"Name":"end","Field":"end","Type":"integer","Help":"End is the end of the window as a Unix timestamp in milliseconds.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many metrics come back; unset means 100, at most 5000.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the page to metric names containing it.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source narrows the page by ingestion source.","Required":false}],"Example":null},{"Service":"o11y","Name":"list-org-preferences","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.","Method":"GET","Path":"/v1/o11y/org/preferences","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"list-roles","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.","Method":"GET","Path":"/v1/o11y/roles","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"list-rules","OperationID":"ListRules","Summary":"Lists all alert rules with their current evaluation state.","Description":"Lists all alert rules with their current evaluation state. Viewer gate.","Method":"GET","Path":"/v1/o11y/rules","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"list-service-account-keys","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.","Method":"GET","Path":"/v1/o11y/service_accounts/:id/keys","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"list-service-accounts","OperationID":"ListServiceAccounts","Summary":"Lists the caller's org's service accounts.","Description":"Lists the caller's org's service accounts.","Method":"GET","Path":"/v1/o11y/service_accounts","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"list-services-metadata","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.","Method":"GET","Path":"/v1/o11y/cloud_integrations/:cloud_provider/services","Args":[{"Name":"cloud_provider","Help":""}],"Flags":[{"Name":"cloud-integration-id","Field":"cloud_integration_id","Type":"string","Help":"CloudIntegrationID, when set, scopes the listing to one cloud integration.","Required":false}],"Example":null},{"Service":"o11y","Name":"list-span-mapper-groups","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.","Method":"GET","Path":"/v1/o11y/span_mapper_groups","Args":[],"Flags":[{"Name":"enabled","Field":"enabled","Type":"boolean","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"list-span-mappers","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.","Method":"GET","Path":"/v1/o11y/span_mapper_groups/:groupId/span_mappers","Args":[{"Name":"groupId","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"list-trace-funnels","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.","Method":"GET","Path":"/v1/o11y/trace-funnels/list","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"list-user-preferences","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.","Method":"GET","Path":"/v1/o11y/user/preferences","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/livez","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"lock-dashboard-v2","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.","Method":"PUT","Path":"/v1/o11y/dashboards/:id/lock","Args":[{"Name":"id","Help":"ID is the resource id from the path."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/login","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/logs/aggregate","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"logs-fields-create","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.","Method":"POST","Path":"/v1/o11y/logs/fields","Args":[],"Flags":[{"Name":"data-type","Field":"dataType","Type":"string","Help":"DataType is the field's data type, e.g. string, int64, float64, bool.\nRequired.","Required":true},{"Name":"index","Field":"index","Type":"string","Help":"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.","Required":false},{"Name":"index-granularity","Field":"indexGranularity","Type":"integer","Help":"IndexGranularity is the index granularity in rows.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the field to tune. Required.","Required":true},{"Name":"selected","Field":"selected","Type":"boolean","Help":"Selected materializes the field as its own column when true.","Required":false},{"Name":"type","Field":"type","Type":"string","Help":"Type is where the field lives: attributes or resources. Required.","Required":true}],"Example":null},{"Service":"o11y","Name":"logs-fields-list","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.","Method":"GET","Path":"/v1/o11y/logs/fields","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"logs-list","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.","Method":"GET","Path":"/v1/o11y/logs","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many records come back. Zero means the default of 100.","Required":false},{"Name":"timestamp-start","Field":"timestampStart","Type":"integer","Help":"TimestampStart is the start of the window as a nanosecond epoch. Zero\nmeans fifteen minutes before the end.","Required":false},{"Name":"timestamp-end","Field":"timestampEnd","Type":"integer","Help":"TimestampEnd is the end of the window as a nanosecond epoch. Zero means\nnow.","Required":false}],"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/logs/livetail","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"logs-pipelines-create","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.","Method":"POST","Path":"/v1/o11y/logs/pipelines","Args":[],"Flags":[{"Name":"pipelines","Field":"pipelines","Type":"json","Help":"Pipelines are the pipelines the new version holds, in order.","Required":false}],"Example":null},{"Service":"o11y","Name":"logs-pipelines-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.","Method":"GET","Path":"/v1/o11y/logs/pipelines/:version","Args":[{"Name":"version","Help":"Version is the config version to read — a positive number, or \"latest\"."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"logs-pipelines-preview-create","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.","Method":"POST","Path":"/v1/o11y/logs/pipelines/preview","Args":[],"Flags":[{"Name":"logs","Field":"logs","Type":"json","Help":"Logs are the sample records to transform.","Required":false},{"Name":"pipelines","Field":"pipelines","Type":"json","Help":"Pipelines are the pipelines to simulate, in order.","Required":false}],"Example":null},{"Service":"o11y","Name":"logs-promote-paths-create","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.","Method":"POST","Path":"/v1/o11y/logs/promote_paths","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"logs-promote-paths-list","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.","Method":"GET","Path":"/v1/o11y/logs/promote_paths","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"messaging-queues-kafka-consumer-lag-consumer-details-create","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.","Method":"POST","Path":"/v1/o11y/messaging-queues/kafka/consumer-lag/consumer-details","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"End is the window's end, epoch nanoseconds.","Required":false},{"Name":"eval-time","Field":"eval_time","Type":"integer","Help":"EvalTime bounds the span-evaluation scan, nanoseconds; only the\nspan/evaluation view reads it.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window's start, epoch nanoseconds.","Required":false},{"Name":"variables","Field":"variables","Type":"json","Help":"Variables name what the view drills into — topic, partition, service,\nconsumer_group — keyed by the name the view expects.","Required":false}],"Example":null},{"Service":"o11y","Name":"messaging-queues-kafka-consumer-lag-network-latency-create","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.","Method":"POST","Path":"/v1/o11y/messaging-queues/kafka/consumer-lag/network-latency","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"End is the window's end, epoch nanoseconds.","Required":false},{"Name":"eval-time","Field":"eval_time","Type":"integer","Help":"EvalTime bounds the span-evaluation scan, nanoseconds; only the\nspan/evaluation view reads it.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window's start, epoch nanoseconds.","Required":false},{"Name":"variables","Field":"variables","Type":"json","Help":"Variables name what the view drills into — topic, partition, service,\nconsumer_group — keyed by the name the view expects.","Required":false}],"Example":null},{"Service":"o11y","Name":"messaging-queues-kafka-consumer-lag-producer-details-create","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.","Method":"POST","Path":"/v1/o11y/messaging-queues/kafka/consumer-lag/producer-details","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"End is the window's end, epoch nanoseconds.","Required":false},{"Name":"eval-time","Field":"eval_time","Type":"integer","Help":"EvalTime bounds the span-evaluation scan, nanoseconds; only the\nspan/evaluation view reads it.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window's start, epoch nanoseconds.","Required":false},{"Name":"variables","Field":"variables","Type":"json","Help":"Variables name what the view drills into — topic, partition, service,\nconsumer_group — keyed by the name the view expects.","Required":false}],"Example":null},{"Service":"o11y","Name":"messaging-queues-kafka-onboarding-consumers-create","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.","Method":"POST","Path":"/v1/o11y/messaging-queues/kafka/onboarding/consumers","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"End is the window's end, epoch nanoseconds.","Required":false},{"Name":"eval-time","Field":"eval_time","Type":"integer","Help":"EvalTime bounds the span-evaluation scan, nanoseconds; only the\nspan/evaluation view reads it.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window's start, epoch nanoseconds.","Required":false},{"Name":"variables","Field":"variables","Type":"json","Help":"Variables name what the view drills into — topic, partition, service,\nconsumer_group — keyed by the name the view expects.","Required":false}],"Example":null},{"Service":"o11y","Name":"messaging-queues-kafka-onboarding-kafka-create","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.","Method":"POST","Path":"/v1/o11y/messaging-queues/kafka/onboarding/kafka","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"End is the window's end, epoch nanoseconds.","Required":false},{"Name":"eval-time","Field":"eval_time","Type":"integer","Help":"EvalTime bounds the span-evaluation scan, nanoseconds; only the\nspan/evaluation view reads it.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window's start, epoch nanoseconds.","Required":false},{"Name":"variables","Field":"variables","Type":"json","Help":"Variables name what the view drills into — topic, partition, service,\nconsumer_group — keyed by the name the view expects.","Required":false}],"Example":null},{"Service":"o11y","Name":"messaging-queues-kafka-onboarding-producers-create","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.","Method":"POST","Path":"/v1/o11y/messaging-queues/kafka/onboarding/producers","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"End is the window's end, epoch nanoseconds.","Required":false},{"Name":"eval-time","Field":"eval_time","Type":"integer","Help":"EvalTime bounds the span-evaluation scan, nanoseconds; only the\nspan/evaluation view reads it.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window's start, epoch nanoseconds.","Required":false},{"Name":"variables","Field":"variables","Type":"json","Help":"Variables name what the view drills into — topic, partition, service,\nconsumer_group — keyed by the name the view expects.","Required":false}],"Example":null},{"Service":"o11y","Name":"messaging-queues-kafka-partition-latency-consumer-create","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.","Method":"POST","Path":"/v1/o11y/messaging-queues/kafka/partition-latency/consumer","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"End is the window's end, epoch nanoseconds.","Required":false},{"Name":"eval-time","Field":"eval_time","Type":"integer","Help":"EvalTime bounds the span-evaluation scan, nanoseconds; only the\nspan/evaluation view reads it.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window's start, epoch nanoseconds.","Required":false},{"Name":"variables","Field":"variables","Type":"json","Help":"Variables name what the view drills into — topic, partition, service,\nconsumer_group — keyed by the name the view expects.","Required":false}],"Example":null},{"Service":"o11y","Name":"messaging-queues-kafka-partition-latency-overview-create","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.","Method":"POST","Path":"/v1/o11y/messaging-queues/kafka/partition-latency/overview","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"End is the window's end, epoch nanoseconds.","Required":false},{"Name":"eval-time","Field":"eval_time","Type":"integer","Help":"EvalTime bounds the span-evaluation scan, nanoseconds; only the\nspan/evaluation view reads it.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window's start, epoch nanoseconds.","Required":false},{"Name":"variables","Field":"variables","Type":"json","Help":"Variables name what the view drills into — topic, partition, service,\nconsumer_group — keyed by the name the view expects.","Required":false}],"Example":null},{"Service":"o11y","Name":"messaging-queues-kafka-span-evaluation-create","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.","Method":"POST","Path":"/v1/o11y/messaging-queues/kafka/span/evaluation","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"End is the window's end, epoch nanoseconds.","Required":false},{"Name":"eval-time","Field":"eval_time","Type":"integer","Help":"EvalTime bounds the span-evaluation scan, nanoseconds; only the\nspan/evaluation view reads it.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window's start, epoch nanoseconds.","Required":false},{"Name":"variables","Field":"variables","Type":"json","Help":"Variables name what the view drills into — topic, partition, service,\nconsumer_group — keyed by the name the view expects.","Required":false}],"Example":null},{"Service":"o11y","Name":"messaging-queues-kafka-topic-throughput-consumer-create","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.","Method":"POST","Path":"/v1/o11y/messaging-queues/kafka/topic-throughput/consumer","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"End is the window's end, epoch nanoseconds.","Required":false},{"Name":"eval-time","Field":"eval_time","Type":"integer","Help":"EvalTime bounds the span-evaluation scan, nanoseconds; only the\nspan/evaluation view reads it.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window's start, epoch nanoseconds.","Required":false},{"Name":"variables","Field":"variables","Type":"json","Help":"Variables name what the view drills into — topic, partition, service,\nconsumer_group — keyed by the name the view expects.","Required":false}],"Example":null},{"Service":"o11y","Name":"messaging-queues-kafka-topic-throughput-consumer-details-create","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.","Method":"POST","Path":"/v1/o11y/messaging-queues/kafka/topic-throughput/consumer-details","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"End is the window's end, epoch nanoseconds.","Required":false},{"Name":"eval-time","Field":"eval_time","Type":"integer","Help":"EvalTime bounds the span-evaluation scan, nanoseconds; only the\nspan/evaluation view reads it.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window's start, epoch nanoseconds.","Required":false},{"Name":"variables","Field":"variables","Type":"json","Help":"Variables name what the view drills into — topic, partition, service,\nconsumer_group — keyed by the name the view expects.","Required":false}],"Example":null},{"Service":"o11y","Name":"messaging-queues-kafka-topic-throughput-producer-create","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.","Method":"POST","Path":"/v1/o11y/messaging-queues/kafka/topic-throughput/producer","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"End is the window's end, epoch nanoseconds.","Required":false},{"Name":"eval-time","Field":"eval_time","Type":"integer","Help":"EvalTime bounds the span-evaluation scan, nanoseconds; only the\nspan/evaluation view reads it.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window's start, epoch nanoseconds.","Required":false},{"Name":"variables","Field":"variables","Type":"json","Help":"Variables name what the view drills into — topic, partition, service,\nconsumer_group — keyed by the name the view expects.","Required":false}],"Example":null},{"Service":"o11y","Name":"messaging-queues-kafka-topic-throughput-producer-details-create","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.","Method":"POST","Path":"/v1/o11y/messaging-queues/kafka/topic-throughput/producer-details","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"End is the window's end, epoch nanoseconds.","Required":false},{"Name":"eval-time","Field":"eval_time","Type":"integer","Help":"EvalTime bounds the span-evaluation scan, nanoseconds; only the\nspan/evaluation view reads it.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window's start, epoch nanoseconds.","Required":false},{"Name":"variables","Field":"variables","Type":"json","Help":"Variables name what the view drills into — topic, partition, service,\nconsumer_group — keyed by the name the view expects.","Required":false}],"Example":null},{"Service":"o11y","Name":"messaging-queues-queue-overview-create","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.","Method":"POST","Path":"/v1/o11y/messaging-queues/queue-overview","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"End is the window's end, epoch nanoseconds.","Required":false},{"Name":"filters","Field":"filters","Type":"json","Help":"Filters narrow the rows by span attribute; null means all rows.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many rows come back.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window's start, epoch nanoseconds.","Required":false}],"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/metric/metric_metadata","Args":[],"Flags":[{"Name":"metric-name","Field":"metricName","Type":"string","Help":"MetricName is the metric to read.","Required":false},{"Name":"service-name","Field":"serviceName","Type":"string","Help":"ServiceName scopes the metadata to the metric as one service reports it.","Required":false}],"Example":null},{"Service":"o11y","Name":"namespaces-attribute-keys-list","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.","Method":"GET","Path":"/v1/o11y/namespaces/attribute_keys","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the keys must appear on.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the keys to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many keys come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"namespaces-attribute-values-list","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.","Method":"GET","Path":"/v1/o11y/namespaces/attribute_values","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the values must appear on.","Required":false},{"Name":"attribute-key","Field":"attributeKey","Type":"string","Help":"AttributeKey is the key whose values to list.","Required":false},{"Name":"filter-attribute-key-data-type","Field":"filterAttributeKeyDataType","Type":"string","Help":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the values to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the search to one kind of key — tag or resource.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many values come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"namespaces-list-create","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.","Method":"POST","Path":"/v1/o11y/namespaces/list","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"epoch time in ms","Required":false},{"Name":"filters","Field":"filters","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"epoch time in ms","Required":false}],"Example":null},{"Service":"o11y","Name":"next-prev-error-i-ds-list","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.","Method":"GET","Path":"/v1/o11y/nextPrevErrorIDs","Args":[],"Flags":[{"Name":"timestamp","Field":"timestamp","Type":"string","Help":"Timestamp is the instance's time as a nanosecond epoch spelled as a\nstring. Required.","Required":true},{"Name":"group-id","Field":"groupID","Type":"string","Help":"GroupID is the exception group the instance belongs to. Required.","Required":true},{"Name":"error-id","Field":"errorID","Type":"string","Help":"ErrorID is the exception instance id. Required by errorFromErrorID and\nnextPrevErrorIDs; unused by errorFromGroupID.","Required":false}],"Example":null},{"Service":"o11y","Name":"nodes-attribute-keys-list","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.","Method":"GET","Path":"/v1/o11y/nodes/attribute_keys","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the keys must appear on.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the keys to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many keys come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"nodes-attribute-values-list","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.","Method":"GET","Path":"/v1/o11y/nodes/attribute_values","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the values must appear on.","Required":false},{"Name":"attribute-key","Field":"attributeKey","Type":"string","Help":"AttributeKey is the key whose values to list.","Required":false},{"Name":"filter-attribute-key-data-type","Field":"filterAttributeKeyDataType","Type":"string","Help":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the values to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the search to one kind of key — tag or resource.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many values come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"nodes-list-create","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.","Method":"POST","Path":"/v1/o11y/nodes/list","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"epoch time in ms","Required":false},{"Name":"filters","Field":"filters","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"epoch time in ms","Required":false}],"Example":null},{"Service":"o11y","Name":"patch-dashboard-v2","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.","Method":"PATCH","Path":"/v1/o11y/dashboards/:id","Args":[{"Name":"id","Help":"ID is the dashboard id from the path."}],"Flags":[{"Name":"ops","Field":"ops","Type":"json","Help":"Ops are the JSON Patch operations, applied in order. On the wire this IS the\nrequest body — a bare array, not an object.","Required":false}],"Example":null},{"Service":"o11y","Name":"patch-rule-by-id","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.","Method":"PATCH","Path":"/v1/o11y/rules/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"pin-dashboard-v2","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.","Method":"PUT","Path":"/v1/o11y/users/me/dashboards/:id/pins","Args":[{"Name":"id","Help":"ID is the resource id from the path."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"pods-attribute-keys-list","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.","Method":"GET","Path":"/v1/o11y/pods/attribute_keys","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the keys must appear on.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the keys to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many keys come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"pods-attribute-values-list","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.","Method":"GET","Path":"/v1/o11y/pods/attribute_values","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the values must appear on.","Required":false},{"Name":"attribute-key","Field":"attributeKey","Type":"string","Help":"AttributeKey is the key whose values to list.","Required":false},{"Name":"filter-attribute-key-data-type","Field":"filterAttributeKeyDataType","Type":"string","Help":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the values to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the search to one kind of key — tag or resource.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many values come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"pods-list-create","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.","Method":"POST","Path":"/v1/o11y/pods/list","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"epoch time in ms","Required":false},{"Name":"filters","Field":"filters","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"epoch time in ms","Required":false}],"Example":null},{"Service":"o11y","Name":"preview-metric-reduction-rule","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.","Method":"POST","Path":"/v1/o11y/metric_reduction_rules/preview","Args":[],"Flags":[{"Name":"labels","Field":"labels","Type":"json","Help":"Labels are the label names the rule would match. Required, at least one.","Required":true},{"Name":"lookback-ms","Field":"lookbackMs","Type":"integer","Help":"LookbackMs is how far back to sample when estimating.","Required":false},{"Name":"match-type","Field":"matchType","Type":"string","Help":"MatchType is drop or keep. Required.","Required":true},{"Name":"metric-name","Field":"metricName","Type":"string","Help":"MetricName is the metric the rule would govern. Required.","Required":true}],"Example":null},{"Service":"o11y","Name":"processes-attribute-keys-list","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.","Method":"GET","Path":"/v1/o11y/processes/attribute_keys","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the keys must appear on.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the keys to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many keys come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"processes-attribute-values-list","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.","Method":"GET","Path":"/v1/o11y/processes/attribute_values","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the values must appear on.","Required":false},{"Name":"attribute-key","Field":"attributeKey","Type":"string","Help":"AttributeKey is the key whose values to list.","Required":false},{"Name":"filter-attribute-key-data-type","Field":"filterAttributeKeyDataType","Type":"string","Help":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the values to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the search to one kind of key — tag or resource.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many values come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"processes-list-create","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.","Method":"POST","Path":"/v1/o11y/processes/list","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"epoch time in ms","Required":false},{"Name":"filters","Field":"filters","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"epoch time in ms","Required":false}],"Example":null},{"Service":"o11y","Name":"product-metrics-list","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.","Method":"GET","Path":"/v1/o11y/product/metrics","Args":[],"Flags":[{"Name":"product","Field":"product","Type":"string","Help":"Product is the console product slug to read, e.g. \"kms\". Required.","Required":false},{"Name":"range","Field":"range","Type":"integer","Help":"Range is the window in seconds. Default 3600, capped at 604800 (7d).","Required":false},{"Name":"step-sec","Field":"stepSec","Type":"integer","Help":"StepSec is the bucket width in seconds, clamped to [30, 3600]. Absent\npicks ~60 buckets across the range.","Required":false}],"Example":{"product":"kms","range":3600}},{"Service":"o11y","Name":"put-host","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.","Method":"PUT","Path":"/v1/o11y/zeus/hosts","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"put-profile","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.","Method":"PUT","Path":"/v1/o11y/zeus/profiles","Args":[],"Flags":[{"Name":"existing-observability-tool","Field":"existing_observability_tool","Type":"string","Help":"","Required":false},{"Name":"has-existing-observability-tool","Field":"has_existing_observability_tool","Type":"boolean","Help":"","Required":false},{"Name":"logs-scale-per-day-in-gb","Field":"logs_scale_per_day_in_gb","Type":"integer","Help":"","Required":false},{"Name":"number-of-hosts","Field":"number_of_hosts","Type":"integer","Help":"","Required":false},{"Name":"number-of-services","Field":"number_of_services","Type":"integer","Help":"","Required":false},{"Name":"reasons-for-interest-in-o11y","Field":"reasons_for_interest_in_o11y","Type":"json","Help":"","Required":false},{"Name":"timeline-for-migrating-to-o11y","Field":"timeline_for_migrating_to_o11y","Type":"string","Help":"","Required":false},{"Name":"uses-otel","Field":"uses_otel","Type":"boolean","Help":"","Required":false},{"Name":"where-did-you-discover-o11y","Field":"where_did_you_discover_o11y","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"pvcs-attribute-keys-list","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.","Method":"GET","Path":"/v1/o11y/pvcs/attribute_keys","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the keys must appear on.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the keys to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many keys come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"pvcs-attribute-values-list","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.","Method":"GET","Path":"/v1/o11y/pvcs/attribute_values","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the values must appear on.","Required":false},{"Name":"attribute-key","Field":"attributeKey","Type":"string","Help":"AttributeKey is the key whose values to list.","Required":false},{"Name":"filter-attribute-key-data-type","Field":"filterAttributeKeyDataType","Type":"string","Help":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the values to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the search to one kind of key — tag or resource.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many values come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"pvcs-list-create","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.","Method":"POST","Path":"/v1/o11y/pvcs/list","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"epoch time in ms","Required":false},{"Name":"filters","Field":"filters","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"epoch time in ms","Required":false}],"Example":null},{"Service":"o11y","Name":"query-filter-analyze-create","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.","Method":"POST","Path":"/v1/o11y/query_filter/analyze","Args":[],"Flags":[{"Name":"query","Field":"query","Type":"string","Help":"Query is the query text. Required.","Required":true},{"Name":"query-type","Field":"queryType","Type":"string","Help":"QueryType says which language the query is in — promql or the datastore's\nSQL dialect. Required.","Required":true}],"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/query","Args":[],"Flags":[{"Name":"query","Field":"query","Type":"string","Help":"Query is the PromQL expression to evaluate. Required.","Required":true},{"Name":"time","Field":"time","Type":"string","Help":"Time is the evaluation timestamp — epoch seconds or RFC3339. Empty\nevaluates at now.","Required":false},{"Name":"stats","Field":"stats","Type":"string","Help":"Stats set to any non-empty value includes query statistics in the answer.","Required":false},{"Name":"timeout","Field":"timeout","Type":"string","Help":"Timeout caps evaluation time, as a duration in seconds.","Required":false}],"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/query_progress","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"query-range-create","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.","Method":"POST","Path":"/v1/o11y/query_range","Args":[],"Flags":[{"Name":"composite-query","Field":"compositeQuery","Type":"json","Help":"CompositeQuery is the composite query to use for the request.","Required":false},{"Name":"end","Field":"end","Type":"integer","Help":"End is the end time of the query in epoch milliseconds.","Required":false},{"Name":"format-options","Field":"formatOptions","Type":"json","Help":"","Required":false},{"Name":"no-cache","Field":"noCache","Type":"boolean","Help":"NoCache is a flag to disable caching for the request.","Required":false},{"Name":"request-type","Field":"requestType","Type":"json","Help":"RequestType is the type of the request.","Required":false},{"Name":"schema-version","Field":"schemaVersion","Type":"string","Help":"SchemaVersion is the version of the schema to use for the request payload.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the start time of the query in epoch milliseconds.","Required":false},{"Name":"variables","Field":"variables","Type":"json","Help":"Variables is the variables to use for the request.","Required":false}],"Example":null},{"Service":"o11y","Name":"query-range-format-create","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.","Method":"POST","Path":"/v1/o11y/query_range/format","Args":[],"Flags":[{"Name":"composite-query","Field":"compositeQuery","Type":"json","Help":"","Required":false},{"Name":"end","Field":"end","Type":"integer","Help":"","Required":false},{"Name":"format-for-web","Field":"formatForWeb","Type":"boolean","Help":"","Required":false},{"Name":"no-cache","Field":"noCache","Type":"boolean","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"","Required":false},{"Name":"step","Field":"step","Type":"integer","Help":"step is in seconds; used for prometheus queries","Required":false},{"Name":"variables","Field":"variables","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/query_range","Args":[],"Flags":[{"Name":"start","Field":"start","Type":"string","Help":"Start is the window start — a unix timestamp (seconds, with optional\nfraction) or an RFC 3339 time. Required.","Required":true},{"Name":"end","Field":"end","Type":"string","Help":"End is the window end, in the same form as Start, and not before it.\nRequired.","Required":true},{"Name":"step","Field":"step","Type":"string","Help":"Step is the query resolution, e.g. 60s, 1m, 1h — a positive duration.\nRequired.","Required":true},{"Name":"query","Field":"query","Type":"string","Help":"Query is the PromQL expression to evaluate. Required.","Required":true},{"Name":"stats","Field":"stats","Type":"string","Help":"Stats, when \"all\", asks for query statistics alongside the result.","Required":false},{"Name":"timeout","Field":"timeout","Type":"string","Help":"Timeout caps how long the query may run, e.g. 30s, 1m — a positive\nduration. Absent means the server default.","Required":false}],"Example":null},{"Service":"o11y","Name":"query-range-preview-create","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.","Method":"POST","Path":"/v1/o11y/query_range/preview","Args":[],"Flags":[{"Name":"composite-query","Field":"compositeQuery","Type":"json","Help":"CompositeQuery is the composite query to use for the request.","Required":false},{"Name":"end","Field":"end","Type":"integer","Help":"End is the end time of the query in epoch milliseconds.","Required":false},{"Name":"format-options","Field":"formatOptions","Type":"json","Help":"","Required":false},{"Name":"no-cache","Field":"noCache","Type":"boolean","Help":"NoCache is a flag to disable caching for the request.","Required":false},{"Name":"request-type","Field":"requestType","Type":"json","Help":"RequestType is the type of the request.","Required":false},{"Name":"schema-version","Field":"schemaVersion","Type":"string","Help":"SchemaVersion is the version of the schema to use for the request payload.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the start time of the query in epoch milliseconds.","Required":false},{"Name":"variables","Field":"variables","Type":"json","Help":"Variables is the variables to use for the request.","Required":false},{"Name":"verbose","Field":"verbose","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/readyz","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"reviews-create","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.","Method":"POST","Path":"/v1/o11y/reviews","Args":[],"Flags":[{"Name":"description","Field":"description","Type":"string","Help":"Description is optional free text, up to 512 characters.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the queue's display handle, 1–128 printable characters. It must be\nunique within the org's project. Required.","Required":false},{"Name":"score-config-ids","Field":"scoreConfigIds","Type":"json","Help":"ScoreConfigIDs are the eval score-configs reviewers grade against.","Required":false}],"Example":{"name":"hallucination review","scoreConfigIds":["quality"]}},{"Service":"o11y","Name":"reviews-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.","Method":"DELETE","Path":"/v1/o11y/reviews/:id","Args":[{"Name":"id","Help":"ID is the annotation queue to act on, from the path."}],"Flags":null,"Example":{"id":"annq_1"}},{"Service":"o11y","Name":"reviews-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.","Method":"GET","Path":"/v1/o11y/reviews/:id","Args":[{"Name":"id","Help":"ID is the annotation queue to act on, from the path."}],"Flags":null,"Example":{"id":"annq_1"}},{"Service":"o11y","Name":"reviews-items","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.","Method":"POST","Path":"/v1/o11y/reviews/:id/items","Args":[{"Name":"id","Help":"ID is the annotation queue to add to, from the path."}],"Flags":[{"Name":"items","Field":"items","Type":"json","Help":"Items are the objects to enqueue for review, 1–200 per request. Each names\nexactly one object.","Required":false}],"Example":{"id":"annq_1","items":[{"traceId":"tr_1"}]}},{"Service":"o11y","Name":"reviews-items-list","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.","Method":"GET","Path":"/v1/o11y/reviews/:id/items","Args":[{"Name":"id","Help":"ID is the annotation queue whose items to list, from the path."}],"Flags":[{"Name":"status","Field":"status","Type":"string","Help":"Status filters to PENDING or COMPLETED items. Absent returns both.","Required":false},{"Name":"page","Field":"page","Type":"integer","Help":"Page is the 1-based page to read. Default 1.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit is how many rows to return. Default 20, capped at 100.","Required":false}],"Example":{"id":"annq_1","status":"PENDING"}},{"Service":"o11y","Name":"reviews-list","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.","Method":"GET","Path":"/v1/o11y/reviews","Args":[],"Flags":[{"Name":"page","Field":"page","Type":"integer","Help":"Page is the 1-based page to read. Default 1.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit is how many rows to return. Default 20, capped at 100.","Required":false}],"Example":{"limit":20,"page":1}},{"Service":"o11y","Name":"reviews-update","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.","Method":"PATCH","Path":"/v1/o11y/reviews/:id","Args":[{"Name":"id","Help":"ID is the annotation queue to update, from the path."}],"Flags":[{"Name":"description","Field":"description","Type":"string","Help":"Description replaces the free text when present, up to 512 characters.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name replaces the queue's display handle when present, 1–128 printable\ncharacters and unique within the project.","Required":false},{"Name":"score-config-ids","Field":"scoreConfigIds","Type":"json","Help":"ScoreConfigIDs replaces the whole score-config set when present.","Required":false}],"Example":{"id":"annq_1","name":"hallucination review v2"}},{"Service":"o11y","Name":"reviews-update","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.","Method":"PATCH","Path":"/v1/o11y/reviews/:id/items/:itemId","Args":[{"Name":"id","Help":"ID is the annotation queue the item belongs to, from the path."},{"Name":"itemId","Help":"ItemID is the item to update, from the path."}],"Flags":[{"Name":"assignee","Field":"assignee","Type":"string","Help":"Assignee replaces the reviewer this item is for, up to 512 characters.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status is the item's new review state: PENDING or COMPLETED. Required.","Required":false}],"Example":{"id":"annq_1","itemId":"annqi_1","status":"COMPLETED"}},{"Service":"o11y","Name":"revoke-service-account-key","OperationID":"RevokeServiceAccountKey","Summary":"Revokes an API key.","Description":"Revokes an API key. Revocation is immediate and\npermanent.","Method":"DELETE","Path":"/v1/o11y/service_accounts/:id/keys/:fid","Args":[{"Name":"id","Help":""},{"Name":"fid","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"search-ingestion-keys","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.","Method":"GET","Path":"/v1/o11y/gateway/ingestion_keys/search","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"Name is the substring to match ingestion-key names against.","Required":false},{"Name":"page","Field":"page","Type":"integer","Help":"Page is the 1-based page number.","Required":false},{"Name":"per-page","Field":"per_page","Type":"integer","Help":"PerPage is the page size.","Required":false}],"Example":null},{"Service":"o11y","Name":"search-traces","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.","Method":"GET","Path":"/v1/o11y/traces/:traceId","Args":[{"Name":"traceId","Help":""}],"Flags":[{"Name":"span-id","Field":"spanId","Type":"string","Help":"","Required":false},{"Name":"level-up","Field":"levelUp","Type":"integer","Help":"","Required":false},{"Name":"level-down","Field":"levelDown","Type":"integer","Help":"","Required":false},{"Name":"span-render-limit","Field":"spanRenderLimit","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"sentinel-discover-create","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.","Method":"POST","Path":"/v1/o11y/sentinel/discover","Args":[],"Flags":[{"Name":"aggregations","Field":"aggregations","Type":"json","Help":"Aggregations are the measures to compute per group. Empty means a count.","Required":false},{"Name":"filters","Field":"filters","Type":"json","Help":"Filters narrow the scan; each is a field, an operator (eq, neq, like) and\na value, and they combine with AND.","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"GroupBy are the columns to group the rows by.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many rows come back.","Required":false},{"Name":"order-by","Field":"orderBy","Type":"string","Help":"OrderBy is the column or aggregation to sort the rows on.","Required":false},{"Name":"order-dir","Field":"orderDir","Type":"string","Help":"OrderDir is asc or desc.","Required":false},{"Name":"period","Field":"period","Type":"string","Help":"Period is the window to read, relative to now — 1h, 24h, 7d, 14d, 30d.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project is the project to read, as its id. Required.","Required":true}],"Example":null},{"Service":"o11y","Name":"sentinel-events-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.","Method":"GET","Path":"/v1/o11y/sentinel/events/:id","Args":[{"Name":"id","Help":"ID is the event id."}],"Flags":[{"Name":"project","Field":"project","Type":"string","Help":"Project is the project the event belongs to, by its id. Required.","Required":true}],"Example":null},{"Service":"o11y","Name":"sentinel-issues-events-list","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.","Method":"GET","Path":"/v1/o11y/sentinel/issues/:id/events","Args":[{"Name":"id","Help":"ID is the issue id."}],"Flags":[{"Name":"project","Field":"project","Type":"string","Help":"Project is the project whose occurrences to read, by its id. Required.","Required":true},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many occurrences come back. Zero means the default.","Required":false}],"Example":null},{"Service":"o11y","Name":"sentinel-issues-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.","Method":"GET","Path":"/v1/o11y/sentinel/issues/:id","Args":[{"Name":"id","Help":"ID is the issue id."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"sentinel-issues-list","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.","Method":"GET","Path":"/v1/o11y/sentinel/issues","Args":[],"Flags":[{"Name":"status","Field":"status","Type":"string","Help":"Status narrows to one lifecycle state: unresolved, resolved or ignored.","Required":false},{"Name":"level","Field":"level","Type":"string","Help":"Level narrows to one severity, e.g. error, warning, info.","Required":false},{"Name":"environment","Field":"environment","Type":"string","Help":"Environment narrows to one deployment environment.","Required":false},{"Name":"service-name","Field":"serviceName","Type":"string","Help":"ServiceName narrows to one reporting service.","Required":false},{"Name":"query","Field":"query","Type":"string","Help":"Query narrows to issues whose text contains it.","Required":false},{"Name":"sort","Field":"sort","Type":"string","Help":"Sort orders the page, e.g. lastSeen, firstSeen, count.","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset is how many issues to skip. Zero starts at the first.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many issues come back. Zero means the default.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project narrows the org's issues to one project, by its id.","Required":false},{"Name":"period","Field":"period","Type":"string","Help":"Period is the window to read, relative to now — 1h, 24h, 7d, 14d, 30d.","Required":false}],"Example":null},{"Service":"o11y","Name":"sentinel-issues-update","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.","Method":"PUT","Path":"/v1/o11y/sentinel/issues/:id","Args":[{"Name":"id","Help":"ID is the issue id."}],"Flags":[{"Name":"assignee","Field":"assignee","Type":"string","Help":"Assignee is who the issue is assigned to.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status is the new lifecycle state: unresolved, resolved or ignored.","Required":false}],"Example":null},{"Service":"o11y","Name":"sentinel-logs-list","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.","Method":"GET","Path":"/v1/o11y/sentinel/logs","Args":[],"Flags":[{"Name":"project","Field":"project","Type":"string","Help":"Project is the project to read, as its id. Required.","Required":true},{"Name":"query","Field":"query","Type":"string","Help":"Query narrows the page to events whose text contains it.","Required":false},{"Name":"period","Field":"period","Type":"string","Help":"Period is the window to read, relative to now — 1h, 24h, 7d, 14d, 30d.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many events come back.","Required":false}],"Example":null},{"Service":"o11y","Name":"sentinel-projects-create","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.","Method":"POST","Path":"/v1/o11y/sentinel/projects","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"Name is the project's display name. Required.","Required":true},{"Name":"platform","Field":"platform","Type":"string","Help":"Platform is the reporting runtime, e.g. go, python, javascript.","Required":false},{"Name":"slug","Field":"slug","Type":"string","Help":"Slug is the project's short name. Server-assigned from Name when empty.","Required":false}],"Example":null},{"Service":"o11y","Name":"sentinel-projects-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.","Method":"DELETE","Path":"/v1/o11y/sentinel/projects/:id","Args":[{"Name":"id","Help":"ID is the project id."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"sentinel-projects-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.","Method":"GET","Path":"/v1/o11y/sentinel/projects/:id","Args":[{"Name":"id","Help":"ID is the project id."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"sentinel-projects-list","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.","Method":"GET","Path":"/v1/o11y/sentinel/projects","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"sentinel-stats-list","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.","Method":"GET","Path":"/v1/o11y/sentinel/stats","Args":[],"Flags":[{"Name":"project","Field":"project","Type":"string","Help":"Project is the project to read, as its id. Required.","Required":true},{"Name":"field","Field":"field","Type":"string","Help":"Field is the dimension to count over. Empty counts all events.","Required":false},{"Name":"period","Field":"period","Type":"string","Help":"Period is the window to read, relative to now — 1h, 24h, 7d, 14d, 30d.","Required":false}],"Example":null},{"Service":"o11y","Name":"sentinel-traces-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.","Method":"GET","Path":"/v1/o11y/sentinel/traces/:id","Args":[{"Name":"id","Help":"ID is the trace id."}],"Flags":[{"Name":"project","Field":"project","Type":"string","Help":"Project is the project the trace's errors belong to. Required.","Required":true}],"Example":null},{"Service":"o11y","Name":"sentinel-traces-list","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\".","Method":"GET","Path":"/v1/o11y/sentinel/traces","Args":[],"Flags":[{"Name":"project","Field":"project","Type":"string","Help":"Project is the project to read, as its id. Required.","Required":true},{"Name":"period","Field":"period","Type":"string","Help":"Period is the window to read, relative to now — 1h, 24h, 7d, 14d, 30d.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many traces come back.","Required":false}],"Example":null},{"Service":"o11y","Name":"service-entry-point-operations-create","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.","Method":"POST","Path":"/v1/o11y/service/entry_point_operations","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"string","Help":"End is the window's end, epoch nanoseconds as a string.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many operations come back.","Required":false},{"Name":"service","Field":"service","Type":"string","Help":"Service is the service whose operations are read.","Required":false},{"Name":"start","Field":"start","Type":"string","Help":"Start is the window's start, epoch nanoseconds as a string.","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"Tags narrow the spans counted, each a span-attribute predicate.","Required":false}],"Example":null},{"Service":"o11y","Name":"service-top-level-operations-create","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.","Method":"POST","Path":"/v1/o11y/service/top_level_operations","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"string","Help":"End is the window's end, epoch nanoseconds as a string; empty means\nunbounded.","Required":false},{"Name":"service","Field":"service","Type":"string","Help":"Service narrows the map to one service when set.","Required":false},{"Name":"start","Field":"start","Type":"string","Help":"Start is the window's start, epoch nanoseconds as a string; empty means\nunbounded.","Required":false}],"Example":null},{"Service":"o11y","Name":"service-top-operations-create","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.","Method":"POST","Path":"/v1/o11y/service/top_operations","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"string","Help":"End is the window's end, epoch nanoseconds as a string.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many operations come back.","Required":false},{"Name":"service","Field":"service","Type":"string","Help":"Service is the service whose operations are read.","Required":false},{"Name":"start","Field":"start","Type":"string","Help":"Start is the window's start, epoch nanoseconds as a string.","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"Tags narrow the spans counted, each a span-attribute predicate.","Required":false}],"Example":null},{"Service":"o11y","Name":"services-create","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.","Method":"POST","Path":"/v1/o11y/services","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"string","Help":"End is the window's end, epoch nanoseconds as a string.","Required":false},{"Name":"start","Field":"start","Type":"string","Help":"Start is the window's start, epoch nanoseconds as a string.","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"Tags narrow the spans counted, each a span-attribute predicate.","Required":false}],"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/services/list","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"sessions-list","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.","Method":"GET","Path":"/v1/o11y/sessions","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"settings-apdex-create","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.","Method":"POST","Path":"/v1/o11y/settings/apdex","Args":[],"Flags":[{"Name":"exclude-status-codes","Field":"excludeStatusCodes","Type":"string","Help":"ExcludeStatusCodes are status codes excluded from the score, comma\nseparated.","Required":false},{"Name":"service-name","Field":"serviceName","Type":"string","Help":"ServiceName is the service the threshold applies to.","Required":false},{"Name":"threshold","Field":"threshold","Type":"number","Help":"Threshold is the satisfied-response time in seconds.","Required":false}],"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/settings/apdex","Args":[],"Flags":[{"Name":"services","Field":"services","Type":"string","Help":"Services are the service names, comma separated.","Required":false}],"Example":null},{"Service":"o11y","Name":"settings-ttl-create","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.","Method":"POST","Path":"/v1/o11y/settings/ttl","Args":[],"Flags":[{"Name":"cold-storage-duration-days","Field":"coldStorageDurationDays","Type":"integer","Help":"ColdStorageDurationDays is how old data must be before it moves, in days.","Required":false},{"Name":"cold-storage-volume","Field":"coldStorageVolume","Type":"string","Help":"ColdStorageVolume names the volume aged data moves to, when set.","Required":false},{"Name":"default-ttl-days","Field":"defaultTTLDays","Type":"integer","Help":"DefaultTTLDays is the retention for data no rule matches, in days.","Required":false},{"Name":"ttl-conditions","Field":"ttlConditions","Type":"json","Help":"TTLConditions are ordered per-label rules; the first matching rule wins.","Required":false},{"Name":"type","Field":"type","Type":"string","Help":"Type is the signal the policy applies to — traces, metrics or logs.","Required":false}],"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/settings/ttl","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"span-percentile-create","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.","Method":"POST","Path":"/v1/o11y/span_percentile","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"End is the window end, as epoch nanoseconds.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the span name whose peers are compared. Required.","Required":true},{"Name":"resource-attributes","Field":"resourceAttributes","Type":"json","Help":"ResourceAttributes narrow the peer group to spans carrying them all.","Required":false},{"Name":"service-name","Field":"serviceName","Type":"string","Help":"ServiceName is the service the span belongs to. Required.","Required":true},{"Name":"span-duration","Field":"spanDuration","Type":"integer","Help":"SpanDuration is the span's duration in nanoseconds.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window start, as epoch nanoseconds.","Required":false}],"Example":null},{"Service":"o11y","Name":"statefulsets-attribute-keys-list","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.","Method":"GET","Path":"/v1/o11y/statefulsets/attribute_keys","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the keys come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the keys will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the keys must appear on.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the keys to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the keys to one kind — tag or resource. Empty means all;\nan invalid value reads as empty.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many keys come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"statefulsets-attribute-values-list","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.","Method":"GET","Path":"/v1/o11y/statefulsets/attribute_values","Args":[],"Flags":[{"Name":"data-source","Field":"dataSource","Type":"string","Help":"DataSource is the telemetry the values come from — metrics for the infra\nfaces. The runtime requires it.","Required":false},{"Name":"aggregate-operator","Field":"aggregateOperator","Type":"string","Help":"AggregateOperator is the aggregation the values will be used under, e.g.\nnoop, count, avg. The runtime requires it for non-metrics sources.","Required":false},{"Name":"aggregate-attribute","Field":"aggregateAttribute","Type":"string","Help":"AggregateAttribute is the metric the values must appear on.","Required":false},{"Name":"attribute-key","Field":"attributeKey","Type":"string","Help":"AttributeKey is the key whose values to list.","Required":false},{"Name":"filter-attribute-key-data-type","Field":"filterAttributeKeyDataType","Type":"string","Help":"FilterAttributeKeyDataType is the key's data type — string, int64,\nfloat64 or bool. Empty means unspecified.","Required":false},{"Name":"search-text","Field":"searchText","Type":"string","Help":"SearchText narrows the values to those containing it.","Required":false},{"Name":"tag-type","Field":"tagType","Type":"string","Help":"TagType narrows the search to one kind of key — tag or resource.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many values come back. Absent means 50.","Required":false}],"Example":null},{"Service":"o11y","Name":"statefulsets-list-create","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.","Method":"POST","Path":"/v1/o11y/statefulsets/list","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"integer","Help":"epoch time in ms","Required":false},{"Name":"filters","Field":"filters","Type":"json","Help":"","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"","Required":false},{"Name":"order-by","Field":"orderBy","Type":"json","Help":"","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"epoch time in ms","Required":false}],"Example":null},{"Service":"o11y","Name":"stats-list","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.","Method":"GET","Path":"/v1/o11y/stats","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/status","Args":[],"Flags":[{"Name":"product","Field":"product","Type":"string","Help":"Product is the console product slug to probe, e.g. \"kms\". Required.","Required":false}],"Example":{"product":"kms"}},{"Service":"o11y","Name":"substitute-vars-create","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.","Method":"POST","Path":"/v1/o11y/substitute_vars","Args":[],"Flags":[{"Name":"composite-query","Field":"compositeQuery","Type":"json","Help":"CompositeQuery is the composite query to use for the request.","Required":false},{"Name":"end","Field":"end","Type":"integer","Help":"End is the end time of the query in epoch milliseconds.","Required":false},{"Name":"format-options","Field":"formatOptions","Type":"json","Help":"","Required":false},{"Name":"no-cache","Field":"noCache","Type":"boolean","Help":"NoCache is a flag to disable caching for the request.","Required":false},{"Name":"request-type","Field":"requestType","Type":"json","Help":"RequestType is the type of the request.","Required":false},{"Name":"schema-version","Field":"schemaVersion","Type":"string","Help":"SchemaVersion is the version of the schema to use for the request payload.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the start time of the query in epoch milliseconds.","Required":false},{"Name":"variables","Field":"variables","Type":"json","Help":"Variables is the variables to use for the request.","Required":false}],"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/summary","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"test-channel","OperationID":"TestChannel","Summary":"Sends a test notification to the posted receiver.","Description":"Sends a test notification to the posted receiver. Editor gate.","Method":"POST","Path":"/v1/o11y/channels/test","Args":[],"Flags":[{"Name":"receiver","Field":"Receiver","Type":"json","Help":"","Required":false},{"Name":"googlechat-configs","Field":"googlechat_configs","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"test-channel-deprecated","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.","Method":"POST","Path":"/v1/o11y/testChannel","Args":[],"Flags":[{"Name":"receiver","Field":"Receiver","Type":"json","Help":"","Required":false},{"Name":"googlechat-configs","Field":"googlechat_configs","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"test-rule","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.","Method":"POST","Path":"/v1/o11y/rules/test","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"test-rule-notification","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.","Method":"POST","Path":"/v1/o11y/testRule","Args":[],"Flags":null,"Example":null},{"Service":"o11y","Name":"third-party-apis-overview-domain-create","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.","Method":"POST","Path":"/v1/o11y/third-party-apis/overview/domain","Args":[],"Flags":[{"Name":"domain","Field":"domain","Type":"string","Help":"Domain narrows the read to one external domain (the domain view requires\nit).","Required":false},{"Name":"end","Field":"end","Type":"integer","Help":"End is the window's end, epoch milliseconds.","Required":false},{"Name":"endpoint","Field":"endpoint","Type":"string","Help":"Endpoint narrows the domain view to one endpoint.","Required":false},{"Name":"filter","Field":"filter","Type":"json","Help":"Filter is an additional predicate in the query-builder filter syntax.","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"GroupBy adds grouping columns to the result.","Required":false},{"Name":"show-ip","Field":"show_ip","Type":"boolean","Help":"ShowIP keeps rows whose domain is a bare IP address; they are dropped\notherwise.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window's start, epoch milliseconds.","Required":false}],"Example":null},{"Service":"o11y","Name":"third-party-apis-overview-list-create","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.","Method":"POST","Path":"/v1/o11y/third-party-apis/overview/list","Args":[],"Flags":[{"Name":"domain","Field":"domain","Type":"string","Help":"Domain narrows the read to one external domain (the domain view requires\nit).","Required":false},{"Name":"end","Field":"end","Type":"integer","Help":"End is the window's end, epoch milliseconds.","Required":false},{"Name":"endpoint","Field":"endpoint","Type":"string","Help":"Endpoint narrows the domain view to one endpoint.","Required":false},{"Name":"filter","Field":"filter","Type":"json","Help":"Filter is an additional predicate in the query-builder filter syntax.","Required":false},{"Name":"group-by","Field":"groupBy","Type":"json","Help":"GroupBy adds grouping columns to the result.","Required":false},{"Name":"show-ip","Field":"show_ip","Type":"boolean","Help":"ShowIP keeps rows whose domain is a bare IP address; they are dropped\notherwise.","Required":false},{"Name":"start","Field":"start","Type":"integer","Help":"Start is the window's start, epoch milliseconds.","Required":false}],"Example":null},{"Service":"o11y","Name":"traces-list","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.","Method":"GET","Path":"/v1/o11y/traces","Args":[],"Flags":[{"Name":"range","Field":"range","Type":"integer","Help":"Range is the window in seconds, counted back from now over each trace's\nlast activity. Default 3600, capped at 604800 (7d).","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit is how many traces to return. Default 50, capped at 500.","Required":false},{"Name":"min-duration-ms","Field":"minDurationMs","Type":"integer","Help":"MinDurationMs keeps only traces that lasted at least this many\nmilliseconds. Zero or absent keeps every trace in the window.","Required":false}],"Example":{"limit":50,"range":3600}},{"Service":"o11y","Name":"uninstall-integration","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.","Method":"POST","Path":"/v1/o11y/integrations/uninstall","Args":[],"Flags":[{"Name":"integration-id","Field":"integration_id","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"unlock-dashboard-v2","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.","Method":"DELETE","Path":"/v1/o11y/dashboards/:id/lock","Args":[{"Name":"id","Help":"ID is the resource id from the path."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"unpin-dashboard-v2","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.","Method":"DELETE","Path":"/v1/o11y/users/me/dashboards/:id/pins","Args":[{"Name":"id","Help":"ID is the resource id from the path."}],"Flags":null,"Example":null},{"Service":"o11y","Name":"update-account","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.","Method":"PUT","Path":"/v1/o11y/cloud_integrations/:cloud_provider/accounts/:id","Args":[{"Name":"cloud_provider","Help":""},{"Name":"id","Help":""}],"Flags":[{"Name":"config","Field":"config","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"update-channel-by-id","OperationID":"UpdateChannelByID","Summary":"Replaces a notification channel's receiver, by id.","Description":"Replaces a notification channel's receiver, by id. Admin gate.","Method":"PUT","Path":"/v1/o11y/channels/:id","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"receiver","Field":"Receiver","Type":"json","Help":"","Required":false},{"Name":"googlechat-configs","Field":"googlechat_configs","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"update-dashboard-v2","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.","Method":"PUT","Path":"/v1/o11y/dashboards/:id","Args":[{"Name":"id","Help":"ID is the dashboard id from the path."}],"Flags":[{"Name":"image","Field":"image","Type":"string","Help":"Image is an optional cover image reference.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name must equal the dashboard's existing name — it is immutable.","Required":false},{"Name":"schema-version","Field":"schemaVersion","Type":"string","Help":"SchemaVersion is the dashboard schema version; must be the current v6.","Required":false},{"Name":"spec","Field":"spec","Type":"json","Help":"Spec is the replacement Perses spec, carried verbatim as open JSON.","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"Tags replace the dashboard's tags; at most ten.","Required":false}],"Example":null},{"Service":"o11y","Name":"update-dashboard-view","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.","Method":"PUT","Path":"/v1/o11y/dashboard_views/:id","Args":[{"Name":"id","Help":"ID is the saved view id from the path."}],"Flags":[{"Name":"data","Field":"data","Type":"json","Help":"Data is the listing state the view captures.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the saved view's name; at most 32 characters, no surrounding space.","Required":false}],"Example":null},{"Service":"o11y","Name":"update-downtime-schedule-by-id","OperationID":"UpdateDowntimeScheduleByID","Summary":"Replaces a planned maintenance window, by id.","Description":"Replaces a planned maintenance window, by id. Editor gate.","Method":"PUT","Path":"/v1/o11y/downtime_schedules/:id","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"alert-ids","Field":"alertIds","Type":"json","Help":"","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"schedule","Field":"schedule","Type":"json","Help":"","Required":false},{"Name":"scope","Field":"scope","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"update-ingestion-key","OperationID":"UpdateIngestionKey","Summary":"Changes an ingestion key, by id.","Description":"Changes an ingestion key, by id. Editor gate.","Method":"PATCH","Path":"/v1/o11y/gateway/ingestion_keys/:keyId","Args":[{"Name":"keyId","Help":""}],"Flags":[{"Name":"expires-at","Field":"expires_at","Type":"string","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"update-ingestion-key-limit","OperationID":"UpdateIngestionKeyLimit","Summary":"Changes an ingestion key limit, by limit id.","Description":"Changes an ingestion key limit, by limit id. Editor\ngate.","Method":"PATCH","Path":"/v1/o11y/gateway/ingestion_keys/limits/:limitId","Args":[{"Name":"limitId","Help":""}],"Flags":[{"Name":"config","Field":"config","Type":"json","Help":"","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"update-metric-metadata","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.","Method":"POST","Path":"/v1/o11y/metrics/metadata","Args":[],"Flags":[{"Name":"description","Field":"description","Type":"string","Help":"Description describes the metric.","Required":false},{"Name":"is-monotonic","Field":"isMonotonic","Type":"boolean","Help":"IsMonotonic marks a sum that only ever increases.","Required":false},{"Name":"metric-name","Field":"metricName","Type":"string","Help":"MetricName is the metric to update. Required.","Required":true},{"Name":"temporality","Field":"temporality","Type":"string","Help":"Temporality is delta or cumulative.","Required":false},{"Name":"type","Field":"type","Type":"string","Help":"Type is the metric type, e.g. gauge, sum, histogram.","Required":false},{"Name":"unit","Field":"unit","Type":"string","Help":"Unit is the metric's unit.","Required":false}],"Example":null},{"Service":"o11y","Name":"update-metric-reduction-rule-by-id","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.","Method":"PUT","Path":"/v1/o11y/metric_reduction_rules/:id","Args":[{"Name":"id","Help":"ID is the rule's id."}],"Flags":[{"Name":"labels","Field":"labels","Type":"json","Help":"Labels are the label names the rule matches. Required, at least one.","Required":true},{"Name":"match-type","Field":"matchType","Type":"string","Help":"MatchType is drop or keep. Required.","Required":true}],"Example":null},{"Service":"o11y","Name":"update-my-organization","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.","Method":"PUT","Path":"/v1/o11y/orgs/me","Args":[],"Flags":[{"Name":"alias","Field":"alias","Type":"string","Help":"Alias is an alternate name the org also answers to.","Required":false},{"Name":"created-at","Field":"createdAt","Type":"string","Help":"CreatedAt is when the org was created.","Required":false},{"Name":"display-name","Field":"displayName","Type":"string","Help":"DisplayName is what the console shows for the org.","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"ID is the org id. On update it is ignored: the call always addresses the\ncaller's own org.","Required":false},{"Name":"key","Field":"key","Type":"integer","Help":"Key is the org's stable numeric key, derived from its id.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the org's short name.","Required":false},{"Name":"updated-at","Field":"updatedAt","Type":"string","Help":"UpdatedAt is when it last changed.","Required":false}],"Example":null},{"Service":"o11y","Name":"update-my-service-account","OperationID":"UpdateMyServiceAccount","Summary":"Renames the calling service account.","Description":"Renames the calling service account.","Method":"PUT","Path":"/v1/o11y/service_accounts/me","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"Name is the account's new name, under the same rules it was created with.\nRequired.","Required":false}],"Example":null},{"Service":"o11y","Name":"update-org-preference","OperationID":"UpdateOrgPreference","Summary":"Sets one org-scoped preference, by name.","Description":"Sets one org-scoped preference, by name. Admin gate.","Method":"PUT","Path":"/v1/o11y/org/preferences/:name","Args":[{"Name":"name","Help":""}],"Flags":[{"Name":"value","Field":"value","Type":"json","Help":"Value is the value to set; its JSON type must match the preference's\ndeclared value type.","Required":false}],"Example":null},{"Service":"o11y","Name":"update-public-dashboard","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.","Method":"PUT","Path":"/v1/o11y/dashboards/:id/public","Args":[{"Name":"id","Help":"ID is the dashboard id from the path."}],"Flags":[{"Name":"default-time-range","Field":"defaultTimeRange","Type":"string","Help":"DefaultTimeRange is the fixed window as a Go duration, e.g. 1h, 30m.","Required":false},{"Name":"time-range-enabled","Field":"timeRangeEnabled","Type":"boolean","Help":"TimeRangeEnabled lets the public page pick its own time range; when false\nthe share fixes DefaultTimeRange.","Required":false}],"Example":null},{"Service":"o11y","Name":"update-quick-filters","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.","Method":"PUT","Path":"/v1/o11y/orgs/me/filters","Args":[],"Flags":[{"Name":"filters","Field":"filters","Type":"json","Help":"Filters are the attributes to offer, in the order to offer them.","Required":false},{"Name":"signal","Field":"signal","Type":"string","Help":"Signal is the signal whose filters are being replaced.","Required":false}],"Example":null},{"Service":"o11y","Name":"update-role","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.","Method":"PUT","Path":"/v1/o11y/roles/:id","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"description","Field":"description","Type":"string","Help":"Description says what the role is for. Required — send an empty string to\nclear it.","Required":false},{"Name":"transaction-groups","Field":"transactionGroups","Type":"json","Help":"TransactionGroups are the grants the role carries. Required — send an\nempty array to clear them.","Required":false}],"Example":null},{"Service":"o11y","Name":"update-route-policy","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.","Method":"PUT","Path":"/v1/o11y/route_policies/:id","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"channels","Field":"channels","Type":"json","Help":"","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"expression","Field":"expression","Type":"string","Help":"","Required":false},{"Name":"kind","Field":"kind","Type":"json","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"update-rule-by-id","OperationID":"UpdateRuleByID","Summary":"Replaces an alert rule's definition, by id.","Description":"Replaces an alert rule's definition, by id. Editor gate.","Method":"PUT","Path":"/v1/o11y/rules/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"o11y","Name":"update-service","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.","Method":"PUT","Path":"/v1/o11y/cloud_integrations/:cloud_provider/accounts/:id/services/:service_id","Args":[{"Name":"cloud_provider","Help":""},{"Name":"id","Help":""},{"Name":"service_id","Help":""}],"Flags":[{"Name":"config","Field":"config","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"update-service-account","OperationID":"UpdateServiceAccount","Summary":"Renames a service account.","Description":"Renames a service account.","Method":"PUT","Path":"/v1/o11y/service_accounts/:id","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"Name is the account's new name, under the same rules it was created with.\nRequired.","Required":false}],"Example":null},{"Service":"o11y","Name":"update-service-account-key","OperationID":"UpdateServiceAccountKey","Summary":"Renames an API key or moves its expiry.","Description":"Renames an API key or moves its expiry.","Method":"PUT","Path":"/v1/o11y/service_accounts/:id/keys/:fid","Args":[{"Name":"id","Help":""},{"Name":"fid","Help":""}],"Flags":[{"Name":"expires-at","Field":"expiresAt","Type":"integer","Help":"ExpiresAt is when the key stops working, as a unix timestamp in seconds.\nZero means it never expires; a past timestamp is refused.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the key's new name, under the same rules it was created with.\nRequired.","Required":false}],"Example":null},{"Service":"o11y","Name":"update-span-mapper","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.","Method":"PATCH","Path":"/v1/o11y/span_mapper_groups/:groupId/span_mappers/:mapperId","Args":[{"Name":"groupId","Help":""},{"Name":"mapperId","Help":""}],"Flags":[{"Name":"config","Field":"config","Type":"json","Help":"","Required":false},{"Name":"enabled","Field":"enabled","Type":"boolean","Help":"","Required":false},{"Name":"field-context","Field":"fieldContext","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"update-span-mapper-group","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.","Method":"PATCH","Path":"/v1/o11y/span_mapper_groups/:groupId","Args":[{"Name":"groupId","Help":""}],"Flags":[{"Name":"condition","Field":"condition","Type":"json","Help":"","Required":false},{"Name":"enabled","Field":"enabled","Type":"boolean","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"update-trace-field","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.","Method":"POST","Path":"/v1/o11y/traces/fields","Args":[],"Flags":[{"Name":"data-type","Field":"dataType","Type":"string","Help":"DataType is the field's data type, e.g. string, int64, float64, bool.\nRequired.","Required":true},{"Name":"index","Field":"index","Type":"string","Help":"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.","Required":false},{"Name":"index-granularity","Field":"indexGranularity","Type":"integer","Help":"IndexGranularity is the index granularity in rows.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the field to tune. Required.","Required":true},{"Name":"selected","Field":"selected","Type":"boolean","Help":"Selected materializes the field as its own column when true.","Required":false},{"Name":"type","Field":"type","Type":"string","Help":"Type is where the field lives: attributes or resources. Required.","Required":true}],"Example":null},{"Service":"o11y","Name":"update-trace-funnel","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.","Method":"PUT","Path":"/v1/o11y/trace-funnels/:funnel_id","Args":[{"Name":"funnel_id","Help":""}],"Flags":[{"Name":"description","Field":"description","Type":"string","Help":"Description replaces the funnel's description. Empty leaves it as it was.","Required":false},{"Name":"funnel-name","Field":"funnel_name","Type":"string","Help":"Name replaces the funnel's name. Empty leaves it as it was.","Required":false},{"Name":"timestamp","Field":"timestamp","Type":"integer","Help":"Timestamp is when the change was made, as a millisecond epoch.","Required":false}],"Example":null},{"Service":"o11y","Name":"update-trace-funnel-steps","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.","Method":"PUT","Path":"/v1/o11y/trace-funnels/steps/update","Args":[],"Flags":[{"Name":"description","Field":"description","Type":"string","Help":"Description replaces the funnel's description. Empty leaves it as it was.","Required":false},{"Name":"funnel-id","Field":"funnel_id","Type":"string","Help":"FunnelID is the funnel to update.","Required":false},{"Name":"funnel-name","Field":"funnel_name","Type":"string","Help":"Name replaces the funnel's name. Empty leaves it as it was.","Required":false},{"Name":"steps","Field":"steps","Type":"json","Help":"Steps are the funnel's steps, in order. At least two are needed before\nany analytics read will answer.","Required":false},{"Name":"timestamp","Field":"timestamp","Type":"integer","Help":"Timestamp is when the change was made, as a millisecond epoch.","Required":false}],"Example":null},{"Service":"o11y","Name":"update-user-preference","OperationID":"UpdateUserPreference","Summary":"Sets one preference of the calling user, by name.","Description":"Sets one preference of the calling user, by name.\nViewer gate.","Method":"PUT","Path":"/v1/o11y/user/preferences/:name","Args":[{"Name":"name","Help":""}],"Flags":[{"Name":"value","Field":"value","Type":"json","Help":"Value is the value to set; its JSON type must match the preference's\ndeclared value type.","Required":false}],"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/usage","Args":[],"Flags":[{"Name":"start","Field":"start","Type":"string","Help":"Start is the window start, as epoch nanoseconds. Required.","Required":true},{"Name":"end","Field":"end","Type":"string","Help":"End is the window end, as epoch nanoseconds. Required.","Required":true},{"Name":"step","Field":"step","Type":"integer","Help":"Step is the bucket width in seconds. The runtime requires it.","Required":false},{"Name":"service","Field":"service","Type":"string","Help":"Service narrows usage to one service. Empty covers all.","Required":false}],"Example":null},{"Service":"o11y","Name":"validate-draft-funnel-traces","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.","Method":"POST","Path":"/v1/o11y/trace-funnels/analytics/validate","Args":[],"Flags":[{"Name":"end-time","Field":"end_time","Type":"integer","Help":"EndTime is the end of the window, as a millisecond epoch.","Required":false},{"Name":"start-time","Field":"start_time","Type":"integer","Help":"StartTime is the start of the window, as a millisecond epoch.","Required":false},{"Name":"step-end","Field":"step_end","Type":"integer","Help":"StepEnd is the step the transition runs to, 1-based.","Required":false},{"Name":"step-start","Field":"step_start","Type":"integer","Help":"StepStart is the step the transition runs from, 1-based. Ignored by the\nreads that span the whole funnel.","Required":false},{"Name":"steps","Field":"steps","Type":"json","Help":"Steps are the funnel's steps, in order. At least two are needed.","Required":false}],"Example":null},{"Service":"o11y","Name":"validate-trace-funnel-traces","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\".","Method":"POST","Path":"/v1/o11y/trace-funnels/:funnel_id/analytics/validate","Args":[{"Name":"funnel_id","Help":""}],"Flags":[{"Name":"end-time","Field":"end_time","Type":"integer","Help":"","Required":false},{"Name":"start-time","Field":"start_time","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"o11y","Name":"variables-query-create","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.","Method":"POST","Path":"/v1/o11y/variables/query","Args":[],"Flags":[{"Name":"query","Field":"query","Type":"string","Help":"Query is the variable query to evaluate. Required.","Required":true},{"Name":"variables","Field":"variables","Type":"json","Help":"Variables are the current values of the other dashboard variables, for\nqueries that reference them.","Required":false}],"Example":null},{"Service":"o11y","Name":"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.","Method":"GET","Path":"/v1/o11y/version","Args":[],"Flags":null,"Example":null},{"Service":"openapi","Name":"commands-list","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.","Method":"GET","Path":"/v1/openapi/commands","Args":[],"Flags":null,"Example":null},{"Service":"openapi-json","Name":"list","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.","Method":"GET","Path":"/v1/openapi.json","Args":[],"Flags":null,"Example":null},{"Service":"patent","Name":"approvals-create","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.","Method":"POST","Path":"/v1/patent/approvals","Args":[],"Flags":[{"Name":"approvals","Field":"approvals","Type":"json","Help":"Approvals are the decisions to append, at most 2000.","Required":false}],"Example":{"approvals":[{"comment":"research log reviewed, the mechanism is ours","decision":"approved","disclosure_id":"router-v2","role":"cto"}]}},{"Service":"patent","Name":"approvals-list","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.","Method":"GET","Path":"/v1/patent/approvals","Args":[],"Flags":[{"Name":"disclosure","Field":"disclosure","Type":"string","Help":"Disclosure narrows to the decisions on one document.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project narrows to one project.","Required":false}],"Example":null},{"Service":"patent","Name":"disclosures-create","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.","Method":"POST","Path":"/v1/patent/disclosures","Args":[],"Flags":[{"Name":"disclosures","Field":"disclosures","Type":"json","Help":"Disclosures are the documents to append, at most 2000.","Required":false}],"Example":null},{"Service":"patent","Name":"disclosures-list","OperationID":"get_patent_disclosures","Summary":"Returns the canonical disclosures, each carrying its current approvals.","Description":"Returns the canonical disclosures, each carrying its\ncurrent approvals.","Method":"GET","Path":"/v1/patent/disclosures","Args":[],"Flags":[{"Name":"id","Field":"id","Type":"string","Help":"ID reads one disclosure.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status narrows to one status.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project narrows to one project.","Required":false}],"Example":null},{"Service":"patent","Name":"grants-create","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.","Method":"POST","Path":"/v1/patent/grants","Args":[],"Flags":[{"Name":"id","Field":"id","Type":"string","Help":"ID is the record's stable id.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind is idea, implementation or disclosure — what the id names.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project locates the record inside the caller's own org.","Required":false},{"Name":"visibility","Field":"visibility","Type":"string","Help":"Visibility is private, org or public.","Required":false}],"Example":null},{"Service":"patent","Name":"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.","Method":"GET","Path":"/v1/patent/health","Args":[],"Flags":null,"Example":null},{"Service":"patent","Name":"ideas-create","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.","Method":"POST","Path":"/v1/patent/ideas","Args":[],"Flags":[{"Name":"ideas","Field":"ideas","Type":"json","Help":"Ideas are the entries to append, at most 2000.","Required":false}],"Example":{"ideas":[{"id":"route-by-queue-depth","kind":"mechanism","statement":"..."}]}},{"Service":"patent","Name":"ideas-list","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.","Method":"GET","Path":"/v1/patent/ideas","Args":[],"Flags":[{"Name":"id","Field":"id","Type":"string","Help":"ID reads one entry, which is how a single idea is addressed — there is no\nsecond route for it.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind narrows to one kind of conception entry.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project narrows to one project; empty reads the org's whole set.","Required":false}],"Example":null},{"Service":"patent","Name":"implementations-create","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.","Method":"POST","Path":"/v1/patent/implementations","Args":[],"Flags":[{"Name":"implementations","Field":"implementations","Type":"json","Help":"Implementations are the records to append, at most 2000.","Required":false}],"Example":{"implementations":[{"git_sha":"...","id":"router-v2","idea_ids":["route-by-queue-depth"],"model":"zen6-coder"}]}},{"Service":"patent","Name":"implementations-list","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.","Method":"GET","Path":"/v1/patent/implementations","Args":[],"Flags":[{"Name":"id","Field":"id","Type":"string","Help":"ID reads one implementation.","Required":false},{"Name":"idea","Field":"idea","Type":"string","Help":"Idea narrows to implementations citing one conception entry — which is\nhow a correction finds every artifact built on the idea it invalidates.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project narrows to one project.","Required":false}],"Example":null},{"Service":"patent","Name":"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.","Method":"GET","Path":"/v1/patent/proof","Args":[],"Flags":[{"Name":"disclosure","Field":"disclosure","Type":"string","Help":"Disclosure folds the record set one document rests on, and reports on\nthat set alone — which is what an attorney asks for.","Required":false},{"Name":"idea","Field":"idea","Type":"string","Help":"Idea narrows to the one entry and the artifacts citing it.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project narrows inside the org; empty reads the caller's scope.","Required":false}],"Example":null},{"Service":"patent","Name":"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.","Method":"GET","Path":"/v1/patent/timeline","Args":[],"Flags":[{"Name":"id","Field":"id","Type":"string","Help":"ID is the entry's stable id. Required.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind is idea, implementation or disclosure — which log to read.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project narrows inside the org; empty is the caller's own scope.","Required":false}],"Example":null},{"Service":"patrol","Name":"alarm-create","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.","Method":"POST","Path":"/v1/patrol/alarm","Args":[],"Flags":[{"Name":"account","Field":"account","Type":"string","Help":"Account is the alarm-panel account number that reported. It is what an\nactivation matches a site on when no site is named.","Required":false},{"Name":"raw","Field":"raw","Type":"json","Help":"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.","Required":false},{"Name":"ref","Field":"ref","Type":"string","Help":"Ref is the receiving centre's own reference for the activation.","Required":false},{"Name":"site","Field":"site","Type":"string","Help":"Site names the site directly, by document name, when the caller already\nknows it.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source is which receiver or operator the activation came through.","Required":false},{"Name":"trigger","Field":"trigger","Type":"string","Help":"Trigger is what the panel reported.","Required":false},{"Name":"zone","Field":"zone","Type":"string","Help":"Zone is the panel zone that fired.","Required":false}],"Example":null},{"Service":"patrol","Name":"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.","Method":"GET","Path":"/v1/patrol/camera","Args":[],"Flags":[{"Name":"site","Field":"site","Type":"string","Help":"Site narrows the list to one site by document name. Empty lists every\ncamera.","Required":false}],"Example":null},{"Service":"patrol","Name":"camera-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.","Method":"GET","Path":"/v1/patrol/camera/:name/stream/:ticket","Args":[{"Name":"name","Help":"Name is the camera's document name, from the path."},{"Name":"ticket","Help":"Ticket is the tag the minted address carries, from the path."}],"Flags":[{"Name":"expires","Field":"expires","Type":"string","Help":"Expires is the moment the tag covers, as the seconds the minted address\ncarries in its `expires` parameter.","Required":false}],"Example":null},{"Service":"patrol","Name":"camera-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.","Method":"GET","Path":"/v1/patrol/camera/:name/stream","Args":[{"Name":"name","Help":"Name is the camera's document name, from the path."}],"Flags":null,"Example":null},{"Service":"patrol","Name":"event-create","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.","Method":"POST","Path":"/v1/patrol/event","Args":[],"Flags":[{"Name":"detail","Field":"detail","Type":"string","Help":"Detail is the longer account.","Required":false},{"Name":"level","Field":"level","Type":"string","Help":"Level is red, amber, green or cyan.","Required":false},{"Name":"site","Field":"site","Type":"string","Help":"Site is the site it is about, by document name.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source is what raised it.","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"Title is the one line the feed shows.","Required":false},{"Name":"unit","Field":"unit","Type":"string","Help":"Unit is the unit it is about, by call sign.","Required":false}],"Example":null},{"Service":"patrol","Name":"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.","Method":"GET","Path":"/v1/patrol/event","Args":[],"Flags":[{"Name":"level","Field":"level","Type":"string","Help":"Level narrows the list to red, amber, green or cyan. Empty lists every\nlevel.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many rows are returned. Anything that is not a positive\ninteger uses 80, and higher values are clamped to 80.","Required":false}],"Example":null},{"Service":"patrol","Name":"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.","Method":"GET","Path":"/v1/patrol/feed","Args":[],"Flags":null,"Example":null},{"Service":"patrol","Name":"incident-create","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.","Method":"POST","Path":"/v1/patrol/incident","Args":[],"Flags":[{"Name":"ref","Field":"ref","Type":"string","Help":"Ref is the receiving centre's own reference.","Required":false},{"Name":"site","Field":"site","Type":"string","Help":"Site is where it is happening, by document name.","Required":false},{"Name":"trigger","Field":"trigger","Type":"string","Help":"Trigger is what was reported.","Required":false},{"Name":"zone","Field":"zone","Type":"string","Help":"Zone is the panel zone that reported.","Required":false}],"Example":null},{"Service":"patrol","Name":"incident-get","OperationID":"get_patrol_incident","Summary":"Lists responses.","Description":"Lists responses. ?open=1 narrows it to the ones still running.","Method":"GET","Path":"/v1/patrol/incident","Args":[],"Flags":[{"Name":"open","Field":"open","Type":"integer","Help":"Open lists only the incidents that are not closed when it is 1.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many are returned. Anything that is not a positive integer\nuses 50, and higher values are clamped to 50.","Required":false}],"Example":null},{"Service":"patrol","Name":"incident-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.","Method":"GET","Path":"/v1/patrol/incident/:name","Args":[{"Name":"name","Help":"Name is the incident's document name, from the path."}],"Flags":null,"Example":null},{"Service":"patrol","Name":"incident-step","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.","Method":"POST","Path":"/v1/patrol/incident/:name/step","Args":[{"Name":"name","Help":"Name is the incident's document name, from the path."}],"Flags":[{"Name":"act","Field":"act","Type":"string","Help":"Act is VERIFY, DISPATCH, ROLL, ARRIVE, CHECK, SECURE, FILE, CLOSE or\nESCALATE.","Required":false},{"Name":"detail","Field":"detail","Type":"string","Help":"Detail is what to write on the trail with this act.","Required":false},{"Name":"false","Field":"false","Type":"boolean","Help":"False says the activation turned out to be nothing, read by CLOSE.","Required":false},{"Name":"outcome","Field":"outcome","Type":"string","Help":"Outcome is what the incident came to, read by CLOSE.","Required":false},{"Name":"unit","Field":"unit","Type":"string","Help":"Unit is the call sign to send, read by DISPATCH.","Required":false}],"Example":null},{"Service":"patrol","Name":"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.","Method":"GET","Path":"/v1/patrol/key","Args":[],"Flags":null,"Example":null},{"Service":"patrol","Name":"key-get","OperationID":"get_patrol_key_by_name","Summary":"Returns one key set from the register.","Description":"Returns one key set from the register.","Method":"GET","Path":"/v1/patrol/key/:name","Args":[{"Name":"name","Help":"Name is the key set's reference, from the path."}],"Flags":null,"Example":null},{"Service":"patrol","Name":"key-move","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.","Method":"POST","Path":"/v1/patrol/key/:name/move","Args":[{"Name":"name","Help":"Name is the key set's reference, from the path."}],"Flags":[{"Name":"act","Field":"act","Type":"string","Help":"Act is out, in or audit.","Required":false},{"Name":"holder","Field":"holder","Type":"string","Help":"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.","Required":false},{"Name":"job","Field":"job","Type":"string","Help":"Job is the work the keys were drawn for.","Required":false}],"Example":null},{"Service":"patrol","Name":"note-create","OperationID":"post_patrol_note","Summary":"Records an internal remark, stamped with who wrote it.","Description":"Records an internal remark, stamped with who wrote it.","Method":"POST","Path":"/v1/patrol/note","Args":[],"Flags":[{"Name":"body","Field":"body","Type":"string","Help":"Body is the remark.","Required":false},{"Name":"subject","Field":"subject","Type":"string","Help":"Subject is what the note is about.","Required":false}],"Example":null},{"Service":"patrol","Name":"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.","Method":"GET","Path":"/v1/patrol/note","Args":[],"Flags":[{"Name":"subject","Field":"subject","Type":"string","Help":"Subject narrows the list to one subject by exact match. Empty lists every\nnote.","Required":false}],"Example":null},{"Service":"patrol","Name":"point-confirm","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.","Method":"POST","Path":"/v1/patrol/point/:name/confirm","Args":[{"Name":"name","Help":"Name is the checkpoint's document name, from the path."}],"Flags":[{"Name":"lat","Field":"lat","Type":"number","Help":"Lat is the latitude the confirmation was taken at.","Required":false},{"Name":"lon","Field":"lon","Type":"number","Help":"Lon is the longitude the confirmation was taken at.","Required":false},{"Name":"method","Field":"method","Type":"string","Help":"Method is how presence was proved: tag, scan, fence, manual or photo.","Required":false},{"Name":"photo","Field":"photo","Type":"string","Help":"Photo is the object key of a photo taken there, never the bytes.","Required":false}],"Example":null},{"Service":"patrol","Name":"report-create","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.","Method":"POST","Path":"/v1/patrol/report","Args":[],"Flags":[{"Name":"client","Field":"client","Type":"string","Help":"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.","Required":false},{"Name":"from","Field":"from","Type":"string","Help":"From is the start of the window to cover.","Required":false},{"Name":"incident","Field":"incident","Type":"string","Help":"Incident is the incident to report on, required for kind incident.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind is shift, incident or client.","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"To is the end of that window.","Required":false}],"Example":null},{"Service":"patrol","Name":"report-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.","Method":"GET","Path":"/v1/patrol/report/:name","Args":[{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"patrol","Name":"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.","Method":"GET","Path":"/v1/patrol/site","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many sites are returned. Anything that is not a positive\ninteger uses 500, and higher values are clamped to 500.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status narrows the list to ok, fault, alarm or offline. Empty lists every\nstatus.","Required":false}],"Example":null},{"Service":"patrol","Name":"site-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.","Method":"GET","Path":"/v1/patrol/site/:name","Args":[{"Name":"name","Help":"Name is the site's document name, from the path."}],"Flags":null,"Example":null},{"Service":"patrol","Name":"site-update","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.","Method":"PUT","Path":"/v1/patrol/site/:name","Args":[{"Name":"name","Help":"Name is the site's document name, from the path."}],"Flags":[{"Name":"category","Field":"category","Type":"string","Help":"Category is what kind of premises this is.","Required":false},{"Name":"contact","Field":"contact","Type":"string","Help":"Contact is the keyholder to reach.","Required":false},{"Name":"eircode","Field":"eircode","Type":"string","Help":"Eircode is the postal code.","Required":false},{"Name":"notes","Field":"notes","Type":"string","Help":"Notes is the standing brief for the site.","Required":false},{"Name":"sector","Field":"sector","Type":"string","Help":"Sector is the patrol sector the site sits in.","Required":false},{"Name":"sla","Field":"sla","Type":"integer","Help":"SLA is the contracted response time in minutes.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status is ok, fault, alarm or offline.","Required":false},{"Name":"tier","Field":"tier","Type":"string","Help":"Tier is the contracted service tier.","Required":false},{"Name":"town","Field":"town","Type":"string","Help":"Town is the town the site is in.","Required":false}],"Example":null},{"Service":"patrol","Name":"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.","Method":"GET","Path":"/v1/patrol/snapshot","Args":[],"Flags":[{"Name":"events","Field":"events","Type":"integer","Help":"Events caps how many feed rows ride along. Anything that is not a positive\ninteger uses 80, and higher values are clamped to 80.","Required":false}],"Example":null},{"Service":"patrol","Name":"tenant-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.","Method":"GET","Path":"/v1/patrol/tenant/:org","Args":[{"Name":"org","Help":"Org is the IAM org the tenant belongs to, from the path."}],"Flags":null,"Example":null},{"Service":"patrol","Name":"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.","Method":"GET","Path":"/v1/patrol/tour","Args":[],"Flags":[{"Name":"date","Field":"date","Type":"string","Help":"Date narrows the list to one day, as YYYY-MM-DD. \"today\" means today.\nEmpty lists every round held.","Required":false}],"Example":null},{"Service":"patrol","Name":"unit-fix","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.","Method":"POST","Path":"/v1/patrol/unit/:name/fix","Args":[{"Name":"name","Help":"Name is the unit's call sign, from the path."}],"Flags":[{"Name":"at","Field":"at","Type":"string","Help":"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.","Required":false},{"Name":"lat","Field":"lat","Type":"number","Help":"Lat is the latitude in degrees.","Required":false},{"Name":"lon","Field":"lon","Type":"number","Help":"Lon is the longitude in degrees.","Required":false}],"Example":null},{"Service":"patrol","Name":"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.","Method":"GET","Path":"/v1/patrol/unit","Args":[],"Flags":null,"Example":null},{"Service":"patrol","Name":"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.","Method":"GET","Path":"/v1/patrol/unit/near","Args":[],"Flags":[{"Name":"site","Field":"site","Type":"string","Help":"Site is the site to measure from, by document name.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many units come back. Anything that is not a positive\ninteger uses 3, and higher values are clamped to 10.","Required":false}],"Example":null},{"Service":"patrol","Name":"unit-state","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.","Method":"POST","Path":"/v1/patrol/unit/:name/state","Args":[{"Name":"name","Help":"Name is the unit's call sign, from the path."}],"Flags":[{"Name":"state","Field":"state","Type":"string","Help":"State is available, assigned, enroute, onsite, offline, break or emergency.","Required":false}],"Example":null},{"Service":"plan","Name":"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.","Method":"GET","Path":"/v1/plan/blockchain","Args":[],"Flags":null,"Example":null},{"Service":"plan","Name":"dns-list","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.","Method":"GET","Path":"/v1/plan/dns","Args":[],"Flags":null,"Example":null},{"Service":"plan","Name":"entitlements-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.","Method":"GET","Path":"/v1/plan/entitlements/:id","Args":[{"Name":"id","Help":"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."}],"Flags":null,"Example":{"id":"team"}},{"Service":"plan","Name":"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.","Method":"GET","Path":"/v1/plan/gpu","Args":[],"Flags":null,"Example":null},{"Service":"plan","Name":"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.","Method":"GET","Path":"/v1/plan/health","Args":[],"Flags":null,"Example":null},{"Service":"plan","Name":"list","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.","Method":"GET","Path":"/v1/plan","Args":[],"Flags":null,"Example":null},{"Service":"plan","Name":"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.","Method":"GET","Path":"/v1/plan/policy","Args":[],"Flags":null,"Example":null},{"Service":"plan","Name":"regions-list","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.","Method":"GET","Path":"/v1/plan/regions","Args":[],"Flags":null,"Example":null},{"Service":"plan","Name":"resolve-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.","Method":"GET","Path":"/v1/plan/resolve/:id","Args":[{"Name":"id","Help":"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."}],"Flags":null,"Example":{"id":"dev"}},{"Service":"plan","Name":"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.","Method":"GET","Path":"/v1/plan/schema","Args":[],"Flags":null,"Example":null},{"Service":"plan","Name":"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.","Method":"GET","Path":"/v1/plan/storage","Args":[],"Flags":null,"Example":null},{"Service":"plan","Name":"subscriptions-list","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.","Method":"GET","Path":"/v1/plan/subscriptions","Args":[],"Flags":null,"Example":null},{"Service":"plan","Name":"tools-list","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.","Method":"GET","Path":"/v1/plan/tools","Args":[],"Flags":null,"Example":null},{"Service":"plan","Name":"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.","Method":"GET","Path":"/v1/plan/vocab","Args":[],"Flags":null,"Example":null},{"Service":"platform","Name":"apps-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.","Method":"GET","Path":"/v1/platform/apps/:app/cd","Args":[{"Name":"app","Help":"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."}],"Flags":[{"Name":"org","Field":"org","Type":"string","Help":"Org names the organisation the declaration lives in, defaulting to the\ncaller's own and subject to the same SuperAdmin rule as the listing.","Required":false}],"Example":null},{"Service":"platform","Name":"apps-create","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.","Method":"POST","Path":"/v1/platform/apps","Args":[],"Flags":[{"Name":"build","Field":"build","Type":"boolean","Help":"","Required":false},{"Name":"dockerfile","Field":"dockerfile","Type":"string","Help":"","Required":false},{"Name":"env","Field":"env","Type":"json","Help":"","Required":false},{"Name":"host","Field":"host","Type":"string","Help":"","Required":false},{"Name":"mode","Field":"mode","Type":"string","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"org","Field":"org","Type":"string","Help":"","Required":false},{"Name":"part-of","Field":"partOf","Type":"string","Help":"","Required":false},{"Name":"port","Field":"port","Type":"integer","Help":"","Required":false},{"Name":"ref","Field":"ref","Type":"string","Help":"","Required":false},{"Name":"replicas","Field":"replicas","Type":"integer","Help":"","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"","Required":false},{"Name":"tag","Field":"tag","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"platform","Name":"apps-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.","Method":"GET","Path":"/v1/platform/apps/:app","Args":[{"Name":"app","Help":"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."}],"Flags":[{"Name":"org","Field":"org","Type":"string","Help":"Org names the organisation the declaration lives in, defaulting to the\ncaller's own and subject to the same SuperAdmin rule as the listing.","Required":false}],"Example":null},{"Service":"platform","Name":"apps-list","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.","Method":"GET","Path":"/v1/platform/apps","Args":[],"Flags":[{"Name":"org","Field":"org","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"platform","Name":"apps-project-update","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.","Method":"PUT","Path":"/v1/platform/apps/:app/project","Args":[{"Name":"app","Help":"App is the declaration's name, from the path."}],"Flags":[{"Name":"mode","Field":"mode","Type":"string","Help":"Mode is `branch` (the default) or `commit`.","Required":false},{"Name":"org","Field":"org","Type":"string","Help":"Org is the values directory the app lives in, defaulting to the caller's own\norg.","Required":false},{"Name":"part-of","Field":"partOf","Type":"string","Help":"PartOf is the project to move it to. A name nothing names yet creates it.","Required":false}],"Example":null},{"Service":"platform","Name":"builds-list","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.","Method":"GET","Path":"/v1/platform/builds","Args":[],"Flags":null,"Example":null},{"Service":"platform","Name":"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.","Method":"GET","Path":"/v1/platform/cd","Args":[],"Flags":null,"Example":null},{"Service":"platform","Name":"environments-list","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.","Method":"GET","Path":"/v1/platform/environments","Args":[],"Flags":null,"Example":null},{"Service":"platform","Name":"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.","Method":"GET","Path":"/v1/platform/fleet","Args":[],"Flags":[{"Name":"env","Field":"env","Type":"string","Help":"Env narrows to one lifecycle env: main, test or dev.","Required":false},{"Name":"health","Field":"health","Type":"string","Help":"Health narrows to one health colour: green, yellow or red.","Required":false},{"Name":"org","Field":"org","Type":"string","Help":"Org narrows to one image namespace.","Required":false},{"Name":"drift","Field":"drift","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"platform","Name":"fleet-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.","Method":"GET","Path":"/v1/platform/fleet/:app","Args":[{"Name":"app","Help":"App is the service's CR name, from the path. It must be a DNS-1123 label."}],"Flags":[{"Name":"env","Field":"env","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"platform","Name":"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.","Method":"GET","Path":"/v1/platform/health","Args":[],"Flags":null,"Example":null},{"Service":"platform","Name":"pipelines-list","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.","Method":"GET","Path":"/v1/platform/pipelines","Args":[],"Flags":null,"Example":null},{"Service":"platform","Name":"projects-apps","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.","Method":"POST","Path":"/v1/platform/projects/:project/apps","Args":[{"Name":"project","Help":"Project is the project to create the application under, from the path."}],"Flags":[{"Name":"build-type","Field":"buildType","Type":"string","Help":"BuildType is `pack` — the zero-config default that detects any project —\nor `dockerfile`, the explicit escape hatch. An image app never builds.","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"Description is free text about what the application is.","Required":false},{"Name":"dockerfile","Field":"dockerfile","Type":"string","Help":"Dockerfile is the path to build from, for buildType `dockerfile`.","Required":false},{"Name":"domains","Field":"domains","Type":"json","Help":"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.","Required":false},{"Name":"env","Field":"env","Type":"json","Help":"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.","Required":false},{"Name":"environment","Field":"environment","Type":"string","Help":"Environment is the deploy target this app names (\"production\" by default).","Required":false},{"Name":"image","Field":"image","Type":"json","Help":"Image is the container image to run, for source `image`.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the application's display name. Required; the slug is derived from\nit when none is given.","Required":false},{"Name":"port","Field":"port","Type":"integer","Help":"Port is the container port the app listens on.","Required":false},{"Name":"replicas","Field":"replicas","Type":"integer","Help":"Replicas is how many copies to run; clamped to the deployment's limit\nrather than refused.","Required":false},{"Name":"repo","Field":"repo","Type":"json","Help":"Repo is the git source to build from, for source `git`.","Required":false},{"Name":"slug","Field":"slug","Type":"string","Help":"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.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source is `git`, which requires repo.url, or `image`, which requires\nimage.repository. Anything else is 400.","Required":false},{"Name":"storage-gb","Field":"storageGb","Type":"integer","Help":"StorageGB is the persistent volume size in GiB; absent means stateless.\nClamped to the deployment's limit rather than refused.","Required":false}],"Example":null},{"Service":"platform","Name":"projects-apps-list","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.","Method":"GET","Path":"/v1/platform/projects/:project/apps","Args":[{"Name":"project","Help":"Project is the project's name, from the path."}],"Flags":null,"Example":null},{"Service":"platform","Name":"projects-create","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.","Method":"POST","Path":"/v1/platform/projects","Args":[],"Flags":[{"Name":"apps","Field":"apps","Type":"json","Help":"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.","Required":false},{"Name":"mode","Field":"mode","Type":"string","Help":"Mode is `branch` (the default: a review branch, nothing deploys) or `commit`\n(main).","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the project, a DNS-1123 label; it becomes each app's `partOf`.","Required":false},{"Name":"org","Field":"org","Type":"string","Help":"Org names the project's owner, defaulting to the caller's own scope; naming\nanother is an act-as only a SuperAdmin has.","Required":false}],"Example":null},{"Service":"platform","Name":"projects-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.","Method":"DELETE","Path":"/v1/platform/projects/:project","Args":[{"Name":"project","Help":"Project is the project to delete, from the path."}],"Flags":[{"Name":"into","Field":"into","Type":"string","Help":"Into is the existing project its apps move into. Required: an app always\nbelongs to exactly one project.","Required":false},{"Name":"org","Field":"org","Type":"string","Help":"Org names the projects' owner, defaulting to the caller's own scope.","Required":false},{"Name":"mode","Field":"mode","Type":"string","Help":"Mode is `branch` (the default) or `commit`.","Required":false}],"Example":null},{"Service":"platform","Name":"projects-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.","Method":"DELETE","Path":"/v1/platform/projects/:project/apps/:app","Args":[{"Name":"project","Help":"Project is the project the application lives under, from the path."},{"Name":"app","Help":"App is the application's slug, from the path."}],"Flags":null,"Example":null},{"Service":"platform","Name":"projects-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.","Method":"DELETE","Path":"/v1/platform/projects/:project/apps/:app/domains/:host","Args":[{"Name":"project","Help":"Project is the project the application lives under, from the path."},{"Name":"app","Help":"App is the application's slug, from the path."},{"Name":"host","Help":"Host is the hostname, from the path."}],"Flags":null,"Example":null},{"Service":"platform","Name":"projects-deploy","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.","Method":"POST","Path":"/v1/platform/projects/:project/apps/:app/deploy","Args":[{"Name":"project","Help":"Project is the project the application lives under, from the path."},{"Name":"app","Help":"App is the application's slug, from the path."}],"Flags":[{"Name":"commit","Field":"commit","Type":"string","Help":"Commit is the git commit or ref to build, for a git-source app. Defaults to\nthe app's branch.","Required":false},{"Name":"tag","Field":"tag","Type":"string","Help":"Tag is the image tag to deploy, for an image-source app. Defaults to the\napp's tag, then `latest`.","Required":false}],"Example":null},{"Service":"platform","Name":"projects-deployments-list","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.","Method":"GET","Path":"/v1/platform/projects/:project/apps/:app/deployments","Args":[{"Name":"project","Help":"Project is the project the application lives under, from the path."},{"Name":"app","Help":"App is the application's slug, from the path."}],"Flags":null,"Example":null},{"Service":"platform","Name":"projects-domains","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.","Method":"POST","Path":"/v1/platform/projects/:project/apps/:app/domains","Args":[{"Name":"project","Help":"Project is the project the application lives under, from the path."},{"Name":"app","Help":"App is the application's slug, from the path."}],"Flags":[{"Name":"host","Field":"host","Type":"string","Help":"Host is the hostname to attach. Required, and must be a valid DNS hostname.","Required":false}],"Example":null},{"Service":"platform","Name":"projects-domains-list","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.","Method":"GET","Path":"/v1/platform/projects/:project/apps/:app/domains","Args":[{"Name":"project","Help":"Project is the project the application lives under, from the path."},{"Name":"app","Help":"App is the application's slug, from the path."}],"Flags":null,"Example":null},{"Service":"platform","Name":"projects-env-update","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.","Method":"PUT","Path":"/v1/platform/projects/:project/apps/:app/env","Args":[{"Name":"project","Help":"Project is the project the application lives under, from the path."},{"Name":"app","Help":"App is the application's slug, from the path."}],"Flags":[{"Name":"env","Field":"env","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"platform","Name":"projects-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.","Method":"GET","Path":"/v1/platform/projects/:project","Args":[{"Name":"project","Help":"Project is the project's name, from the path."}],"Flags":[{"Name":"org","Field":"org","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"platform","Name":"projects-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.","Method":"GET","Path":"/v1/platform/projects/:project/apps/:app","Args":[{"Name":"project","Help":"Project is the project the application lives under, from the path."},{"Name":"app","Help":"App is the application's slug, from the path."}],"Flags":null,"Example":null},{"Service":"platform","Name":"projects-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.","Method":"GET","Path":"/v1/platform/projects/:project/apps/:app/deployments/:id","Args":[{"Name":"project","Help":"Project is the project the application lives under, from the path."},{"Name":"app","Help":"App is the application's slug, from the path."},{"Name":"id","Help":"ID is the deployment's id, from the path."}],"Flags":null,"Example":null},{"Service":"platform","Name":"projects-list","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.","Method":"GET","Path":"/v1/platform/projects","Args":[],"Flags":[{"Name":"org","Field":"org","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"platform","Name":"projects-logs-list","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.","Method":"GET","Path":"/v1/platform/projects/:project/apps/:app/deployments/:id/logs","Args":[{"Name":"project","Help":"Project is the project the application lives under, from the path."},{"Name":"app","Help":"App is the application's slug, from the path."},{"Name":"id","Help":"ID is the deployment's id, from the path."}],"Flags":null,"Example":null},{"Service":"platform","Name":"projects-preview","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.","Method":"POST","Path":"/v1/platform/projects/:project/apps/:app/preview","Args":[{"Name":"project","Help":"Project is the project the parent application lives under, from the path."},{"Name":"app","Help":"App is the parent application's slug, from the path."}],"Flags":[{"Name":"branch","Field":"branch","Type":"string","Help":"Branch is the branch to preview; defaults to the parent app's branch.","Required":false},{"Name":"image","Field":"image","Type":"string","Help":"Image is the already-built image ref to deploy. Required — a preview never\nbuilds.","Required":false}],"Example":null},{"Service":"platform","Name":"projects-promote","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.","Method":"POST","Path":"/v1/platform/projects/:project/apps/:app/promote","Args":[{"Name":"project","Help":"Project is the project the application lives under, from the path."},{"Name":"app","Help":"App is the application's slug, from the path."}],"Flags":[{"Name":"deployment-id","Field":"deploymentId","Type":"string","Help":"DeploymentID promotes that deployment's exact built image. One of this and\nTag is required.","Required":false},{"Name":"tag","Field":"tag","Type":"string","Help":"Tag promotes an image tag, resolved the same way a deploy resolves one.","Required":false}],"Example":null},{"Service":"platform","Name":"projects-rollback","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.","Method":"POST","Path":"/v1/platform/projects/:project/apps/:app/rollback","Args":[{"Name":"project","Help":"Project is the project the application lives under, from the path."},{"Name":"app","Help":"App is the application's slug, from the path."}],"Flags":[{"Name":"deployment-id","Field":"deploymentId","Type":"string","Help":"DeploymentID is the deployment to redeploy. Omit it to return to the\nprevious release.","Required":false}],"Example":null},{"Service":"platform","Name":"projects-start","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.","Method":"POST","Path":"/v1/platform/projects/:project/apps/:app/start","Args":[{"Name":"project","Help":"Project is the project the application lives under, from the path."},{"Name":"app","Help":"App is the application's slug, from the path."}],"Flags":null,"Example":null},{"Service":"platform","Name":"projects-stop","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.","Method":"POST","Path":"/v1/platform/projects/:project/apps/:app/stop","Args":[{"Name":"project","Help":"Project is the project the application lives under, from the path."},{"Name":"app","Help":"App is the application's slug, from the path."}],"Flags":null,"Example":null},{"Service":"platform","Name":"projects-update","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.","Method":"PUT","Path":"/v1/platform/projects/:project","Args":[{"Name":"project","Help":"Project is the project to rename, from the path."}],"Flags":[{"Name":"mode","Field":"mode","Type":"string","Help":"Mode is `branch` (the default) or `commit`.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is its new name, which no app may already name.","Required":false},{"Name":"org","Field":"org","Type":"string","Help":"Org names the project's owner, defaulting to the caller's own scope.","Required":false}],"Example":null},{"Service":"platform","Name":"projects-verify","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.","Method":"POST","Path":"/v1/platform/projects/:project/apps/:app/domains/:host/verify","Args":[{"Name":"project","Help":"Project is the project the application lives under, from the path."},{"Name":"app","Help":"App is the application's slug, from the path."},{"Name":"host","Help":"Host is the hostname, from the path."}],"Flags":null,"Example":null},{"Service":"platform","Name":"releases-list","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.","Method":"GET","Path":"/v1/platform/releases","Args":[],"Flags":null,"Example":null},{"Service":"platform","Name":"run-create","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.","Method":"POST","Path":"/v1/platform/run","Args":[],"Flags":[{"Name":"env","Field":"env","Type":"json","Help":"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.","Required":false},{"Name":"gpu","Field":"gpu","Type":"integer","Help":"GPU is how many GPUs the run asks for; a negative value is 400.","Required":false},{"Name":"image","Field":"image","Type":"string","Help":"Image is the container image to run. Required.","Required":false},{"Name":"max-scale","Field":"maxScale","Type":"integer","Help":"MaxScale above the floor declares an autoscaling ceiling; 0 means no\nautoscaler at all — a fixed run at the floor.","Required":false},{"Name":"min-scale","Field":"minScale","Type":"integer","Help":"MinScale is the replica floor, clamped to the deployment's limit.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false},{"Name":"port","Field":"port","Type":"integer","Help":"Port is the container port the run listens on.","Required":false},{"Name":"runtime","Field":"runtime","Type":"string","Help":"Runtime is accepted for the client contract and echoed nowhere: the image\nIS the runtime unit.","Required":false},{"Name":"shape","Field":"shape","Type":"string","Help":"Shape is a compute size label, echoed back; sizing is the operator's\ndefault. Defaults to \"auto\".","Required":false}],"Example":null},{"Service":"pref","Name":"list","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.","Method":"GET","Path":"/v1/pref","Args":[],"Flags":null,"Example":null},{"Service":"pref","Name":"update","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.","Method":"PATCH","Path":"/v1/pref","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"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.","Method":"GET","Path":"/v1/pricing/base","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"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.","Method":"GET","Path":"/v1/pricing/blockchain","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"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.","Method":"GET","Path":"/v1/pricing/cloud","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"cloud-plans-list","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.","Method":"GET","Path":"/v1/pricing/cloud/plans","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"cloud-regions-list","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.","Method":"GET","Path":"/v1/pricing/cloud/regions","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"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.","Method":"GET","Path":"/v1/pricing/cloud/storage","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"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.","Method":"GET","Path":"/v1/pricing/compute","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"compute-presets-list","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.","Method":"GET","Path":"/v1/pricing/compute/presets","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"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\".","Method":"GET","Path":"/v1/pricing/datastore","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"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.","Method":"GET","Path":"/v1/pricing/enablement","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"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.","Method":"GET","Path":"/v1/pricing/featured","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"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.","Method":"GET","Path":"/v1/pricing/free","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"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.","Method":"GET","Path":"/v1/pricing/gpu","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"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.","Method":"GET","Path":"/v1/pricing/health","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"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.","Method":"GET","Path":"/v1/pricing/iam","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"list","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.","Method":"GET","Path":"/v1/pricing","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"model-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.","Method":"GET","Path":"/v1/pricing/model/:name","Args":[{"Name":"name","Help":"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."}],"Flags":null,"Example":{"name":"zen4"}},{"Service":"pricing","Name":"models-list","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.","Method":"GET","Path":"/v1/pricing/models","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"paas-list","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.","Method":"GET","Path":"/v1/pricing/paas","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"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.","Method":"GET","Path":"/v1/pricing/policy","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"providers-list","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.","Method":"GET","Path":"/v1/pricing/providers","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"services-list","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.","Method":"GET","Path":"/v1/pricing/services","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"subscriptions-list","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.","Method":"GET","Path":"/v1/pricing/subscriptions","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"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.","Method":"GET","Path":"/v1/pricing/summary","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"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.","Method":"GET","Path":"/v1/pricing/tariff","Args":[],"Flags":null,"Example":null},{"Service":"pricing","Name":"tools-list","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.","Method":"GET","Path":"/v1/pricing/tools","Args":[],"Flags":null,"Example":null},{"Service":"principal","Name":"agents-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.","Method":"GET","Path":"/v1/principal/agents/:ref","Args":[{"Name":"ref","Help":"Ref is the agent's id or its name in the caller's org."}],"Flags":null,"Example":null},{"Service":"principal","Name":"clearance-create","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.","Method":"POST","Path":"/v1/principal/clearance","Args":[],"Flags":[{"Name":"amount","Field":"amount","Type":"string","Help":"Amount is the gross amount in U.S. dollars, e.g. \"1250.00\".","Required":false},{"Name":"category","Field":"category","Type":"string","Help":"Category is what is bought: services, attorney, rents, royalties, other or\nmerchandise. Services when omitted.","Required":false},{"Name":"payee","Field":"payee","Type":"string","Help":"Payee is the org id of the org to be paid.","Required":false},{"Name":"performed","Field":"performed","Type":"string","Help":"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.","Required":false},{"Name":"platform","Field":"platform","Type":"boolean","Help":"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.","Required":false},{"Name":"rail","Field":"rail","Type":"string","Help":"Rail is how it will move: x402, ledger, chain, ach, wire, card, network or\nother — the rails an economic event names. Ledger when omitted.","Required":false}],"Example":{"amount":"5000.00","category":"services","payee":"globex","performed":"DE"}},{"Service":"principal","Name":"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.","Method":"GET","Path":"/v1/principal/clearance","Args":[],"Flags":[{"Name":"payee","Field":"payee","Type":"string","Help":"Payee narrows to one payee.","Required":false}],"Example":null},{"Service":"principal","Name":"clearance-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.","Method":"GET","Path":"/v1/principal/clearance/:id","Args":[{"Name":"id","Help":"ID is the clearance, \"clr_\"-prefixed."}],"Flags":null,"Example":null},{"Service":"principal","Name":"keys-list","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.","Method":"GET","Path":"/v1/principal/keys","Args":[],"Flags":null,"Example":null},{"Service":"principal","Name":"list","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.","Method":"GET","Path":"/v1/principal","Args":[],"Flags":null,"Example":null},{"Service":"principal","Name":"statements-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.","Method":"GET","Path":"/v1/principal/statements/:id","Args":[{"Name":"id","Help":"ID is the statement's jti, as its JWS carries it."}],"Flags":null,"Example":null},{"Service":"project","Name":"activate","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.","Method":"POST","Path":"/v1/project/:slug/releases/:release/activate","Args":[{"Name":"slug","Help":"Slug is the site the release belongs to, from the path."},{"Name":"release","Help":"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."}],"Flags":null,"Example":null},{"Service":"project","Name":"complete","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.","Method":"POST","Path":"/v1/project/:slug/deployments/:id/complete","Args":[{"Name":"slug","Help":"Slug is the project the deployment belongs to, from the path."},{"Name":"id","Help":"ID is the queued deployment to complete, from the path."}],"Flags":[{"Name":"bytes","Field":"bytes","Type":"integer","Help":"Bytes is their total size in bytes.","Required":false},{"Name":"commit","Field":"commit","Type":"string","Help":"Commit is the revision that was built, recorded on the deployment.","Required":false},{"Name":"copy","Field":"copy","Type":"json","Help":"Copy lists the keys to take from CopyFrom's prefix, relative to it. They are\nalso named in Keys, which stays the whole release.","Required":false},{"Name":"copy-from","Field":"copyFrom","Type":"string","Help":"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.","Required":false},{"Name":"files","Field":"files","Type":"integer","Help":"Files is how many objects CI published.","Required":false},{"Name":"keys","Field":"keys","Type":"json","Help":"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.","Required":false},{"Name":"live-url","Field":"liveUrl","Type":"string","Help":"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.","Required":false},{"Name":"message","Field":"message","Type":"string","Help":"Message is what happened, in words — on an error completion, why it failed.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status is how the build ended: `live` if it succeeded, `error` if it did not.\nNothing else is accepted.","Required":false}],"Example":null},{"Service":"project","Name":"create","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.","Method":"POST","Path":"/v1/project","Args":[],"Flags":[{"Name":"analytics","Field":"analytics","Type":"boolean","Help":"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.","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"Description is the one-line summary, copied onto anything forked from this\nproject.","Required":false},{"Name":"framework","Field":"framework","Type":"string","Help":"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.","Required":false},{"Name":"license","Field":"license","Type":"string","Help":"License is the terms that upstream work carries.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false},{"Name":"repo","Field":"repo","Type":"json","Help":"Repo links a git source, so pushes to it rebuild this project. Omit it for a\nproject deployed by uploading an artifact.","Required":false},{"Name":"slug","Field":"slug","Type":"string","Help":"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.","Required":false},{"Name":"upstream","Field":"upstream","Type":"string","Help":"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.","Required":false},{"Name":"visibility","Field":"visibility","Type":"string","Help":"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).","Required":false}],"Example":null},{"Service":"project","Name":"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.","Method":"DELETE","Path":"/v1/project/:slug","Args":[{"Name":"slug","Help":"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."}],"Flags":null,"Example":null},{"Service":"project","Name":"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.","Method":"DELETE","Path":"/v1/project/:slug/domains/:host","Args":[{"Name":"slug","Help":"Slug is the project the host is attached to, from the path."},{"Name":"host","Help":"Host is the custom hostname, from the path. It is cleaned to its canonical\nform (lowercased, trailing dot dropped) before anything is looked up."}],"Flags":null,"Example":null},{"Service":"project","Name":"deploy","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.","Method":"POST","Path":"/v1/project/:slug/deploy","Args":[{"Name":"slug","Help":""}],"Flags":[{"Name":"body","Field":"body","Type":"file","Help":"","Required":false,"In":"body"}],"Example":null,"Consumes":["application/octet-stream"]},{"Service":"project","Name":"deployments","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.","Method":"POST","Path":"/v1/project/:slug/deployments","Args":[{"Name":"slug","Help":"Slug is the site to deploy, from the path."}],"Flags":[{"Name":"commit","Field":"commit","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"project","Name":"deployments-list","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.","Method":"GET","Path":"/v1/project/:slug/deployments","Args":[{"Name":"slug","Help":"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."}],"Flags":null,"Example":null},{"Service":"project","Name":"domains","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.","Method":"POST","Path":"/v1/project/:slug/domains","Args":[{"Name":"slug","Help":"Slug is the site the hosts attach to, from the path."}],"Flags":[{"Name":"domains","Field":"domains","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"project","Name":"domains-list","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.","Method":"GET","Path":"/v1/project/:slug/domains","Args":[{"Name":"slug","Help":"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."}],"Flags":null,"Example":null},{"Service":"project","Name":"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.","Method":"GET","Path":"/v1/project/edge","Args":[],"Flags":null,"Example":null},{"Service":"project","Name":"fork-create","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.","Method":"POST","Path":"/v1/project/fork","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"target project name (optional; defaults to the parent's title)","Required":false},{"Name":"slug","Field":"slug","Type":"string","Help":"parent slug to fork — catalog template or published project (required)","Required":false},{"Name":"target","Field":"target","Type":"string","Help":"Target overrides the derived project slug (optional; defaults to the\nparent slug). Kept distinct from Slug so callers can rename on fork.","Required":false},{"Name":"variant","Field":"variant","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"project","Name":"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.","Method":"GET","Path":"/v1/project/:slug","Args":[{"Name":"slug","Help":"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."}],"Flags":null,"Example":null},{"Service":"project","Name":"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.","Method":"GET","Path":"/v1/project/:slug/deployments/:id","Args":[{"Name":"slug","Help":"Slug is the project the deployment belongs to, from the path."},{"Name":"id","Help":"ID is the deployment id, from the path. A deployment of another project —\nor of another tenant's project — is not found."}],"Flags":null,"Example":null},{"Service":"project","Name":"list","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.","Method":"GET","Path":"/v1/project","Args":[],"Flags":null,"Example":null},{"Service":"project","Name":"publish","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.","Method":"POST","Path":"/v1/project/:slug/publish","Args":[{"Name":"slug","Help":"Slug is the site to publish, from the path."}],"Flags":[{"Name":"source","Field":"source","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"project","Name":"purge","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.","Method":"POST","Path":"/v1/project/:slug/purge","Args":[{"Name":"slug","Help":"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."}],"Flags":null,"Example":null},{"Service":"project","Name":"releases","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.","Method":"POST","Path":"/v1/project/:slug/releases","Args":[{"Name":"slug","Help":"Slug is the site to publish, from the path."}],"Flags":[{"Name":"source","Field":"source","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"project","Name":"releases-list","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.","Method":"GET","Path":"/v1/project/:slug/releases","Args":[{"Name":"slug","Help":"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."}],"Flags":null,"Example":null},{"Service":"project","Name":"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.","Method":"GET","Path":"/v1/project/:slug/shot","Args":[{"Name":"slug","Help":""}],"Flags":null,"Example":null},{"Service":"project","Name":"sites-create","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.","Method":"POST","Path":"/v1/project/sites","Args":[],"Flags":[{"Name":"brief","Field":"brief","Type":"string","Help":"Brief is what the site should be, in plain language. It is the whole input the\nmodel gets and it is size-bounded.","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"Model names which model writes the site. Absent takes the deployment's\ndefault — this route spends inference on the caller's org either way.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the site's display name. Taken from what the model writes when omitted.","Required":false},{"Name":"slug","Field":"slug","Type":"string","Help":"Slug is the handle and public host label to publish under. Derived from the\nname, or from the brief, when omitted.","Required":false}],"Example":null},{"Service":"project","Name":"sites-deploy-create","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.","Method":"POST","Path":"/v1/project/sites/deploy","Args":[],"Flags":[{"Name":"files","Field":"files","Type":"json","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the site's display name.","Required":false},{"Name":"slug","Field":"slug","Type":"string","Help":"Slug is the handle and public host label to publish under.","Required":false}],"Example":null},{"Service":"project","Name":"sites-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.","Method":"GET","Path":"/v1/project/sites/:slug","Args":[{"Name":"slug","Help":"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."}],"Flags":null,"Example":null},{"Service":"project","Name":"sites-list","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.","Method":"GET","Path":"/v1/project/sites","Args":[],"Flags":null,"Example":null},{"Service":"project","Name":"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.","Method":"DELETE","Path":"/v1/project/:slug/star","Args":[{"Name":"slug","Help":"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."}],"Flags":null,"Example":null},{"Service":"project","Name":"star-update","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.","Method":"PUT","Path":"/v1/project/:slug/star","Args":[{"Name":"slug","Help":"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."}],"Flags":null,"Example":null},{"Service":"project","Name":"tags-list","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.","Method":"GET","Path":"/v1/project/tags","Args":[],"Flags":null,"Example":null},{"Service":"project","Name":"update","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.","Method":"PATCH","Path":"/v1/project/:slug","Args":[{"Name":"slug","Help":"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."}],"Flags":[{"Name":"cache-control","Field":"cacheControl","Type":"string","Help":"CacheControl replaces the Cache-Control policy the edge serves this site's\nHTML under. Absent leaves it.","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"Description replaces the one-line summary. Absent leaves it.","Required":false},{"Name":"drop-local","Field":"dropLocal","Type":"boolean","Help":"DropLocal turns the drop of localhost events at ingest on or off. Absent leaves it.","Required":false},{"Name":"framework","Field":"framework","Type":"string","Help":"Framework replaces the build hint. It affects the NEXT build only — nothing\nalready deployed is rebuilt.","Required":false},{"Name":"hidden","Field":"hidden","Type":"boolean","Help":"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.","Required":false},{"Name":"hidden-reason","Field":"hiddenReason","Type":"string","Help":"HiddenReason records WHY moderation hid it, so the action can be explained\nand reviewed later. Admin-gated like hidden itself.","Required":false},{"Name":"internal-networks","Field":"internalNetworks","Type":"json","Help":"InternalNetworks replaces the site's own addresses: CIDRs or bare addresses, at\nmost 64. Absent leaves them; send [] to clear.","Required":false},{"Name":"license","Field":"license","Type":"string","Help":"License is the terms that upstream work carries, with the same clear-versus-\nleave rule.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name replaces the display name. Absent leaves it; the slug never moves with it.","Required":false},{"Name":"repo","Field":"repo","Type":"json","Help":"Repo relinks the git source. Absent leaves the existing link.","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"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).","Required":false},{"Name":"upstream","Field":"upstream","Type":"string","Help":"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.","Required":false},{"Name":"visibility","Field":"visibility","Type":"string","Help":"Visibility flips an existing project between \"public\" and \"private\". Same\nONE rule as at create: public is free, private needs a paid plan.","Required":false}],"Example":null},{"Service":"project","Name":"verify","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\".","Method":"POST","Path":"/v1/project/:slug/domains/:host/verify","Args":[{"Name":"slug","Help":"Slug is the project the host is attached to, from the path."},{"Name":"host","Help":"Host is the custom hostname, from the path. It is cleaned to its canonical\nform (lowercased, trailing dot dropped) before anything is looked up."}],"Flags":null,"Example":null},{"Service":"prompt","Name":"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.","Method":"GET","Path":"/v1/prompt/catalog","Args":[],"Flags":null,"Example":null},{"Service":"prompt","Name":"create","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.","Method":"POST","Path":"/v1/prompt","Args":[],"Flags":[{"Name":"labels","Field":"labels","Type":"json","Help":"Labels is free-form taxonomy, each up to 64 characters, capped at 32 entries.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false},{"Name":"prompt","Field":"prompt","Type":"string","Help":"Prompt is the template body, capped at 64 KiB. It holds template text only —\nnever a secret.","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"Tags is free-form taxonomy under the same bounds as Labels.","Required":false},{"Name":"type","Field":"type","Type":"string","Help":"Type labels the template's kind; defaults to \"text\".","Required":false}],"Example":{"name":"greeting","prompt":"You are a helpful assistant.","tags":["support"]}},{"Service":"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.","Method":"DELETE","Path":"/v1/prompt/:name","Args":[{"Name":"name","Help":"Name is the prompt to act on, from the path."}],"Flags":null,"Example":{"name":"greeting"}},{"Service":"prompt","Name":"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.","Method":"GET","Path":"/v1/prompt/:name","Args":[{"Name":"name","Help":"Name is the prompt to act on, from the path."}],"Flags":null,"Example":{"name":"greeting"}},{"Service":"prompt","Name":"list","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.","Method":"GET","Path":"/v1/prompt","Args":[],"Flags":null,"Example":null},{"Service":"prompt","Name":"metrics-list","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.","Method":"GET","Path":"/v1/prompt/metrics","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/:provider/callback","Args":[{"Name":"provider","Help":""}],"Flags":null,"Example":null},{"Service":"provider","Name":"connect","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).","Method":"POST","Path":"/v1/provider/:provider/connect","Args":[{"Name":"provider","Help":"Provider is the connector's registry id, from the :provider path segment."}],"Flags":[{"Name":"account-id","Field":"accountId","Type":"string","Help":"AccountID is the provider account the credential should be scoped to, for the\nproviders whose Verify needs one (Cloudflare). Ignored by the OAuth path.","Required":false},{"Name":"fields","Field":"fields","Type":"json","Help":"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.","Required":false},{"Name":"return","Field":"return","Type":"string","Help":"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.","Required":false},{"Name":"token","Field":"token","Type":"string","Help":"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.","Required":false}],"Example":{"accountId":"a1b2c3","provider":"cloudflare","token":"cf-scoped-api-token"}},{"Service":"provider","Name":"disconnect","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.","Method":"POST","Path":"/v1/provider/:provider/disconnect","Args":[{"Name":"provider","Help":"Provider is the connector's registry id, from the :provider path segment."}],"Flags":[{"Name":"account","Field":"account","Type":"string","Help":"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.","Required":false}],"Example":{"account":"acme","provider":"github"}},{"Service":"provider","Name":"discord-interactions-create","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.","Method":"POST","Path":"/v1/provider/discord/interactions","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/discord/link/callback","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/discord/link/discord","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/discord/link","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"forge-webhook-create","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.","Method":"POST","Path":"/v1/provider/forge/webhook","Args":[],"Flags":[{"Name":"action","Field":"action","Type":"string","Help":"","Required":false},{"Name":"repository","Field":"repository","Type":"json","Help":"","Required":false},{"Name":"workflow-job","Field":"workflow_job","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/:provider","Args":[{"Name":"provider","Help":"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."}],"Flags":null,"Example":{"provider":"slack"}},{"Service":"provider","Name":"github-fork-create","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.","Method":"POST","Path":"/v1/provider/github/fork","Args":[],"Flags":[{"Name":"org","Field":"org","Type":"string","Help":"Org is the GitHub account to fork INTO; empty forks to the installation's\nown account, which is the common case.","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"Repo is a repository the org's installation was GRANTED, by name.","Required":false}],"Example":{"repo":"widgets"}},{"Service":"provider","Name":"github-installations-list","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.","Method":"GET","Path":"/v1/provider/github/installations","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"github-issues-backfill-create","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.","Method":"POST","Path":"/v1/provider/github/issues/backfill","Args":[],"Flags":[{"Name":"repo","Field":"repo","Type":"string","Help":"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\".","Required":false},{"Name":"state","Field":"state","Type":"string","Help":"State is the GitHub issue state to walk: \"open\" (the default), \"closed\" or\n\"all\". Anything else is a 400.","Required":false}],"Example":{"repo":"acme/api","state":"all"}},{"Service":"provider","Name":"github-repos-branches-list","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.","Method":"GET","Path":"/v1/provider/github/repos/:owner/:repo/branches","Args":[{"Name":"owner","Help":"Owner is the GitHub account that holds the repository."},{"Name":"repo","Help":"Repo is the repository's name within that account."}],"Flags":[{"Name":"q","Field":"q","Type":"string","Help":"Q keeps branches whose name starts with it, matched by GitHub.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit is the page size: 1 to 100, and 50 when absent or unreadable.","Required":false},{"Name":"after","Field":"after","Type":"string","Help":"After is the `next` of the previous page.","Required":false}],"Example":{"owner":"hanzoai","q":"feat/","repo":"cloud"}},{"Service":"provider","Name":"github-repos-import-create","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.","Method":"POST","Path":"/v1/provider/github/repos/import","Args":[],"Flags":[{"Name":"all","Field":"all","Type":"boolean","Help":"All imports every repository the installation grants, instead of naming\nthem. Archived and disabled repositories are skipped either way — they\ncannot be fetched.","Required":false},{"Name":"repos","Field":"repos","Type":"json","Help":"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.","Required":false}],"Example":{"repos":["widgets"]}},{"Service":"provider","Name":"github-repos-list","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.","Method":"GET","Path":"/v1/provider/github/repos","Args":[],"Flags":[{"Name":"q","Field":"q","Type":"string","Help":"Q keeps repositories whose owner/name contains it, case-insensitively.","Required":false},{"Name":"owner","Field":"owner","Type":"string","Help":"Owner keeps one GitHub account's repositories — an org or a user login.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit is the page size: 1 to 100, and 50 when absent or unreadable.","Required":false},{"Name":"after","Field":"after","Type":"string","Help":"After is the `next` of the previous page. Absent starts at the most\nrecently pushed.","Required":false}],"Example":{"limit":50,"q":"cloud"}},{"Service":"provider","Name":"github-repos-pages","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).","Method":"POST","Path":"/v1/provider/github/repos/:repo/pages","Args":[{"Name":"repo","Help":"Repo is the repository, from the :repo path segment."}],"Flags":[{"Name":"branch","Field":"branch","Type":"string","Help":"Branch is the legacy source branch; empty defaults to the repo's own default\nbranch. Ignored when buildType is \"workflow\".","Required":false},{"Name":"build-type","Field":"buildType","Type":"string","Help":"BuildType selects the builder: \"workflow\" builds via GitHub Actions, anything\nelse builds from the branch source above.","Required":false},{"Name":"path","Field":"path","Type":"string","Help":"Path is the source directory within the branch: \"/\" (the default) or \"/docs\".\nGitHub allows no others.","Required":false}],"Example":{"branch":"main","path":"/docs","repo":"widgets"}},{"Service":"provider","Name":"github-repos-pages-builds","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.","Method":"POST","Path":"/v1/provider/github/repos/:repo/pages/builds","Args":[{"Name":"repo","Help":"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."}],"Flags":null,"Example":{"repo":"widgets"}},{"Service":"provider","Name":"github-repos-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\".","Method":"DELETE","Path":"/v1/provider/github/repos/:repo/pages","Args":[{"Name":"repo","Help":"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."}],"Flags":null,"Example":{"repo":"widgets"}},{"Service":"provider","Name":"github-repos-pages-list","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.","Method":"GET","Path":"/v1/provider/github/repos/:repo/pages","Args":[{"Name":"repo","Help":"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."}],"Flags":null,"Example":{"repo":"widgets"}},{"Service":"provider","Name":"github-repos-pages-update","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.","Method":"PUT","Path":"/v1/provider/github/repos/:repo/pages","Args":[{"Name":"repo","Help":"Repo is the repository, from the :repo path segment."}],"Flags":[{"Name":"branch","Field":"branch","Type":"string","Help":"Branch switches the legacy source branch. Empty leaves the source alone.","Required":false},{"Name":"build-type","Field":"buildType","Type":"string","Help":"BuildType switches the builder: \"legacy\" or \"workflow\". Empty leaves it.","Required":false},{"Name":"cname","Field":"cname","Type":"string","Help":"CNAME is the custom domain. Omit to leave it alone, \"\" to clear it, or a\nvalid FQDN to set it.","Required":false},{"Name":"https-enforced","Field":"httpsEnforced","Type":"boolean","Help":"HTTPSEnforced toggles GitHub's enforce-HTTPS bit. Omit to leave it alone.","Required":false},{"Name":"path","Field":"path","Type":"string","Help":"Path is the source directory to pair with Branch: \"/\" (the default) or\n\"/docs\". Read only when Branch is given.","Required":false}],"Example":{"cname":"docs.acme.com","httpsEnforced":true,"repo":"widgets"}},{"Service":"provider","Name":"github-search-create","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.","Method":"POST","Path":"/v1/provider/github/search","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the answer; 0 takes the default and anything above the ceiling\nis clamped rather than refused.","Required":false},{"Name":"q","Field":"q","Type":"string","Help":"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.","Required":false}],"Example":{"limit":5,"q":"language:go raft"}},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/github/user/callback","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"github-user-complete-create","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.","Method":"POST","Path":"/v1/provider/github/user/complete","Args":[],"Flags":[{"Name":"grant","Field":"grant","Type":"string","Help":"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.","Required":false}],"Example":{"grant":"9f2c1e7a4b8d0e3f6a5b2c1d0e9f8a7b"}},{"Service":"provider","Name":"github-user-connect-create","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.","Method":"POST","Path":"/v1/provider/github/user/connect","Args":[],"Flags":[{"Name":"return","Field":"return","Type":"string","Help":"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.","Required":false}],"Example":{"return":"https://hanzo.ai/?at=-/settings/integrations"}},{"Service":"provider","Name":"github-user-disconnect-create","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.","Method":"POST","Path":"/v1/provider/github/user/disconnect","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/github/user","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"github-webhook-create","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.","Method":"POST","Path":"/v1/provider/github/webhook","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"gitlab-projects-list","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.","Method":"GET","Path":"/v1/provider/gitlab/projects","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/google/user/callback","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"google-user-complete-create","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.","Method":"POST","Path":"/v1/provider/google/user/complete","Args":[],"Flags":[{"Name":"grant","Field":"grant","Type":"string","Help":"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.","Required":false}],"Example":{"grant":"9f2c1e7a4b8d0e3f6a5b2c1d0e9f8a7b"}},{"Service":"provider","Name":"google-user-connect-create","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.","Method":"POST","Path":"/v1/provider/google/user/connect","Args":[],"Flags":[{"Name":"return","Field":"return","Type":"string","Help":"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.","Required":false}],"Example":{"return":"https://hanzo.ai/?at=-/settings/integrations"}},{"Service":"provider","Name":"google-user-disconnect-create","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.","Method":"POST","Path":"/v1/provider/google/user/disconnect","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/google/user","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"linear-claim-create","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.","Method":"POST","Path":"/v1/provider/linear/claim","Args":[],"Flags":[{"Name":"secret","Field":"secret","Type":"string","Help":"Secret is the signing secret configured on the webhook in Linear. Claiming\nagain with a new value rotates it.","Required":false}],"Example":{"secret":"whsec_…"}},{"Service":"provider","Name":"linear-comments-create","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.","Method":"POST","Path":"/v1/provider/linear/comments","Args":[],"Flags":[{"Name":"body","Field":"body","Type":"string","Help":"Body is the comment, Markdown.","Required":false},{"Name":"issue","Field":"issue","Type":"string","Help":"Issue is the issue's identifier (ENG-123) or its id.","Required":false}],"Example":{"body":"Reproduced on main; fix in #482.","issue":"ENG-123"}},{"Service":"provider","Name":"linear-issues-backfill-create","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.","Method":"POST","Path":"/v1/provider/linear/issues/backfill","Args":[],"Flags":[{"Name":"state","Field":"state","Type":"string","Help":"State is the set of issues to walk: \"open\" (the default), \"closed\" or \"all\".","Required":false}],"Example":{"state":"all"}},{"Service":"provider","Name":"linear-webhook-create","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.","Method":"POST","Path":"/v1/provider/linear/webhook","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"list","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.","Method":"GET","Path":"/v1/provider","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/:provider/logo","Args":[{"Name":"provider","Help":""}],"Flags":null,"Example":null},{"Service":"provider","Name":"openrouter-webhook-create","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.","Method":"POST","Path":"/v1/provider/openrouter/webhook","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"run","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.","Method":"POST","Path":"/v1/provider/:provider/run","Args":[{"Name":"provider","Help":"Provider is the connector, from the path."}],"Flags":[{"Name":"action","Field":"action","Type":"string","Help":"Action is the action's name, as GET /v1/provider/{provider} lists it.","Required":false},{"Name":"input","Field":"input","Type":"json","Help":"Input is the action's props, by name.","Required":false}],"Example":{"action":"create_bitlink","input":{"long_url":"https://hanzo.ai"},"provider":"bitly"}},{"Service":"provider","Name":"slack-channels-list","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.","Method":"GET","Path":"/v1/provider/slack/channels","Args":[],"Flags":[{"Name":"types","Field":"types","Type":"string","Help":"Types selects public_channel, private_channel, im or mpim, comma-separated.\nDefaults to public_channel; each selected type requires its own read scope.","Required":false},{"Name":"cursor","Field":"cursor","Type":"string","Help":"Cursor continues the previous page's next_cursor.","Required":false}],"Example":null},{"Service":"provider","Name":"slack-commands-create","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.","Method":"POST","Path":"/v1/provider/slack/commands","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"slack-events-create","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.","Method":"POST","Path":"/v1/provider/slack/events","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/slack/file","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/slack/install","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"slack-join-create","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.","Method":"POST","Path":"/v1/provider/slack/join","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/slack/link/callback","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/slack/link","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/slack/link/slack","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"slack-messages-create","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.","Method":"POST","Path":"/v1/provider/slack/messages","Args":[],"Flags":[{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is a Slack channel ID, name (#hanzo-gtm), or Slack channel mention.","Required":false},{"Name":"text","Field":"text","Type":"string","Help":"Text is the message to post as Hanzo, up to 40000 characters.","Required":false},{"Name":"thread-ts","Field":"thread_ts","Type":"string","Help":"ThreadTS optionally replies under this parent message's exact ts.","Required":false}],"Example":null},{"Service":"provider","Name":"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.","Method":"DELETE","Path":"/v1/provider/slack/messages","Args":[],"Flags":[{"Name":"channel","Field":"channel","Type":"string","Help":"","Required":false},{"Name":"ts","Field":"ts","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"provider","Name":"slack-messages-list","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.","Method":"GET","Path":"/v1/provider/slack/messages","Args":[],"Flags":[{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is a Slack channel ID, name (#hanzo-gtm), or Slack channel mention.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit bounds the page to 1-100 messages; zero defaults to 15.","Required":false},{"Name":"cursor","Field":"cursor","Type":"string","Help":"Cursor continues the previous page's next_cursor.","Required":false},{"Name":"thread-ts","Field":"thread_ts","Type":"string","Help":"ThreadTS reads a thread via conversations.replies. Empty reads recent\nchannel messages via conversations.history, which excludes thread replies.","Required":false},{"Name":"oldest","Field":"oldest","Type":"string","Help":"Oldest filters to messages after this Slack timestamp (exclusive).","Required":false},{"Name":"latest","Field":"latest","Type":"string","Help":"Latest filters to messages before this Slack timestamp (exclusive).","Required":false}],"Example":null},{"Service":"provider","Name":"slack-messages-update","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.","Method":"PUT","Path":"/v1/provider/slack/messages","Args":[],"Flags":[{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is a Slack channel ID, name (#hanzo-gtm), or channel mention.","Required":false},{"Name":"text","Field":"text","Type":"string","Help":"Text is the replacement, up to 40000 characters.","Required":false},{"Name":"ts","Field":"ts","Type":"string","Help":"TS is the exact timestamp of the message to rewrite.","Required":false}],"Example":null},{"Service":"provider","Name":"slack-reactions-create","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.","Method":"POST","Path":"/v1/provider/slack/reactions","Args":[],"Flags":[{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is a Slack channel ID, name (#hanzo-gtm), or channel mention.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the emoji's name WITHOUT colons — \"eyes\", not \":eyes:\".","Required":false},{"Name":"ts","Field":"ts","Type":"string","Help":"TS is the exact timestamp of the message to react to.","Required":false}],"Example":null},{"Service":"provider","Name":"slack-search-create","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.","Method":"POST","Path":"/v1/provider/slack/search","Args":[],"Flags":[{"Name":"count","Field":"count","Type":"integer","Help":"Count bounds the page, 1-100. Zero means 20.","Required":false},{"Name":"page","Field":"page","Type":"integer","Help":"Page is the 1-based page of results. Zero means the first.","Required":false},{"Name":"query","Field":"query","Type":"string","Help":"Query is Slack's own search syntax — bare words, or in:#channel,\nfrom:@someone, before:2026-09-01, has:link.","Required":false}],"Example":null},{"Service":"provider","Name":"teams-events-create","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.","Method":"POST","Path":"/v1/provider/teams/events","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/teams/link/aad","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/teams/link/callback","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/teams/link","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"telegram-connect-create","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.","Method":"POST","Path":"/v1/provider/telegram/connect","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/telegram/link/auth","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/telegram/link/callback","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/telegram/link","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"telegram-webhook-create","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.","Method":"POST","Path":"/v1/provider/telegram/webhook","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/twitter/callback","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"verify","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).","Method":"POST","Path":"/v1/provider/:provider/verify","Args":[{"Name":"provider","Help":"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."}],"Flags":null,"Example":{"provider":"cloudflare"}},{"Service":"provider","Name":"whatsapp-webhook-create","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.","Method":"POST","Path":"/v1/provider/whatsapp/webhook","Args":[],"Flags":null,"Example":null},{"Service":"provider","Name":"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.","Method":"GET","Path":"/v1/provider/whatsapp/webhook","Args":[],"Flags":null,"Example":null},{"Service":"provisioning","Name":"datastore-create","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.","Method":"POST","Path":"/v1/provisioning/datastore","Args":[],"Flags":[{"Name":"instance","Field":"instance","Type":"string","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"provisioning","Name":"datastore-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.","Method":"DELETE","Path":"/v1/provisioning/datastore/:name","Args":[{"Name":"name","Help":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create."}],"Flags":null,"Example":{"name":"warehouse"}},{"Service":"provisioning","Name":"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.","Method":"GET","Path":"/v1/provisioning/datastore","Args":[],"Flags":null,"Example":null},{"Service":"provisioning","Name":"datastore-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.","Method":"GET","Path":"/v1/provisioning/datastore/:name","Args":[{"Name":"name","Help":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create."}],"Flags":null,"Example":{"name":"warehouse"}},{"Service":"provisioning","Name":"docdb-create","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.","Method":"POST","Path":"/v1/provisioning/docdb","Args":[],"Flags":[{"Name":"instance","Field":"instance","Type":"string","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"provisioning","Name":"docdb-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.","Method":"DELETE","Path":"/v1/provisioning/docdb/:name","Args":[{"Name":"name","Help":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create."}],"Flags":null,"Example":{"name":"sessions"}},{"Service":"provisioning","Name":"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.","Method":"GET","Path":"/v1/provisioning/docdb","Args":[],"Flags":null,"Example":null},{"Service":"provisioning","Name":"docdb-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.","Method":"GET","Path":"/v1/provisioning/docdb/:name","Args":[{"Name":"name","Help":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create."}],"Flags":null,"Example":{"name":"sessions"}},{"Service":"provisioning","Name":"kv-create","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.","Method":"POST","Path":"/v1/provisioning/kv","Args":[],"Flags":[{"Name":"instance","Field":"instance","Type":"string","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"provisioning","Name":"kv-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.","Method":"DELETE","Path":"/v1/provisioning/kv/:name","Args":[{"Name":"name","Help":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create."}],"Flags":null,"Example":{"name":"sessions"}},{"Service":"provisioning","Name":"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.","Method":"GET","Path":"/v1/provisioning/kv","Args":[],"Flags":null,"Example":null},{"Service":"provisioning","Name":"kv-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.","Method":"GET","Path":"/v1/provisioning/kv/:name","Args":[{"Name":"name","Help":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create."}],"Flags":null,"Example":{"name":"sessions"}},{"Service":"provisioning","Name":"s3-create","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.","Method":"POST","Path":"/v1/provisioning/s3","Args":[],"Flags":[{"Name":"instance","Field":"instance","Type":"string","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"provisioning","Name":"s3-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.","Method":"DELETE","Path":"/v1/provisioning/s3/:name","Args":[{"Name":"name","Help":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create."}],"Flags":null,"Example":{"name":"uploads"}},{"Service":"provisioning","Name":"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.","Method":"GET","Path":"/v1/provisioning/s3","Args":[],"Flags":null,"Example":null},{"Service":"provisioning","Name":"s3-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.","Method":"GET","Path":"/v1/provisioning/s3/:name","Args":[{"Name":"name","Help":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create."}],"Flags":null,"Example":{"name":"uploads"}},{"Service":"provisioning","Name":"search-create","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.","Method":"POST","Path":"/v1/provisioning/search","Args":[],"Flags":[{"Name":"instance","Field":"instance","Type":"string","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"provisioning","Name":"search-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.","Method":"DELETE","Path":"/v1/provisioning/search/:name","Args":[{"Name":"name","Help":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create."}],"Flags":null,"Example":{"name":"products"}},{"Service":"provisioning","Name":"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.","Method":"GET","Path":"/v1/provisioning/search","Args":[],"Flags":null,"Example":null},{"Service":"provisioning","Name":"search-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.","Method":"GET","Path":"/v1/provisioning/search/:name","Args":[{"Name":"name","Help":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create."}],"Flags":null,"Example":{"name":"products"}},{"Service":"provisioning","Name":"sql-create","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.","Method":"POST","Path":"/v1/provisioning/sql","Args":[],"Flags":[{"Name":"instance","Field":"instance","Type":"string","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"provisioning","Name":"sql-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.","Method":"DELETE","Path":"/v1/provisioning/sql/:name","Args":[{"Name":"name","Help":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create."}],"Flags":null,"Example":{"name":"orders"}},{"Service":"provisioning","Name":"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.","Method":"GET","Path":"/v1/provisioning/sql","Args":[],"Flags":null,"Example":null},{"Service":"provisioning","Name":"sql-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.","Method":"GET","Path":"/v1/provisioning/sql/:name","Args":[{"Name":"name","Help":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create."}],"Flags":null,"Example":{"name":"orders"}},{"Service":"provisioning","Name":"vector-create","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.","Method":"POST","Path":"/v1/provisioning/vector","Args":[],"Flags":[{"Name":"instance","Field":"instance","Type":"string","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"provisioning","Name":"vector-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.","Method":"DELETE","Path":"/v1/provisioning/vector/:name","Args":[{"Name":"name","Help":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create."}],"Flags":null,"Example":{"name":"embeddings"}},{"Service":"provisioning","Name":"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.","Method":"GET","Path":"/v1/provisioning/vector","Args":[],"Flags":null,"Example":null},{"Service":"provisioning","Name":"vector-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.","Method":"GET","Path":"/v1/provisioning/vector/:name","Args":[{"Name":"name","Help":"Name is the resource's org-unique slug, from the path. Lower-cased and\ntrimmed before lookup, exactly as it was at create."}],"Flags":null,"Example":{"name":"embeddings"}},{"Service":"pubsub","Name":"publish-create","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.","Method":"POST","Path":"/v1/pubsub/publish","Args":[],"Flags":[{"Name":"data","Field":"data","Type":"string","Help":"Data is the payload, carried verbatim as UTF-8 text (typically JSON).\nBinary payloads belong on the NATS port.","Required":false},{"Name":"headers","Field":"headers","Type":"json","Help":"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.","Required":false},{"Name":"subject","Field":"subject","Type":"string","Help":"Subject is the subject to publish to, in the org's own namespace — e.g.\norders.created. No wildcards.","Required":false}],"Example":{"data":"{\"id\":\"o_1\"}","headers":{"Nats-Msg-Id":"o_1"},"subject":"orders.created"}},{"Service":"pubsub","Name":"request-create","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.","Method":"POST","Path":"/v1/pubsub/request","Args":[],"Flags":[{"Name":"data","Field":"data","Type":"string","Help":"Data is the request payload, carried verbatim as UTF-8 text.","Required":false},{"Name":"headers","Field":"headers","Type":"json","Help":"Headers are optional request headers, one value per name.","Required":false},{"Name":"subject","Field":"subject","Type":"string","Help":"Subject is the subject a responder listens on, in the org's namespace.","Required":false},{"Name":"timeout-ms","Field":"timeoutMs","Type":"integer","Help":"TimeoutMs bounds the wait for a reply. 0 or less means the default of\n5000; anything above 30000 is clamped to 30000.","Required":false}],"Example":{"data":"{\"sku\":\"gpu_1\"}","subject":"billing.quote","timeoutMs":2000}},{"Service":"reference","Name":"risk-clear-reference","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.","Method":"DELETE","Path":"/v1/reference/:set","Args":[{"Name":"set","Help":""}],"Flags":[{"Name":"key","Field":"key","Type":"string","Help":"","Required":false}],"Example":{"key":"partner.example","set":"domain"}},{"Service":"reference","Name":"risk-reference","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.","Method":"GET","Path":"/v1/reference/:set","Args":[{"Name":"set","Help":""}],"Flags":[{"Name":"after","Field":"after","Type":"string","Help":"After pages the override listing: the last key of the previous page.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the override listing: default 200, maximum 1000.","Required":false}],"Example":{"limit":50,"set":"domain"}},{"Service":"reference","Name":"risk-reference-sets","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.","Method":"GET","Path":"/v1/reference","Args":[],"Flags":null,"Example":null},{"Service":"reference","Name":"risk-resolve-reference","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.","Method":"POST","Path":"/v1/reference/resolve","Args":[],"Flags":[{"Name":"keys","Field":"keys","Type":"json","Help":"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.","Required":false},{"Name":"sets","Field":"sets","Type":"json","Help":"Sets narrows which sets to consult. Empty consults every set whose matcher\ncan read the keys given.","Required":false}],"Example":{"keys":["user@tempbox.example","3.5.140.1"],"sets":["domain","net"]}},{"Service":"reference","Name":"risk-set-reference","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.","Method":"PUT","Path":"/v1/reference/:set","Args":[{"Name":"set","Help":""}],"Flags":[{"Name":"entries","Field":"entries","Type":"json","Help":"Entries are the overrides to write, up to 1000 per call.","Required":false}],"Example":{"entries":[{"key":"partner.example","note":"our reseller","verdict":"allow"}],"set":"domain"}},{"Service":"referral","Name":"claim-create","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.","Method":"POST","Path":"/v1/referral/claim","Args":[],"Flags":[{"Name":"code","Field":"code","Type":"string","Help":"Code is the referrer's referral code, as it appeared in their ?ref= link.\nCase and surrounding whitespace do not matter.","Required":false},{"Name":"invite","Field":"invite","Type":"string","Help":"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.","Required":false}],"Example":{"code":"H4NZ0ABC"}},{"Service":"referral","Name":"list","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.","Method":"GET","Path":"/v1/referral","Args":[],"Flags":null,"Example":null},{"Service":"referral","Name":"update","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.","Method":"PUT","Path":"/v1/referral","Args":[],"Flags":[{"Name":"code","Field":"code","Type":"string","Help":"Code is the custom referral code to assign to the caller's org (2-32 uppercase alphanumeric, hyphen, or underscore characters).","Required":false}],"Example":null},{"Service":"registry","Name":"images-list","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.","Method":"GET","Path":"/v1/registry/images","Args":[],"Flags":null,"Example":null},{"Service":"registry","Name":"packages-list","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.","Method":"GET","Path":"/v1/registry/packages","Args":[],"Flags":[{"Name":"query","Field":"query","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"registry","Name":"projects-list","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.","Method":"GET","Path":"/v1/registry/projects","Args":[],"Flags":null,"Example":null},{"Service":"registry","Name":"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.","Method":"GET","Path":"/v1/registry/status","Args":[],"Flags":null,"Example":null},{"Service":"registry","Name":"tags-list","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.","Method":"GET","Path":"/v1/registry/tags","Args":[],"Flags":[{"Name":"image","Field":"image","Type":"string","Help":"Image is the repository name inside the org's namespace, as returned by\nthe images op. It rides the query string.","Required":false}],"Example":null},{"Service":"registry","Name":"token-create","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.","Method":"POST","Path":"/v1/registry/token","Args":[],"Flags":[{"Name":"image","Field":"image","Type":"string","Help":"Image is the repository name inside the org's namespace (e.g. \"cloud\").","Required":false}],"Example":{"image":"cloud"}},{"Service":"rerank","Name":"create","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.","Method":"POST","Path":"/v1/rerank","Args":[],"Flags":null,"Example":null},{"Service":"responses","Name":"create","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.","Method":"POST","Path":"/v1/responses","Args":[],"Flags":null,"Example":null},{"Service":"risk","Name":"adopt-model","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.","Method":"PUT","Path":"/v1/risk/state/model","Args":[],"Flags":[{"Name":"address","Field":"address","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"risk","Name":"features","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.","Method":"GET","Path":"/v1/risk/features","Args":[],"Flags":[{"Name":"days","Field":"days","Type":"integer","Help":"Days is how far back to measure the organisation's own coverage, 1 to 400.\nZero takes thirty.","Required":false}],"Example":{"days":30}},{"Service":"risk","Name":"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.","Method":"GET","Path":"/v1/risk/health","Args":[],"Flags":null,"Example":null},{"Service":"risk","Name":"learn","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.","Method":"POST","Path":"/v1/risk/learn","Args":[],"Flags":[{"Name":"events","Field":"events","Type":"json","Help":"Events are the things that happened, oldest first. An empty batch is\nrefused: learning nothing is not an operation.","Required":false}],"Example":{"events":[{"id":"tx_9","kind":"account","nano":420000000,"subject":"u_412"}]}},{"Service":"risk","Name":"policy","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.","Method":"GET","Path":"/v1/risk/policy","Args":[],"Flags":null,"Example":null},{"Service":"risk","Name":"publish-model","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.","Method":"POST","Path":"/v1/risk/state/model","Args":[],"Flags":null,"Example":null},{"Service":"risk","Name":"score","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.","Method":"POST","Path":"/v1/risk/score","Args":[],"Flags":[{"Name":"event","Field":"event","Type":"json","Help":"Event is the thing to judge. It is judged against the caller's OWN model\nand nothing is learned from it.","Required":false}],"Example":{"event":{"id":"tx_9","kind":"account","nano":420000000,"subject":"u_412"}}},{"Service":"risk","Name":"search","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.","Method":"POST","Path":"/v1/risk/search","Args":[],"Flags":[{"Name":"days","Field":"days","Type":"integer","Help":"Days is how much of the organisation's own history to replay, 1 to 400.\nZero takes thirty.","Required":false}],"Example":{"days":30}},{"Service":"risk","Name":"search-result","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.","Method":"GET","Path":"/v1/risk/search/:id","Args":[{"Name":"id","Help":"ID is the run, taken from the path. A run another organisation started is\nsimply not there — the same answer an unknown id gives."}],"Flags":null,"Example":{"id":"srch_2f6a1c"}},{"Service":"risk","Name":"set-policy","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.","Method":"PUT","Path":"/v1/risk/policy","Args":[],"Flags":[{"Name":"live","Field":"live","Type":"boolean","Help":"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.","Required":false},{"Name":"review","Field":"review","Type":"number","Help":"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.","Required":false},{"Name":"sample","Field":"sample","Type":"number","Help":"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.","Required":false}],"Example":{"live":false,"review":0.01,"sample":0.001}},{"Service":"risk","Name":"state","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.","Method":"GET","Path":"/v1/risk/state","Args":[],"Flags":null,"Example":null},{"Service":"root","Name":"get-capabilities","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.","Method":"GET","Path":"/v1","Args":[],"Flags":null,"Example":null},{"Service":"root","Name":"get-capability","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.","Method":"GET","Path":"/v1/:name","Args":[{"Name":"name","Help":""}],"Flags":null,"Example":null},{"Service":"runner","Name":"declare-create","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.","Method":"POST","Path":"/v1/runner/declare","Args":[],"Flags":[{"Name":"capabilities","Field":"capabilities","Type":"json","Help":"Capabilities are the optional protocol behaviours this runner\nunderstands, e.g. \"cancelling\".","Required":false},{"Name":"labels","Field":"labels","Type":"json","Help":"Labels replace what the forge holds, so a relabelled runner follows its\nconfiguration without re-registering.","Required":false},{"Name":"version","Field":"version","Type":"string","Help":"Version is the runner build now running.","Required":false}],"Example":null},{"Service":"runner","Name":"log-create","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.","Method":"POST","Path":"/v1/runner/log","Args":[],"Flags":[{"Name":"index","Field":"index","Type":"integer","Help":"Index is the position of the first line in that log, so a resent batch\noverlaps rather than duplicates.","Required":false},{"Name":"last","Field":"last","Type":"boolean","Help":"Last seals the log and moves it to storage. Appending past a seal is an\nerror; resending one is acknowledged.","Required":false},{"Name":"lines","Field":"lines","Type":"json","Help":"Lines is the batch itself.","Required":false},{"Name":"task","Field":"task","Type":"integer","Help":"Task is whose log this is.","Required":false}],"Example":null},{"Service":"runner","Name":"register-create","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.","Method":"POST","Path":"/v1/runner/register","Args":[],"Flags":[{"Name":"capabilities","Field":"capabilities","Type":"json","Help":"Capabilities are the optional protocol behaviours this runner\nunderstands, e.g. \"cancelling\".","Required":false},{"Name":"ephemeral","Field":"ephemeral","Type":"boolean","Help":"Ephemeral declares that this runner takes ONE job and exits.","Required":false},{"Name":"labels","Field":"labels","Type":"json","Help":"Labels are what a workflow's `runs-on:` will select this runner by.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is what to call this runner. Required.","Required":false},{"Name":"token","Field":"token","Type":"string","Help":"Token is the REGISTRATION secret, a different secret from the runner\ntoken the reply carries. Required.","Required":false},{"Name":"version","Field":"version","Type":"string","Help":"Version is the runner build asking to register.","Required":false}],"Example":null},{"Service":"runner","Name":"state-create","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.","Method":"POST","Path":"/v1/runner/state","Args":[],"Flags":[{"Name":"outputs","Field":"outputs","Type":"json","Help":"Outputs are values the job has published since the last report.","Required":false},{"Name":"state","Field":"state","Type":"json","Help":"State is the task's progress and that of each of its steps.","Required":false}],"Example":null},{"Service":"runner","Name":"task-create","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.","Method":"POST","Path":"/v1/runner/task","Args":[],"Flags":[{"Name":"queue","Field":"queue","Type":"integer","Help":"Queue is the queue version the runner last saw. When it equals the\nforge's, nothing has been queued since.","Required":false}],"Example":null},{"Service":"s3","Name":"buckets-complete","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.","Method":"POST","Path":"/v1/s3/buckets/:bucket/uploads/:upload/complete","Args":[{"Name":"bucket","Help":"Bucket is the bucket, from the path."},{"Name":"upload","Help":"Upload is the upload's id, from the path."}],"Flags":[{"Name":"key","Field":"key","Type":"string","Help":"Key is the object key the upload was started on. In the query for a read\nor an abandon, in the body to complete.","Required":false}],"Example":null},{"Service":"s3","Name":"buckets-create","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.","Method":"POST","Path":"/v1/s3/buckets","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"s3","Name":"buckets-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.","Method":"DELETE","Path":"/v1/s3/buckets/:bucket","Args":[{"Name":"bucket","Help":"Bucket is the bucket's friendly name, from the path."}],"Flags":null,"Example":null},{"Service":"s3","Name":"buckets-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.","Method":"DELETE","Path":"/v1/s3/buckets/:bucket/uploads/:upload","Args":[{"Name":"bucket","Help":"Bucket is the bucket, from the path."},{"Name":"upload","Help":"Upload is the upload's id, from the path."}],"Flags":[{"Name":"key","Field":"key","Type":"string","Help":"Key is the object key the upload was started on. In the query for a read\nor an abandon, in the body to complete.","Required":false}],"Example":null},{"Service":"s3","Name":"buckets-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.","Method":"GET","Path":"/v1/s3/buckets/:bucket/uploads/:upload","Args":[{"Name":"bucket","Help":"Bucket is the bucket, from the path."},{"Name":"upload","Help":"Upload is the upload's id, from the path."}],"Flags":[{"Name":"key","Field":"key","Type":"string","Help":"Key is the object key the upload was started on. In the query for a read\nor an abandon, in the body to complete.","Required":false}],"Example":null},{"Service":"s3","Name":"buckets-list","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.","Method":"GET","Path":"/v1/s3/buckets","Args":[],"Flags":null,"Example":null},{"Service":"s3","Name":"buckets-objects","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.","Method":"POST","Path":"/v1/s3/buckets/:bucket/objects","Args":[{"Name":"bucket","Help":"Bucket is the bucket to upload into, from the path."}],"Flags":[{"Name":"key","Field":"key","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"s3","Name":"buckets-objects-list","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.","Method":"GET","Path":"/v1/s3/buckets/:bucket/objects","Args":[{"Name":"bucket","Help":"Bucket is the bucket to list, from the path."}],"Flags":[{"Name":"prefix","Field":"prefix","Type":"string","Help":"","Required":false},{"Name":"recursive","Field":"recursive","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"s3","Name":"buckets-parts","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.","Method":"POST","Path":"/v1/s3/buckets/:bucket/uploads/:upload/parts","Args":[{"Name":"bucket","Help":"Bucket is the bucket, from the path."},{"Name":"upload","Help":"Upload is the upload's id, from the path."}],"Flags":[{"Name":"key","Field":"key","Type":"string","Help":"Key is the object key the upload was started on.","Required":false},{"Name":"parts","Field":"parts","Type":"json","Help":"Parts are the part numbers to mint URLs for, from 1. At most 64 a call.","Required":false}],"Example":null},{"Service":"s3","Name":"buckets-uploads","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.","Method":"POST","Path":"/v1/s3/buckets/:bucket/uploads","Args":[{"Name":"bucket","Help":"Bucket is the bucket to upload into, from the path."}],"Flags":[{"Name":"key","Field":"key","Type":"string","Help":"Key is the object key the upload will become, relative to the bucket\nroot. It is path-cleaned, so a \"../\" cannot escape the bucket.","Required":false},{"Name":"type","Field":"type","Type":"string","Help":"Type is the object's media type, kept with it once it is assembled.","Required":false}],"Example":{"key":"chat/backup.tar","type":"application/x-tar"}},{"Service":"s3","Name":"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.","Method":"GET","Path":"/v1/s3/health","Args":[],"Flags":null,"Example":null},{"Service":"sandbox","Name":"create","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.","Method":"POST","Path":"/v1/sandbox","Args":[],"Flags":[{"Name":"class","Field":"class","Type":"string","Help":"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.","Required":false},{"Name":"cluster","Field":"cluster","Type":"string","Help":"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.","Required":false},{"Name":"image","Field":"image","Type":"string","Help":"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.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"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.","Required":false},{"Name":"runtime","Field":"runtime","Type":"string","Help":"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.","Required":false},{"Name":"ttl-sec","Field":"ttlSec","Type":"integer","Help":"TTLSec is how long the lease runs before the reaper may take it, in\nseconds. Zero takes the class's own default.","Required":false}],"Example":null},{"Service":"sandbox","Name":"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.","Method":"DELETE","Path":"/v1/sandbox/:id","Args":[{"Name":"id","Help":"ID is the sandbox to end, from the path."}],"Flags":[{"Name":"purge","Field":"purge","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"sandbox","Name":"end-sandbox","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.","Method":"POST","Path":"/v1/sandbox/end","Args":[],"Flags":[{"Name":"id","Field":"id","Type":"string","Help":"ID is the sandbox whose lease ends, from an earlier lease.","Required":false},{"Name":"purge","Field":"purge","Type":"boolean","Help":"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.","Required":false}],"Example":null},{"Service":"sandbox","Name":"exec","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.","Method":"POST","Path":"/v1/sandbox/:id/exec","Args":[{"Name":"id","Help":"ID is the sandbox to run in, from the path."}],"Flags":[{"Name":"argv","Field":"argv","Type":"json","Help":"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.","Required":false},{"Name":"command","Field":"command","Type":"string","Help":"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.","Required":false},{"Name":"dir","Field":"dir","Type":"string","Help":"Dir is the working directory to run in. Empty runs in the class's own\nworkdir — /mnt/data for exec, /work for dev.","Required":false},{"Name":"stdin","Field":"stdin","Type":"string","Help":"Stdin is fed to the command on its standard input.","Required":false},{"Name":"timeout-sec","Field":"timeoutSec","Type":"integer","Help":"TimeoutSec bounds the run in seconds. Zero takes the default.","Required":false}],"Example":null},{"Service":"sandbox","Name":"fs","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.","Method":"POST","Path":"/v1/sandbox/:id/fs","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"sandbox","Name":"fs-list","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.","Method":"GET","Path":"/v1/sandbox/:id/fs","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"sandbox","Name":"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.","Method":"GET","Path":"/v1/sandbox/:id","Args":[{"Name":"id","Help":"ID is the sandbox to address, from the path."}],"Flags":null,"Example":null},{"Service":"sandbox","Name":"lease-sandbox","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.","Method":"POST","Path":"/v1/sandbox/lease","Args":[],"Flags":[{"Name":"class","Field":"class","Type":"string","Help":"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.","Required":false},{"Name":"cluster","Field":"cluster","Type":"string","Help":"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.","Required":false},{"Name":"disk","Field":"disk","Type":"boolean","Help":"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.","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"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.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"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.","Required":false},{"Name":"runtime","Field":"runtime","Type":"string","Help":"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.","Required":false},{"Name":"ttl-sec","Field":"ttlSec","Type":"integer","Help":"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.","Required":false}],"Example":null},{"Service":"sandbox","Name":"list","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.","Method":"GET","Path":"/v1/sandbox","Args":[],"Flags":[{"Name":"project","Field":"project","Type":"string","Help":"","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"sandbox","Name":"pause","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.","Method":"POST","Path":"/v1/sandbox/:id/pause","Args":[{"Name":"id","Help":"ID is the sandbox to address, from the path."}],"Flags":null,"Example":null},{"Service":"sandbox","Name":"ports-list","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.","Method":"GET","Path":"/v1/sandbox/:id/ports","Args":[{"Name":"id","Help":"ID is the sandbox, from the path."}],"Flags":null,"Example":null},{"Service":"sandbox","Name":"preview","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.","Method":"POST","Path":"/v1/sandbox/:id/preview","Args":[{"Name":"id","Help":"ID is the sandbox, from the path."}],"Flags":[{"Name":"port","Field":"port","Type":"integer","Help":"Port is the TCP port inside the sandbox to open, 1 to 65535. Whatever\nlistens on it on localhost is what the address serves.","Required":false}],"Example":null},{"Service":"sandbox","Name":"read-sandbox-file","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.","Method":"POST","Path":"/v1/sandbox/read","Args":[],"Flags":[{"Name":"id","Field":"id","Type":"string","Help":"ID is the sandbox to read from, from an earlier lease.","Required":false},{"Name":"path","Field":"path","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"sandbox","Name":"resume","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.","Method":"POST","Path":"/v1/sandbox/:id/resume","Args":[{"Name":"id","Help":"ID is the sandbox to address, from the path."}],"Flags":null,"Example":null},{"Service":"sandbox","Name":"run-in-sandbox","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.","Method":"POST","Path":"/v1/sandbox/run","Args":[],"Flags":[{"Name":"argv","Field":"argv","Type":"json","Help":"Argv is the program and its arguments, already split — the form no shell can\nmisread. Give this or Command, not both.","Required":false},{"Name":"blind","Field":"blind","Type":"json","Help":"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.","Required":false},{"Name":"command","Field":"command","Type":"string","Help":"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.","Required":false},{"Name":"dir","Field":"dir","Type":"string","Help":"Dir runs the command somewhere other than the sandbox's working directory,\nwhich Leased.Workdir names.","Required":false},{"Name":"events","Field":"events","Type":"boolean","Help":"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.","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"ID is the sandbox to run in, from an earlier lease.","Required":false},{"Name":"session","Field":"session","Type":"string","Help":"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.","Required":false},{"Name":"stdin","Field":"stdin","Type":"string","Help":"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.","Required":false},{"Name":"timeout-sec","Field":"timeoutSec","Type":"integer","Help":"TimeoutSec bounds this ONE command, so a wedged program holds the caller for\nits own timeout rather than for the whole lease.","Required":false}],"Example":null},{"Service":"sandbox","Name":"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.","Method":"GET","Path":"/v1/sandbox/:id/screen","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"sandbox","Name":"screen-ticket","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.","Method":"POST","Path":"/v1/sandbox/:id/screen/ticket","Args":[{"Name":"id","Help":"ID is the sandbox to address, from the path."}],"Flags":null,"Example":null},{"Service":"sandbox","Name":"screen-ws-list","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.","Method":"GET","Path":"/v1/sandbox/:id/screen/ws","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"sandbox","Name":"stop-run","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.","Method":"POST","Path":"/v1/sandbox/stop","Args":[],"Flags":[{"Name":"id","Field":"id","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"sandbox","Name":"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.","Method":"GET","Path":"/v1/sandbox/:id/terminal","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"sandbox","Name":"terminal-ticket","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.","Method":"POST","Path":"/v1/sandbox/:id/terminal/ticket","Args":[{"Name":"id","Help":"ID is the sandbox to address, from the path."}],"Flags":null,"Example":null},{"Service":"sandbox","Name":"terminal-ws-list","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.","Method":"GET","Path":"/v1/sandbox/:id/terminal/ws","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"sandbox","Name":"write-sandbox-file","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.","Method":"POST","Path":"/v1/sandbox/write","Args":[],"Flags":[{"Name":"data","Field":"data","Type":"string","Help":"Data is the file's bytes, and replaces whatever was there.","Required":false},{"Name":"id","Field":"id","Type":"string","Help":"ID is the sandbox to write into, from an earlier lease.","Required":false},{"Name":"path","Field":"path","Type":"string","Help":"Path is confined the same way PathIn.Path is. Missing parent directories are\ncreated.","Required":false}],"Example":null},{"Service":"sbom","Name":"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).","Method":"GET","Path":"/v1/sbom/health","Args":[],"Flags":null,"Example":null},{"Service":"search","Name":"search","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.","Method":"POST","Path":"/v1/search","Args":[],"Flags":[{"Name":"doctypes","Field":"doctypes","Type":"json","Help":"DocTypes restricts the semantic leg to a subset of indexed knowledge types.","Required":false},{"Name":"index","Field":"index","Type":"string","Help":"Index names the lexical index to query. Defaults to \"kb\".","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit bounds the FUSED result set (default 10, max 50).","Required":false},{"Name":"mode","Field":"mode","Type":"string","Help":"Mode selects the legs: auto (default) | text | semantic | hybrid.","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset pages the fused result set.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project narrows to one project scope within the org.","Required":false},{"Name":"query","Field":"query","Type":"string","Help":"Query is the natural-language or keyword query. Required.","Required":false}],"Example":null},{"Service":"security","Name":"findings-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.","Method":"GET","Path":"/v1/security/findings/:id","Args":[{"Name":"id","Help":"ID is the finding the URL names."}],"Flags":null,"Example":null},{"Service":"security","Name":"findings-list","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.","Method":"GET","Path":"/v1/security/findings","Args":[],"Flags":[{"Name":"scan-id","Field":"scanId","Type":"string","Help":"ScanID narrows to a single scan.","Required":false},{"Name":"min-severity","Field":"minSeverity","Type":"string","Help":"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\".","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the page.","Required":false}],"Example":null},{"Service":"security","Name":"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.","Method":"GET","Path":"/v1/security/health","Args":[],"Flags":null,"Example":null},{"Service":"security","Name":"rules-list","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.","Method":"GET","Path":"/v1/security/rules","Args":[],"Flags":null,"Example":null},{"Service":"security","Name":"scans-create","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.","Method":"POST","Path":"/v1/security/scans","Args":[],"Flags":[{"Name":"files","Field":"files","Type":"json","Help":"Files is the batch to scan, at most 500 files and 8 MiB of content in total.","Required":true},{"Name":"project","Field":"project","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"security","Name":"scans-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.","Method":"GET","Path":"/v1/security/scans/:id","Args":[{"Name":"id","Help":"ID is the scan the URL names."}],"Flags":null,"Example":null},{"Service":"security","Name":"scans-list","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.","Method":"GET","Path":"/v1/security/scans","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the page.","Required":false}],"Example":null},{"Service":"seo","Name":"audit","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.","Method":"POST","Path":"/v1/seo/audit","Args":[],"Flags":[{"Name":"url","Field":"url","Type":"string","Help":"URL is the page, absolute and http or https.","Required":false}],"Example":null},{"Service":"seo","Name":"backlink","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.","Method":"POST","Path":"/v1/seo/backlinks","Args":[],"Flags":[{"Name":"target","Field":"target","Type":"string","Help":"Target is a domain, a subdomain or a single page URL. A domain summarises the\nwhole site; a URL summarises that page.","Required":false}],"Example":null},{"Service":"seo","Name":"competitor","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.","Method":"POST","Path":"/v1/seo/competitors","Args":[],"Flags":[{"Name":"keywords","Field":"keywords","Type":"json","Help":"Keywords are the phrases. At least one; blanks are dropped.","Required":false},{"Name":"language","Field":"language","Type":"string","Help":"Language is the ISO code. Defaults to \"en\".","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit is how many domains to return, 1 to 1000. Defaults to 100.","Required":false},{"Name":"location","Field":"location","Type":"integer","Help":"Location is the market, as the upstream's numeric code. Defaults to 2840.","Required":false}],"Example":null},{"Service":"seo","Name":"idea","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.","Method":"POST","Path":"/v1/seo/ideas","Args":[],"Flags":[{"Name":"keywords","Field":"keywords","Type":"json","Help":"Keywords are the seeds. At least one; blanks are dropped.","Required":false},{"Name":"language","Field":"language","Type":"string","Help":"Language is the ISO code. Defaults to \"en\".","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"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.","Required":false},{"Name":"location","Field":"location","Type":"integer","Help":"Location is the market, as the upstream's numeric code. Defaults to 2840.","Required":false}],"Example":null},{"Service":"seo","Name":"keyword","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.","Method":"POST","Path":"/v1/seo/keywords","Args":[],"Flags":[{"Name":"keywords","Field":"keywords","Type":"json","Help":"Keywords are the phrases. At least one; blanks are dropped.","Required":false},{"Name":"language","Field":"language","Type":"string","Help":"Language is the ISO code. Defaults to \"en\".","Required":false},{"Name":"location","Field":"location","Type":"integer","Help":"Location is the market, as the upstream's numeric code. Defaults to 2840,\nthe United States.","Required":false}],"Example":null},{"Service":"seo","Name":"rank","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.","Method":"POST","Path":"/v1/seo/rankings","Args":[],"Flags":[{"Name":"domain","Field":"domain","Type":"string","Help":"Domain is the site, with or without a subdomain — \"hanzo.ai\", \"docs.hanzo.ai\".","Required":false},{"Name":"language","Field":"language","Type":"string","Help":"Language is the ISO code. Defaults to \"en\".","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit is how many placements to return, 1 to 1000. Defaults to 100.","Required":false},{"Name":"location","Field":"location","Type":"integer","Help":"Location is the market, as the upstream's numeric code. Defaults to 2840.","Required":false}],"Example":null},{"Service":"seo","Name":"rate","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.","Method":"GET","Path":"/v1/seo/rates","Args":[],"Flags":null,"Example":null},{"Service":"settings","Name":"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.","Method":"GET","Path":"/v1/settings/:product","Args":[{"Name":"product","Help":"Product is the catalog slug, from the path. Must match ^[a-z0-9][a-z0-9._-]{0,62}$."}],"Flags":null,"Example":null},{"Service":"settings","Name":"update","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.","Method":"PUT","Path":"/v1/settings/:product","Args":[{"Name":"product","Help":"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."}],"Flags":[{"Name":"config","Field":"config","Type":"json","Help":"Config is the product's non-secret configuration, stored verbatim. Bounded at\n64 KiB once serialized. Omit it to store an empty object.","Required":false},{"Name":"secrets","Field":"secrets","Type":"json","Help":"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.","Required":false}],"Example":null},{"Service":"share","Name":"enable-create","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.","Method":"POST","Path":"/v1/share/enable","Args":[],"Flags":null,"Example":null},{"Service":"share","Name":"list","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.","Method":"GET","Path":"/v1/share","Args":[],"Flags":null,"Example":null},{"Service":"share","Name":"rotate-create","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.","Method":"POST","Path":"/v1/share/rotate","Args":[],"Flags":null,"Example":null},{"Service":"social","Name":"accounts-create","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.","Method":"POST","Path":"/v1/social/accounts","Args":[],"Flags":[{"Name":"handle","Field":"handle","Type":"string","Help":"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\"","Required":false},{"Name":"provider","Field":"provider","Type":"string","Help":"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\"","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status is the connection lifecycle: connected, disconnected or error.\nOmitted means connected. Only a connected account is a publish target.","Required":false}],"Example":null},{"Service":"social","Name":"accounts-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.","Method":"DELETE","Path":"/v1/social/accounts/:id","Args":[{"Name":"id","Help":"ID is the account or post to act on, taken from the path."}],"Flags":null,"Example":null},{"Service":"social","Name":"accounts-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.","Method":"GET","Path":"/v1/social/accounts/:id","Args":[{"Name":"id","Help":"ID is the account or post to act on, taken from the path."}],"Flags":null,"Example":null},{"Service":"social","Name":"accounts-list","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.","Method":"GET","Path":"/v1/social/accounts","Args":[],"Flags":[{"Name":"provider","Field":"provider","Type":"string","Help":"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.","Required":false},{"Name":"limit","Field":"limit","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"social","Name":"accounts-update","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.","Method":"PUT","Path":"/v1/social/accounts/:id","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"handle","Field":"handle","Type":"string","Help":"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\"","Required":false},{"Name":"provider","Field":"provider","Type":"string","Help":"Provider is the network this account is on: x, facebook, instagram, linkedin,\ntiktok, youtube or threads. Omitted means x.\n\nExample: \"x\"","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status is the connection lifecycle: connected, disconnected or error.\nOmitting it RESETS the account to connected.","Required":false}],"Example":null},{"Service":"social","Name":"credentials-list","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.","Method":"GET","Path":"/v1/social/credentials","Args":[],"Flags":null,"Example":null},{"Service":"social","Name":"credentials-update","OperationID":"put_social_credentials","Summary":"Seals the apps in the body.","Description":"Seals the apps in the body. A network left out is unchanged.","Method":"PUT","Path":"/v1/social/credentials","Args":[],"Flags":[{"Name":"apps","Field":"apps","Type":"json","Help":"Apps are the networks the caller is changing. The rest stay as they are.","Required":false}],"Example":null},{"Service":"social","Name":"posts-create","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.","Method":"POST","Path":"/v1/social/posts","Args":[],"Flags":[{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is the network to publish to: x, facebook, instagram, linkedin,\ntiktok, youtube or threads. Omitted means x.\n\nExample: \"x\"","Required":false},{"Name":"content","Field":"content","Type":"string","Help":"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.\"","Required":false},{"Name":"media","Field":"media","Type":"json","Help":"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.","Required":false},{"Name":"schedule-at","Field":"scheduleAt","Type":"integer","Help":"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.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"social","Name":"posts-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.","Method":"DELETE","Path":"/v1/social/posts/:id","Args":[{"Name":"id","Help":"ID is the account or post to act on, taken from the path."}],"Flags":null,"Example":null},{"Service":"social","Name":"posts-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.","Method":"GET","Path":"/v1/social/posts/:id","Args":[{"Name":"id","Help":"ID is the account or post to act on, taken from the path."}],"Flags":null,"Example":null},{"Service":"social","Name":"posts-list","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.","Method":"GET","Path":"/v1/social/posts","Args":[],"Flags":[{"Name":"status","Field":"status","Type":"string","Help":"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.","Required":false},{"Name":"limit","Field":"limit","Type":"string","Help":"Limit bounds the page, defaulting to 200 and capped at 1000. A string for\nthe same reason accountFilter.Limit is.","Required":false}],"Example":null},{"Service":"social","Name":"posts-publish","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.","Method":"POST","Path":"/v1/social/posts/:id/publish","Args":[{"Name":"id","Help":"ID is the account or post to act on, taken from the path."}],"Flags":null,"Example":null},{"Service":"social","Name":"posts-update","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.","Method":"PUT","Path":"/v1/social/posts/:id","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"channel","Field":"channel","Type":"string","Help":"Channel is the network to publish to: x, facebook, instagram, linkedin,\ntiktok, youtube or threads. Omitted means x.\n\nExample: \"x\"","Required":false},{"Name":"content","Field":"content","Type":"string","Help":"Content is the post's text. Required on every update, and bounded at 8192\ncharacters.\n\nExample: \"Shipping today.\"","Required":false},{"Name":"media","Field":"media","Type":"json","Help":"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.","Required":false},{"Name":"schedule-at","Field":"scheduleAt","Type":"integer","Help":"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.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status is the post's lifecycle state: draft, scheduled, published or failed.\nOmitting it RESETS the post to draft.","Required":false}],"Example":null},{"Service":"social","Name":"providers-list","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.","Method":"GET","Path":"/v1/social/providers","Args":[],"Flags":null,"Example":null},{"Service":"social","Name":"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.","Method":"GET","Path":"/v1/social/summary","Args":[],"Flags":null,"Example":null},{"Service":"space","Name":"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.","Method":"DELETE","Path":"/v1/space/:space/drives/:drive","Args":[{"Name":"space","Help":"Space is the space's name, from the path."},{"Name":"drive","Help":"Drive is the drive's name, from the path."}],"Flags":null,"Example":null},{"Service":"space","Name":"drives","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.","Method":"POST","Path":"/v1/space/:space/drives","Args":[{"Name":"space","Help":"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."}],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"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 \"/\".","Required":false}],"Example":null},{"Service":"space","Name":"drives-list","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.","Method":"GET","Path":"/v1/space/:space/drives","Args":[{"Name":"space","Help":"Space is the space's name, from the path."}],"Flags":null,"Example":null},{"Service":"space","Name":"files-list","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.","Method":"GET","Path":"/v1/space/:space/drives/:drive/files","Args":[{"Name":"space","Help":"Space is the space to list in, from the path."},{"Name":"drive","Help":"Drive is the drive to list, from the path."}],"Flags":[{"Name":"folder","Field":"folder","Type":"string","Help":"","Required":false},{"Name":"recursive","Field":"recursive","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"space","Name":"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.","Method":"GET","Path":"/v1/space/health","Args":[],"Flags":null,"Example":null},{"Service":"space","Name":"spaces-create","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.","Method":"POST","Path":"/v1/space/spaces","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"space","Name":"spaces-list","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.","Method":"GET","Path":"/v1/space/spaces","Args":[],"Flags":null,"Example":null},{"Service":"standing","Name":"upkeep-create","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.","Method":"POST","Path":"/v1/standing/upkeep","Args":[],"Flags":[{"Name":"agent-of-record","Field":"agentOfRecord","Type":"boolean","Help":"AgentOfRecord includes our agent fee, which most entities owe someone.","Required":false},{"Name":"jurisdiction","Field":"jurisdiction","Type":"string","Help":"Jurisdiction is the state the entity stands in.","Required":false},{"Name":"structure","Field":"structure","Type":"string","Help":"Structure is the entity kind: c-corp, llc or dao-llc.","Required":false}],"Example":null},{"Service":"studio","Name":"brands-create","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.*.","Method":"POST","Path":"/v1/studio/brands","Args":[],"Flags":[{"Name":"logos","Field":"logos","Type":"json","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"shared","Field":"shared","Type":"boolean","Help":"","Required":false},{"Name":"tokens","Field":"tokens","Type":"json","Help":"","Required":false}],"Example":{"name":"Acme","tokens":{"color":{"primary":{"$type":"color","$value":"#ff5a1f"}}}}},{"Service":"studio","Name":"brands-delete","OperationID":"delete_studio_brands_by_id","Summary":"Deletes one of your brands.","Description":"Deletes one of your brands.","Method":"DELETE","Path":"/v1/studio/brands/:id","Args":[{"Name":"id","Help":"ID is the resource's id, from the path."}],"Flags":null,"Example":null},{"Service":"studio","Name":"brands-get","OperationID":"get_studio_brands_by_id","Summary":"Reads one brand you may read.","Description":"Reads one brand you may read.","Method":"GET","Path":"/v1/studio/brands/:id","Args":[{"Name":"id","Help":"ID is the resource's id, from the path."}],"Flags":null,"Example":null},{"Service":"studio","Name":"brands-list","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.","Method":"GET","Path":"/v1/studio/brands","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit is how many rows one page holds, 1 to 100 (default 50).","Required":false},{"Name":"cursor","Field":"cursor","Type":"string","Help":"Cursor is the previous page's next.","Required":false}],"Example":null},{"Service":"studio","Name":"brands-update","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.","Method":"PATCH","Path":"/v1/studio/brands/:id","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"logos","Field":"logos","Type":"json","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"shared","Field":"shared","Type":"boolean","Help":"","Required":false},{"Name":"tokens","Field":"tokens","Type":"json","Help":"","Required":false}],"Example":null},{"Service":"studio","Name":"chat-create","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.","Method":"POST","Path":"/v1/studio/chat","Args":[],"Flags":[{"Name":"assets","Field":"assets","Type":"json","Help":"","Required":false},{"Name":"brand","Field":"brand","Type":"string","Help":"","Required":false},{"Name":"message","Field":"message","Type":"string","Help":"","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"","Required":false},{"Name":"thread","Field":"thread","Type":"string","Help":"","Required":false}],"Example":null,"Stream":"sse"},{"Service":"studio","Name":"documents-create","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.","Method":"POST","Path":"/v1/studio/documents","Args":[],"Flags":[{"Name":"brand","Field":"brand","Type":"string","Help":"","Required":false},{"Name":"ir","Field":"ir","Type":"json","Help":"","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind is doc or deck.","Required":false},{"Name":"shared","Field":"shared","Type":"boolean","Help":"","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"","Required":false}],"Example":{"ir":{"slides":[{"layout":"title","title":"Q3 review"}]},"kind":"deck","title":"Q3 review"}},{"Service":"studio","Name":"documents-delete","OperationID":"delete_studio_documents_by_id","Summary":"Deletes one of your documents.","Description":"Deletes one of your documents.","Method":"DELETE","Path":"/v1/studio/documents/:id","Args":[{"Name":"id","Help":"ID is the resource's id, from the path."}],"Flags":null,"Example":null},{"Service":"studio","Name":"documents-get","OperationID":"get_studio_documents_by_id","Summary":"Reads one document you may read.","Description":"Reads one document you may read.","Method":"GET","Path":"/v1/studio/documents/:id","Args":[{"Name":"id","Help":"ID is the resource's id, from the path."}],"Flags":null,"Example":null},{"Service":"studio","Name":"documents-list","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.","Method":"GET","Path":"/v1/studio/documents","Args":[],"Flags":[{"Name":"kind","Field":"kind","Type":"string","Help":"Kind is doc or deck.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"cursor","Field":"cursor","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"studio","Name":"documents-update","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.","Method":"PATCH","Path":"/v1/studio/documents/:id","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"brand","Field":"brand","Type":"string","Help":"","Required":false},{"Name":"ir","Field":"ir","Type":"json","Help":"","Required":false},{"Name":"shared","Field":"shared","Type":"boolean","Help":"","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"studio","Name":"estimate-create","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.","Method":"POST","Path":"/v1/studio/estimate","Args":[],"Flags":[{"Name":"brand","Field":"brand","Type":"string","Help":"Brand is a brand id; its tokens are brand.* in the graph.","Required":false},{"Name":"flow","Field":"flow","Type":"string","Help":"Flow is a flow id.","Required":false},{"Name":"graph","Field":"graph","Type":"json","Help":"","Required":false},{"Name":"input","Field":"input","Type":"json","Help":"Input are the values the inputs schema asks for.","Required":false},{"Name":"parent","Field":"parent","Type":"string","Help":"Parent makes this run the next version of that run.","Required":false},{"Name":"shared","Field":"shared","Type":"boolean","Help":"","Required":false},{"Name":"template","Field":"template","Type":"string","Help":"Template is a template id.","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"studio","Name":"flows-create","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}.","Method":"POST","Path":"/v1/studio/flows","Args":[],"Flags":[{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"graph","Field":"graph","Type":"json","Help":"","Required":false},{"Name":"inputs","Field":"inputs","Type":"json","Help":"","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"shared","Field":"shared","Type":"boolean","Help":"","Required":false}],"Example":null},{"Service":"studio","Name":"flows-delete","OperationID":"delete_studio_flows_by_id","Summary":"Deletes one of your flows.","Description":"Deletes one of your flows.","Method":"DELETE","Path":"/v1/studio/flows/:id","Args":[{"Name":"id","Help":"ID is the resource's id, from the path."}],"Flags":null,"Example":null},{"Service":"studio","Name":"flows-get","OperationID":"get_studio_flows_by_id","Summary":"Reads one flow you may read.","Description":"Reads one flow you may read.","Method":"GET","Path":"/v1/studio/flows/:id","Args":[{"Name":"id","Help":"ID is the resource's id, from the path."}],"Flags":null,"Example":null},{"Service":"studio","Name":"flows-list","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.","Method":"GET","Path":"/v1/studio/flows","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit is how many rows one page holds, 1 to 100 (default 50).","Required":false},{"Name":"cursor","Field":"cursor","Type":"string","Help":"Cursor is the previous page's next.","Required":false}],"Example":null},{"Service":"studio","Name":"flows-update","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.","Method":"PATCH","Path":"/v1/studio/flows/:id","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"graph","Field":"graph","Type":"json","Help":"","Required":false},{"Name":"inputs","Field":"inputs","Type":"json","Help":"","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"","Required":false},{"Name":"shared","Field":"shared","Type":"boolean","Help":"","Required":false}],"Example":null},{"Service":"studio","Name":"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.","Method":"GET","Path":"/v1/studio/gpus","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit is how many rows one page holds, 1 to 100 (default 50).","Required":false},{"Name":"cursor","Field":"cursor","Type":"string","Help":"Cursor is the previous page's next.","Required":false}],"Example":null},{"Service":"studio","Name":"runs-cancel","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.","Method":"POST","Path":"/v1/studio/runs/:id/cancel","Args":[{"Name":"id","Help":"ID is the resource's id, from the path."}],"Flags":null,"Example":null},{"Service":"studio","Name":"runs-create","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.","Method":"POST","Path":"/v1/studio/runs","Args":[],"Flags":[{"Name":"brand","Field":"brand","Type":"string","Help":"Brand is a brand id; its tokens are brand.* in the graph.","Required":false},{"Name":"flow","Field":"flow","Type":"string","Help":"Flow is a flow id.","Required":false},{"Name":"graph","Field":"graph","Type":"json","Help":"","Required":false},{"Name":"input","Field":"input","Type":"json","Help":"Input are the values the inputs schema asks for.","Required":false},{"Name":"parent","Field":"parent","Type":"string","Help":"Parent makes this run the next version of that run.","Required":false},{"Name":"shared","Field":"shared","Type":"boolean","Help":"","Required":false},{"Name":"template","Field":"template","Type":"string","Help":"Template is a template id.","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"","Required":false}],"Example":{"input":{"prompt":"a lighthouse at dawn, risograph"},"template":"image"}},{"Service":"studio","Name":"runs-events-list","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.","Method":"GET","Path":"/v1/studio/runs/:id/events","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null,"Stream":"sse"},{"Service":"studio","Name":"runs-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.","Method":"GET","Path":"/v1/studio/runs/:id","Args":[{"Name":"id","Help":"ID is the resource's id, from the path."}],"Flags":null,"Example":null},{"Service":"studio","Name":"runs-list","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.","Method":"GET","Path":"/v1/studio/runs","Args":[],"Flags":[{"Name":"kind","Field":"kind","Type":"string","Help":"","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status keeps only runs at this status.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"cursor","Field":"cursor","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"studio","Name":"runs-retry","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.","Method":"POST","Path":"/v1/studio/runs/:id/retry","Args":[{"Name":"id","Help":"ID is the resource's id, from the path."}],"Flags":null,"Example":null},{"Service":"studio","Name":"runs-update","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.","Method":"PATCH","Path":"/v1/studio/runs/:id","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"shared","Field":"shared","Type":"boolean","Help":"","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"studio","Name":"runs-versions-list","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.","Method":"GET","Path":"/v1/studio/runs/:id/versions","Args":[{"Name":"id","Help":"ID is the resource's id, from the path."}],"Flags":null,"Example":null},{"Service":"studio","Name":"templates-create","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.","Method":"POST","Path":"/v1/studio/templates","Args":[],"Flags":[{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"graph","Field":"graph","Type":"json","Help":"","Required":false},{"Name":"inputs","Field":"inputs","Type":"json","Help":"","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"","Required":false},{"Name":"preview","Field":"preview","Type":"string","Help":"","Required":false},{"Name":"shared","Field":"shared","Type":"boolean","Help":"","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"","Required":false}],"Example":{"graph":{"steps":[{"id":"html","op":"chat","with":{"prompt":"{{input.brief}}"}}]},"kind":"poster","title":"Event poster"}},{"Service":"studio","Name":"templates-delete","OperationID":"delete_studio_templates_by_id","Summary":"Deletes one of your templates.","Description":"Deletes one of your templates.","Method":"DELETE","Path":"/v1/studio/templates/:id","Args":[{"Name":"id","Help":"ID is the resource's id, from the path."}],"Flags":null,"Example":null},{"Service":"studio","Name":"templates-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.","Method":"GET","Path":"/v1/studio/templates/:id","Args":[{"Name":"id","Help":"ID is the resource's id, from the path."}],"Flags":null,"Example":null},{"Service":"studio","Name":"templates-list","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.","Method":"GET","Path":"/v1/studio/templates","Args":[],"Flags":[{"Name":"kind","Field":"kind","Type":"string","Help":"Kind keeps only templates that make this: image, poster, document, slides,\ntype, model, ad, video, film, voice, music or other.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"","Required":false},{"Name":"cursor","Field":"cursor","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"studio","Name":"templates-update","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.","Method":"PATCH","Path":"/v1/studio/templates/:id","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"description","Field":"description","Type":"string","Help":"","Required":false},{"Name":"graph","Field":"graph","Type":"json","Help":"","Required":false},{"Name":"inputs","Field":"inputs","Type":"json","Help":"","Required":false},{"Name":"preview","Field":"preview","Type":"string","Help":"","Required":false},{"Name":"shared","Field":"shared","Type":"boolean","Help":"","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"studio","Name":"threads-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.","Method":"DELETE","Path":"/v1/studio/threads/:id","Args":[{"Name":"id","Help":"ID is the resource's id, from the path."}],"Flags":null,"Example":null},{"Service":"studio","Name":"threads-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.","Method":"GET","Path":"/v1/studio/threads/:id","Args":[{"Name":"id","Help":"ID is the resource's id, from the path."}],"Flags":null,"Example":null},{"Service":"studio","Name":"threads-list","OperationID":"get_studio_threads","Summary":"Lists your chat threads, most recent first.","Description":"Lists your chat threads, most recent first.","Method":"GET","Path":"/v1/studio/threads","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit is how many rows one page holds, 1 to 100 (default 50).","Required":false},{"Name":"cursor","Field":"cursor","Type":"string","Help":"Cursor is the previous page's next.","Required":false}],"Example":null},{"Service":"sync","Name":"create","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.","Method":"POST","Path":"/v1/sync","Args":[],"Flags":[{"Name":"actor","Field":"actor","Type":"string","Help":"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.","Required":false},{"Name":"direction","Field":"direction","Type":"string","Help":"Direction is both (the default), pull, push or off.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind is what is being synced. Only \"git\" today, which is also the default.","Required":false},{"Name":"run","Field":"run","Type":"boolean","Help":"Run reconciles once immediately after the upsert, in the background.","Required":false},{"Name":"source","Field":"source","Type":"json","Help":"Source is the upstream end. Required.","Required":false},{"Name":"target","Field":"target","Type":"json","Help":"Target is the downstream end. Optional for git: a native repository named\nafter the source is derived when it is omitted.","Required":false},{"Name":"trigger","Field":"trigger","Type":"string","Help":"Trigger is what starts a reconcile: webhook (the default), poll or manual.","Required":false}],"Example":{"run":true,"source":{"locator":"https://github.com/acme/site","provider":"github"}}},{"Service":"sync","Name":"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.","Method":"DELETE","Path":"/v1/sync/:id","Args":[{"Name":"id","Help":"ID is the sync to act on, from the path."}],"Flags":null,"Example":{"id":"sync_1"}},{"Service":"sync","Name":"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.","Method":"GET","Path":"/v1/sync/:id","Args":[{"Name":"id","Help":"ID is the sync to act on, from the path."}],"Flags":null,"Example":{"id":"sync_1"}},{"Service":"sync","Name":"list","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.","Method":"GET","Path":"/v1/sync","Args":[],"Flags":null,"Example":null},{"Service":"sync","Name":"run","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.","Method":"POST","Path":"/v1/sync/:id/run","Args":[{"Name":"id","Help":"ID is the sync to act on, from the path."}],"Flags":null,"Example":{"id":"sync_1"}},{"Service":"sync","Name":"update","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.","Method":"PATCH","Path":"/v1/sync/:id","Args":[{"Name":"id","Help":"ID is the sync to update, from the path."}],"Flags":[{"Name":"actor","Field":"actor","Type":"string","Help":"Actor is the loop-guard identity the sync writes as. Omitted, the stored actor\nstands.","Required":false},{"Name":"direction","Field":"direction","Type":"string","Help":"Direction is both, pull, push or off. Omitted, the stored direction stands.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind names a different kind of sync, and is refused, for the same reason.","Required":false},{"Name":"source","Field":"source","Type":"json","Help":"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.","Required":false},{"Name":"target","Field":"target","Type":"json","Help":"Target names a new native repository, and is refused, for the same reason.","Required":false},{"Name":"trigger","Field":"trigger","Type":"string","Help":"Trigger is webhook, poll or manual. Omitted, the stored trigger stands.","Required":false}],"Example":{"direction":"pull","id":"sync_1"}},{"Service":"task","Name":"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.","Method":"GET","Path":"/v1/task/board","Args":[],"Flags":[{"Name":"key","Field":"key","Type":"string","Help":"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.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status keeps only issues in that board column: backlog, todo, in_progress,\ndone or canceled. An unknown value is refused with 400.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind keeps only work items of that shape: issue, pr or epic. An unknown\nvalue is refused with 400.","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"Repo keeps only issues bound to that git repository.","Required":false},{"Name":"label","Field":"label","Type":"string","Help":"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.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source keeps only issues opened from that surface: team, git, crm,\nhelpdesk, cms or agent. An unknown value is refused with 400.","Required":false},{"Name":"scheduled","Field":"scheduled","Type":"boolean","Help":"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.","Required":false}],"Example":null},{"Service":"task","Name":"issues-list","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.","Method":"GET","Path":"/v1/task/issues","Args":[],"Flags":[{"Name":"q","Field":"q","Type":"string","Help":"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.","Required":false},{"Name":"project","Field":"project","Type":"string","Help":"Project narrows to one team key; \"\" searches every project in the org,\nwhich is the point of this op.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status keeps one board column: backlog, todo, in_progress, done, canceled.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind keeps one shape: issue, pr, epic.","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"Repo keeps issues bound to one git repository.","Required":false},{"Name":"room","Field":"room","Type":"string","Help":"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.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source keeps one origin: team, git, crm, helpdesk, cms, agent. \"git\" is\nhow you ask for the mirrored GitHub issues specifically.","Required":false},{"Name":"assignee","Field":"assignee","Type":"string","Help":"Assignee keeps issues held by one person. Pass \"me\" for yourself.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"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.","Required":false}],"Example":null},{"Service":"task","Name":"projects-claim","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.","Method":"POST","Path":"/v1/task/projects/:key/issues/:num/claim","Args":[{"Name":"key","Help":""},{"Name":"num","Help":""}],"Flags":null,"Example":null},{"Service":"task","Name":"projects-comments-list","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.","Method":"GET","Path":"/v1/task/projects/:key/issues/:num/comments","Args":[{"Name":"key","Help":"Key is the board — the repository name, or an index board's key."},{"Name":"num","Help":"Num is the issue's number on that board."}],"Flags":null,"Example":{"key":"site","num":1}},{"Service":"task","Name":"projects-create","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.","Method":"POST","Path":"/v1/task/projects","Args":[],"Flags":null,"Example":null},{"Service":"task","Name":"projects-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.","Method":"DELETE","Path":"/v1/task/projects/:key","Args":[{"Name":"key","Help":""}],"Flags":null,"Example":null},{"Service":"task","Name":"projects-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.","Method":"GET","Path":"/v1/task/projects/:key","Args":[{"Name":"key","Help":"Key is the project's org-unique handle: 2-8 uppercase alphanumerics starting\nwith a letter (\"ENG\", \"OPS2\"). Matched case-insensitively."}],"Flags":null,"Example":null},{"Service":"task","Name":"projects-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.","Method":"GET","Path":"/v1/task/projects/:key/issues/:num","Args":[{"Name":"key","Help":"Key is the board — the repository name, or an index board's key."},{"Name":"num","Help":"Num is the issue's number on that board."}],"Flags":null,"Example":null},{"Service":"task","Name":"projects-issues","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.","Method":"POST","Path":"/v1/task/projects/:key/issues","Args":[{"Name":"key","Help":"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."}],"Flags":[{"Name":"description","Field":"description","Type":"string","Help":"Description becomes the issue body.","Required":false},{"Name":"priority","Field":"priority","Type":"string","Help":"Priority is one of none, urgent, high, medium or low.","Required":false},{"Name":"reply","Field":"reply","Type":"json","Help":"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.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status is the board column to open into: backlog, todo, in_progress, done\nor canceled. Empty opens into backlog.","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"task","Name":"projects-issues-list","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.","Method":"GET","Path":"/v1/task/projects/:key/issues","Args":[{"Name":"key","Help":"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."}],"Flags":[{"Name":"status","Field":"status","Type":"string","Help":"Status keeps only issues in that board column: backlog, todo, in_progress,\ndone or canceled. An unknown value is refused with 400.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind keeps only work items of that shape: issue, pr or epic. An unknown\nvalue is refused with 400.","Required":false},{"Name":"repo","Field":"repo","Type":"string","Help":"Repo keeps only issues bound to that git repository.","Required":false},{"Name":"label","Field":"label","Type":"string","Help":"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.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source keeps only issues opened from that surface: team, git, crm,\nhelpdesk, cms or agent. An unknown value is refused with 400.","Required":false},{"Name":"scheduled","Field":"scheduled","Type":"boolean","Help":"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.","Required":false}],"Example":null},{"Service":"task","Name":"projects-list","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.","Method":"GET","Path":"/v1/task/projects","Args":[],"Flags":null,"Example":null},{"Service":"task","Name":"projects-update","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.","Method":"PATCH","Path":"/v1/task/projects/:key","Args":[{"Name":"key","Help":""}],"Flags":null,"Example":null},{"Service":"task","Name":"projects-update","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`.","Method":"PATCH","Path":"/v1/task/projects/:key/issues/:num","Args":[{"Name":"key","Help":"Key is the board — the repository name, from the path."},{"Name":"num","Help":"Num is the issue number on that repository, from the path."}],"Flags":[{"Name":"assignee","Field":"assignee","Type":"string","Help":"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.","Required":false},{"Name":"comment","Field":"comment","Type":"string","Help":"Comment is posted on the issue, after every other change — what a person in\nthe issue's thread wants said on it.","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"Description rewrites the body.","Required":false},{"Name":"priority","Field":"priority","Type":"string","Help":"Priority re-prioritises it.","Required":false},{"Name":"reply","Field":"reply","Type":"json","Help":"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.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status moves the card to another column.","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"Title renames the work item.","Required":false}],"Example":null},{"Service":"task","Name":"rooms-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.","Method":"GET","Path":"/v1/task/rooms/:room","Args":[{"Name":"room","Help":"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."}],"Flags":null,"Example":null},{"Service":"tax","Name":"filings-create","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.","Method":"POST","Path":"/v1/tax/filings","Args":[],"Flags":[{"Name":"kind","Field":"kind","Type":"string","Help":"Kind is 1099-NEC or 1099-MISC.","Required":false},{"Name":"year","Field":"year","Type":"integer","Help":"Year is the tax year.","Required":false}],"Example":{"kind":"1099-NEC","year":2026}},{"Service":"tax","Name":"filings-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.","Method":"GET","Path":"/v1/tax/filings/:id","Args":[{"Name":"id","Help":"ID is the filing id, \"iris_\"-prefixed."}],"Flags":null,"Example":null},{"Service":"tax","Name":"filings-list","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.","Method":"GET","Path":"/v1/tax/filings","Args":[],"Flags":null,"Example":null},{"Service":"tax","Name":"filings-receipt","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.","Method":"POST","Path":"/v1/tax/filings/:id/receipt","Args":[{"Name":"id","Help":"ID is the filing, from the path."}],"Flags":[{"Name":"receipt-id","Field":"receiptId","Type":"string","Help":"ReceiptID is the Receipt ID IRIS returned for the submission.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status is submitted (IRIS returned a Receipt ID), accepted,\naccepted_with_errors or rejected (IRIS's acknowledgment).","Required":false},{"Name":"tcc","Field":"tcc","Type":"string","Help":"TCC is the IRIS Transmitter Control Code the payer submitted under: five\nuppercase letters and digits.","Required":false}],"Example":{"receiptId":"2026-12345678901-abc123def","status":"submitted","tcc":"D1234"}},{"Service":"tax","Name":"forms-correct","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.","Method":"POST","Path":"/v1/tax/forms/:id/correct","Args":[{"Name":"id","Help":"ID is the furnished form to correct, from the path."}],"Flags":[{"Name":"boxes","Field":"boxes","Type":"json","Help":"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.","Required":false},{"Name":"reason","Field":"reason","Type":"string","Help":"Reason says what was wrong. Required; it goes on the record.","Required":false}],"Example":{"boxes":[{"box":"1a","cents":250000}],"reason":"a December settlement was refunded"}},{"Service":"tax","Name":"forms-create","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.","Method":"POST","Path":"/v1/tax/forms","Args":[],"Flags":[{"Name":"year","Field":"year","Type":"integer","Help":"Year is the calendar year the payments were made in.","Required":false}],"Example":{"year":2026}},{"Service":"tax","Name":"forms-furnish","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.","Method":"POST","Path":"/v1/tax/forms/:id/furnish","Args":[{"Name":"id","Help":"ID is the form id, \"f1099_\"-prefixed."}],"Flags":null,"Example":null},{"Service":"tax","Name":"forms-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.","Method":"GET","Path":"/v1/tax/forms/:id","Args":[{"Name":"id","Help":"ID is the form id, \"f1099_\"-prefixed."}],"Flags":null,"Example":null},{"Service":"tax","Name":"forms-list","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.","Method":"GET","Path":"/v1/tax/forms","Args":[],"Flags":[{"Name":"year","Field":"year","Type":"integer","Help":"Year narrows the list to one tax year; absent lists every year.","Required":false}],"Example":null},{"Service":"tax","Name":"forms-mailed","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.","Method":"POST","Path":"/v1/tax/forms/:id/mailed","Args":[{"Name":"id","Help":"ID is the form id, \"f1099_\"-prefixed."}],"Flags":null,"Example":null},{"Service":"tax","Name":"forms-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.","Method":"GET","Path":"/v1/tax/forms/:id/pdf","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"tax","Name":"forms-review","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.","Method":"POST","Path":"/v1/tax/forms/:id/review","Args":[{"Name":"id","Help":"ID is the form id, \"f1099_\"-prefixed."}],"Flags":null,"Example":null},{"Service":"tax","Name":"forms-void","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.","Method":"POST","Path":"/v1/tax/forms/:id/void","Args":[{"Name":"id","Help":"ID is the form id, \"f1099_\"-prefixed."}],"Flags":null,"Example":null},{"Service":"tax","Name":"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.","Method":"GET","Path":"/v1/tax/inbox","Args":[],"Flags":[{"Name":"year","Field":"year","Type":"integer","Help":"Year narrows the list to one tax year; absent lists every year.","Required":false}],"Example":null},{"Service":"tax","Name":"inbox-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.","Method":"GET","Path":"/v1/tax/inbox/:id","Args":[{"Name":"id","Help":"ID is the form id, \"f1099_\"-prefixed."}],"Flags":null,"Example":null},{"Service":"tax","Name":"inbox-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.","Method":"GET","Path":"/v1/tax/inbox/:id/pdf","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"tax","Name":"payments-list","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.","Method":"GET","Path":"/v1/tax/payments","Args":[],"Flags":[{"Name":"year","Field":"year","Type":"integer","Help":"Year is the calendar year the payments were made in, e.g. 2026.","Required":false}],"Example":null},{"Service":"tax","Name":"profile-certify-create","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.","Method":"POST","Path":"/v1/tax/profile/certify","Args":[],"Flags":null,"Example":null},{"Service":"tax","Name":"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.","Method":"GET","Path":"/v1/tax/profile","Args":[],"Flags":null,"Example":null},{"Service":"tax","Name":"profile-update","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.","Method":"PUT","Path":"/v1/tax/profile","Args":[],"Flags":[{"Name":"address","Field":"address","Type":"json","Help":"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.","Required":false},{"Name":"business-name","Field":"businessName","Type":"string","Help":"BusinessName is line 2, when it differs from line 1.","Required":false},{"Name":"classification","Field":"classification","Type":"string","Help":"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.","Required":false},{"Name":"electronic-consent","Field":"electronicConsent","Type":"boolean","Help":"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.","Required":false},{"Name":"exempt-payee","Field":"exemptPayee","Type":"string","Help":"ExemptPayee is the exempt payee code, 1–13. Entities only.","Required":false},{"Name":"fatca","Field":"fatca","Type":"string","Help":"FATCA is the FATCA exemption code, A–M. Entities only.","Required":false},{"Name":"foreign-owners","Field":"foreignOwners","Type":"boolean","Help":"ForeignOwners is line 3b; only a partnership, trust/estate or llc_p may set it.","Required":false},{"Name":"foreign-tin","Field":"foreignTin","Type":"string","Help":"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.","Required":false},{"Name":"form","Field":"form","Type":"string","Help":"Form is w9 (a U.S. person), w8ben (a foreign individual) or w8bene (a\nforeign entity). w9 when omitted.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is line 1: the name on the income tax return, or the foreign\nindividual's or organization's name. Required.","Required":false},{"Name":"phone","Field":"phone","Type":"string","Help":"Phone is printed on the 1099s this org files as payer.","Required":false},{"Name":"tin","Field":"tin","Type":"string","Help":"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.","Required":false},{"Name":"tin-type","Field":"tinType","Type":"string","Help":"TINType is ssn (an SSN or ITIN) or ein. An entity other than an individual\nstates an EIN.","Required":false},{"Name":"w8","Field":"w8","Type":"json","Help":"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.","Required":false}],"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"}},{"Service":"tax","Name":"w9-create","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.","Method":"POST","Path":"/v1/tax/w9","Args":[],"Flags":[{"Name":"category","Field":"category","Type":"string","Help":"Category is what the caller pays it for: services, attorney, rents,\nroyalties, other or merchandise. Services when omitted.","Required":false},{"Name":"payee","Field":"payee","Type":"string","Help":"Payee is the org id of the company asked. The caller must have paid it on\nHanzo's rails.","Required":false}],"Example":{"category":"services","payee":"acme"}},{"Service":"tax","Name":"w9-decline","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.","Method":"POST","Path":"/v1/tax/w9/:id/decline","Args":[{"Name":"id","Help":"ID is the relationship's id, \"w9_\"-prefixed."}],"Flags":null,"Example":null},{"Service":"tax","Name":"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.","Method":"GET","Path":"/v1/tax/w9","Args":[],"Flags":null,"Example":null},{"Service":"tax","Name":"w9-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.","Method":"GET","Path":"/v1/tax/w9/:id","Args":[{"Name":"id","Help":"ID is the relationship's id, \"w9_\"-prefixed."}],"Flags":null,"Example":null},{"Service":"tax","Name":"w9-grant","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.","Method":"POST","Path":"/v1/tax/w9/:id/grant","Args":[{"Name":"id","Help":"ID is the relationship's id, \"w9_\"-prefixed."}],"Flags":null,"Example":null},{"Service":"tax","Name":"w9-match","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.","Method":"POST","Path":"/v1/tax/w9/:id/match","Args":[{"Name":"id","Help":"ID is the relationship, from the path."}],"Flags":[{"Name":"result","Field":"result","Type":"string","Help":"Result is what IRS TIN Matching answered for this payee's name and TIN:\nmatched or mismatched.","Required":false}],"Example":{"result":"matched"}},{"Service":"tax","Name":"w9-revoke","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.","Method":"POST","Path":"/v1/tax/w9/:id/revoke","Args":[{"Name":"id","Help":"ID is the relationship's id, \"w9_\"-prefixed."}],"Flags":null,"Example":null},{"Service":"tax","Name":"w9-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.","Method":"GET","Path":"/v1/tax/w9/:id/tin","Args":[{"Name":"id","Help":"ID is the relationship's id, \"w9_\"-prefixed."}],"Flags":null,"Example":null},{"Service":"taxonomy","Name":"categories-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.","Method":"DELETE","Path":"/v1/taxonomy/categories/:id","Args":[{"Name":"id","Help":"ID is the slug to act on, from the path."}],"Flags":null,"Example":null},{"Service":"taxonomy","Name":"categories-update","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.","Method":"PUT","Path":"/v1/taxonomy/categories/:id","Args":[{"Name":"id","Help":"ID is the category slug to write, from the path."}],"Flags":[{"Name":"brands","Field":"brands","Type":"json","Help":"Brands are the brands whose console shows it. Omit for every brand.","Required":false},{"Name":"label","Field":"label","Type":"string","Help":"Label is the display name. Required.","Required":false},{"Name":"order","Field":"order","Type":"integer","Help":"Order is where the category sits among its siblings, ascending.","Required":false},{"Name":"summary","Field":"summary","Type":"string","Help":"Summary is the one line describing what the category groups.","Required":false}],"Example":{"label":"Observe","order":6,"summary":"Traces, metrics, logs and alerts."}},{"Service":"taxonomy","Name":"list","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.","Method":"GET","Path":"/v1/taxonomy","Args":[],"Flags":[{"Name":"brand","Field":"brand","Type":"string","Help":"Brand returns only what that brand's console shows — the categories it\nadmits, and within them the taxa scoped to it. Empty returns everything.","Required":false}],"Example":null},{"Service":"taxonomy","Name":"taxa-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.","Method":"DELETE","Path":"/v1/taxonomy/taxa/:id","Args":[{"Name":"id","Help":"ID is the slug to act on, from the path."}],"Flags":null,"Example":null},{"Service":"taxonomy","Name":"taxa-update","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.","Method":"PUT","Path":"/v1/taxonomy/taxa/:id","Args":[{"Name":"id","Help":"ID is the taxon slug to write, from the path."}],"Flags":[{"Name":"brands","Field":"brands","Type":"json","Help":"Brands are the brands whose console shows it. Omit for every brand its\ncategory admits.","Required":false},{"Name":"category","Field":"category","Type":"string","Help":"Category is the id of an EXISTING category to file it under. Required.","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"Description is the one line shown beneath the name.","Required":false},{"Name":"href","Field":"href","Type":"string","Help":"Href is the absolute URL an external product launches. Give this or route,\nnever both.","Required":false},{"Name":"icon","Field":"icon","Type":"string","Help":"Icon names the icon the surface renders, e.g. \"Database\".","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the display name. Required.","Required":false},{"Name":"order","Field":"order","Type":"integer","Help":"Order is where it sits within its category, ascending.","Required":false},{"Name":"published","Field":"published","Type":"boolean","Help":"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.","Required":false},{"Name":"route","Field":"route","Type":"string","Help":"Route is the in-console path it opens, e.g. \"/vector\". Give this or href,\nnever both.","Required":false},{"Name":"tags","Field":"tags","Type":"json","Help":"Tags are free-form labels for search and grouping across categories.","Required":false}],"Example":{"category":"data","description":"Managed vector search.","icon":"Database","name":"Vector","order":3,"route":"/vector","tags":["search"]}},{"Service":"team","Name":"account-auth-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.","Method":"GET","Path":"/v1/team/account/auth/:provider/callback","Args":[{"Name":"provider","Help":""}],"Flags":null,"Example":null},{"Service":"team","Name":"account-auth-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.","Method":"GET","Path":"/v1/team/account/auth/:provider","Args":[{"Name":"provider","Help":""}],"Flags":null,"Example":null},{"Service":"team","Name":"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.","Method":"DELETE","Path":"/v1/team/account/cookie","Args":[],"Flags":null,"Example":null},{"Service":"team","Name":"account-cookie-update","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.","Method":"PUT","Path":"/v1/team/account/cookie","Args":[],"Flags":null,"Example":null},{"Service":"team","Name":"account-create","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.","Method":"POST","Path":"/v1/team/account","Args":[],"Flags":null,"Example":null},{"Service":"team","Name":"account-providers-list","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.","Method":"GET","Path":"/v1/team/account/providers","Args":[],"Flags":null,"Example":null},{"Service":"team","Name":"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\".","Method":"GET","Path":"/v1/team/billing/plan","Args":[],"Flags":null,"Example":null},{"Service":"team","Name":"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.","Method":"GET","Path":"/v1/team/billing/ui","Args":[],"Flags":null,"Example":null,"Stream":"bytes"},{"Service":"team","Name":"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.","Method":"GET","Path":"/v1/team/collaborator","Args":[],"Flags":null,"Example":null},{"Service":"team","Name":"collaborator-rpc-create","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.","Method":"POST","Path":"/v1/team/collaborator/rpc/:documentId","Args":[{"Name":"documentId","Help":"DocumentID addresses the document field, as\n\"\u003cspaceUuid\u003e|\u003cobjectClass\u003e|\u003cobjectId\u003e|\u003cobjectAttr\u003e\" — the\ncollaborator-client encodeDocumentId shape, from the path."}],"Flags":[{"Name":"method","Field":"method","Type":"string","Help":"Method is the verb: createContent, updateContent or getContent.","Required":false},{"Name":"payload","Field":"payload","Type":"json","Help":"Payload is the verb's argument.","Required":false}],"Example":{"documentId":"6579…|tracker:class:Issue|issue-1|description","method":"getContent","payload":{"source":"issue-1-description-1730000000000"}}},{"Service":"team","Name":"dms-create","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.","Method":"POST","Path":"/v1/team/dms","Args":[],"Flags":[{"Name":"members","Field":"members","Type":"json","Help":"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.","Required":false},{"Name":"space","Field":"space","Type":"string","Help":"Space is the space uuid. Optional for a caller in exactly one space.","Required":false}],"Example":{"members":["9f2c…"]}},{"Service":"team","Name":"docs-comments","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.","Method":"POST","Path":"/v1/team/docs/:id/comments","Args":[{"Name":"id","Help":"ID is the document, from the path."}],"Flags":[{"Name":"files","Field":"files","Type":"json","Help":"Files attaches blobs already uploaded to the space.","Required":false},{"Name":"space","Field":"space","Type":"string","Help":"Space is the space uuid holding it. Body-only.","Required":false},{"Name":"text","Field":"text","Type":"string","Help":"Text is the comment, with the same `\u003c@account-uuid\u003e` mentions a message\ntakes.","Required":false}],"Example":{"space":"0e3c…","text":"step 3 is out of date, \u003c@9f2c…\u003e"}},{"Service":"team","Name":"docs-comments-list","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.","Method":"GET","Path":"/v1/team/docs/:id/comments","Args":[{"Name":"id","Help":"ID is the document, from the path."}],"Flags":[{"Name":"space","Field":"space","Type":"string","Help":"Space is the space uuid holding it.","Required":false}],"Example":null},{"Service":"team","Name":"docs-create","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.","Method":"POST","Path":"/v1/team/docs","Args":[],"Flags":[{"Name":"parent","Field":"parent","Type":"string","Help":"Parent nests the new document under another one.","Required":false},{"Name":"space","Field":"space","Type":"string","Help":"Space is the space uuid. Optional for a caller in exactly one space.","Required":false},{"Name":"teamspace","Field":"teamspace","Type":"string","Help":"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.","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"Title is the document's title. Empty reads \"Untitled\", as in the Team\nclient.","Required":false}],"Example":{"parent":"d41c","title":"Runbook"}},{"Service":"team","Name":"docs-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.","Method":"DELETE","Path":"/v1/team/docs/:id","Args":[{"Name":"id","Help":"ID is the document, from the path."}],"Flags":[{"Name":"space","Field":"space","Type":"string","Help":"Space is the space uuid holding it.","Required":false}],"Example":{"space":"0e3c…"}},{"Service":"team","Name":"docs-get","OperationID":"get_team_docs_by_id","Summary":"Returns one document the caller may see.","Description":"Returns one document the caller may see.","Method":"GET","Path":"/v1/team/docs/:id","Args":[{"Name":"id","Help":"ID is the document, from the path."}],"Flags":[{"Name":"space","Field":"space","Type":"string","Help":"Space is the space uuid holding it.","Required":false}],"Example":{"id":"d41c","space":"0e3c…"}},{"Service":"team","Name":"docs-list","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.","Method":"GET","Path":"/v1/team/docs","Args":[],"Flags":[{"Name":"space","Field":"space","Type":"string","Help":"Space is the space uuid. Optional for a caller in exactly one space.","Required":false},{"Name":"teamspace","Field":"teamspace","Type":"string","Help":"Teamspace narrows the answer to one teamspace.","Required":false},{"Name":"parent","Field":"parent","Type":"string","Help":"Parent narrows the answer to one document's children.","Required":false}],"Example":null},{"Service":"team","Name":"docs-update","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.","Method":"PATCH","Path":"/v1/team/docs/:id","Args":[{"Name":"id","Help":"ID is the document, from the path."}],"Flags":[{"Name":"parent","Field":"parent","Type":"string","Help":"Parent moves the document under another one; \"\" moves it to the top of\nits teamspace. It goes after its new siblings.","Required":false},{"Name":"space","Field":"space","Type":"string","Help":"Space is the space uuid holding it. Body-only.","Required":false},{"Name":"teamspace","Field":"teamspace","Type":"string","Help":"Teamspace moves the document — with everything nested under it — to\nanother teamspace, at the top unless Parent names a document there.","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"Title renames the document. Empty reads \"Untitled\".","Required":false}],"Example":{"parent":"","space":"0e3c…","title":"Runbook (2026)"}},{"Service":"team","Name":"events-list","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.","Method":"GET","Path":"/v1/team/events","Args":[],"Flags":null,"Example":null,"Stream":"sse"},{"Service":"team","Name":"files-create","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.","Method":"POST","Path":"/v1/team/files/:space","Args":[{"Name":"space","Help":""}],"Flags":[{"Name":"body","Field":"body","Type":"file","Help":"","Required":false,"In":"body"}],"Example":null,"Consumes":["application/octet-stream"],"Stream":"bytes"},{"Service":"team","Name":"files-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.","Method":"DELETE","Path":"/v1/team/files/:space/:filename","Args":[{"Name":"space","Help":"Space is the space uuid the blob belongs to, from the path."},{"Name":"filename","Help":"Filename is the last path segment, which the front sets to the blob id\nwhen it sends no explicit `file`."}],"Flags":[{"Name":"file","Field":"file","Type":"string","Help":"File is the blob id, and wins over the path segment when both are present.","Required":false}],"Example":{"file":"0d4f…","space":"6579…"}},{"Service":"team","Name":"files-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.","Method":"GET","Path":"/v1/team/files/:space/:filename","Args":[{"Name":"space","Help":""},{"Name":"filename","Help":""}],"Flags":null,"Example":null,"Stream":"bytes"},{"Service":"team","Name":"inbox-archive","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`.","Method":"POST","Path":"/v1/team/inbox/:id/archive","Args":[{"Name":"id","Help":"ID is the notification, from the path."}],"Flags":[{"Name":"space","Field":"space","Type":"string","Help":"Space is the space uuid it was filed in. Body-only.","Required":false}],"Example":{"space":"0e3c…"}},{"Service":"team","Name":"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.","Method":"GET","Path":"/v1/team/inbox","Args":[],"Flags":[{"Name":"space","Field":"space","Type":"string","Help":"Space is the space uuid. Optional for a caller in exactly one space.","Required":false},{"Name":"archived","Field":"archived","Type":"boolean","Help":"Archived lists the archived notifications instead of the live ones.","Required":false}],"Example":null},{"Service":"team","Name":"inbox-read","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.","Method":"POST","Path":"/v1/team/inbox/:id/read","Args":[{"Name":"id","Help":"ID is the notification, from the path."}],"Flags":[{"Name":"space","Field":"space","Type":"string","Help":"Space is the space uuid it was filed in. Body-only.","Required":false}],"Example":{"space":"0e3c…"}},{"Service":"team","Name":"inbox-read-create","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.","Method":"POST","Path":"/v1/team/inbox/read","Args":[],"Flags":[{"Name":"space","Field":"space","Type":"string","Help":"Space is the space uuid. Optional for a caller in exactly one space.","Required":false}],"Example":{"space":"0e3c…"}},{"Service":"team","Name":"members-list","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.","Method":"GET","Path":"/v1/team/members","Args":[],"Flags":[{"Name":"space","Field":"space","Type":"string","Help":"Space is the space uuid. Optional for a caller in exactly one space.","Required":false}],"Example":null},{"Service":"team","Name":"messages-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.","Method":"DELETE","Path":"/v1/team/messages/:id","Args":[{"Name":"id","Help":"ID is the message, from the path."}],"Flags":[{"Name":"space","Field":"space","Type":"string","Help":"Space names the space holding it. A message id is unique within a space,\nnot across the org.","Required":false}],"Example":{"space":"0e3c…"}},{"Service":"team","Name":"messages-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.","Method":"DELETE","Path":"/v1/team/messages/:id/reactions/:emoji","Args":[{"Name":"id","Help":"ID is the message, from the path."},{"Name":"emoji","Help":"Emoji is the reaction, from the path (percent-encoded on the wire)."}],"Flags":[{"Name":"space","Field":"space","Type":"string","Help":"Space names the space holding the message.","Required":false}],"Example":{"space":"0e3c…"}},{"Service":"team","Name":"messages-replies","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.","Method":"POST","Path":"/v1/team/messages/:id/replies","Args":[{"Name":"id","Help":"ID is the message being answered, from the path."}],"Flags":[{"Name":"files","Field":"files","Type":"json","Help":"Files attaches blobs already uploaded to the space.","Required":false},{"Name":"space","Field":"space","Type":"string","Help":"Space names the space holding it. Body-only.","Required":false},{"Name":"text","Field":"text","Type":"string","Help":"Text is the reply, with the same `\u003c@account-uuid\u003e` mentions a message\ntakes.","Required":false}],"Example":{"space":"0e3c…","text":"on it"}},{"Service":"team","Name":"messages-replies-list","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.","Method":"GET","Path":"/v1/team/messages/:id/replies","Args":[{"Name":"id","Help":"ID is the message, from the path."}],"Flags":[{"Name":"space","Field":"space","Type":"string","Help":"Space names the space holding it. A message id is unique within a space,\nnot across the org.","Required":false}],"Example":null},{"Service":"team","Name":"messages-update","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.","Method":"PATCH","Path":"/v1/team/messages/:id","Args":[{"Name":"id","Help":"ID is the message, from the path."}],"Flags":[{"Name":"space","Field":"space","Type":"string","Help":"Space names the space holding it. Body-only.","Required":false},{"Name":"text","Field":"text","Type":"string","Help":"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.","Required":false}],"Example":{"space":"0e3c…","text":"deploying at 3pm instead"}},{"Service":"team","Name":"messages-update","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 👍.","Method":"PUT","Path":"/v1/team/messages/:id/reactions/:emoji","Args":[{"Name":"id","Help":"ID is the message, from the path."},{"Name":"emoji","Help":"Emoji is the reaction, from the path (percent-encoded on the wire)."}],"Flags":[{"Name":"space","Field":"space","Type":"string","Help":"Space names the space holding the message. Body-only.","Required":false}],"Example":{"space":"0e3c…"}},{"Service":"team","Name":"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.","Method":"GET","Path":"/v1/team/public","Args":[],"Flags":[{"Name":"q","Field":"q","Type":"string","Help":"Q matches a room's name or its topic.","Required":false},{"Name":"org","Field":"org","Type":"string","Help":"Org narrows to one org's published rooms.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"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.","Required":false}],"Example":null},{"Service":"team","Name":"rooms-create","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.","Method":"POST","Path":"/v1/team/rooms","Args":[],"Flags":[{"Name":"bindings","Field":"bindings","Type":"json","Help":"Bindings are what the room is about, each \"\u003ckind\u003e:\u003cref\u003e\".","Required":false},{"Name":"life","Field":"life","Type":"string","Help":"Life is the lifecycle intent, \"standing\" or \"bound\"; empty reads standing.","Required":false},{"Name":"members","Field":"members","Type":"json","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false},{"Name":"private","Field":"private","Type":"boolean","Help":"Private restricts the room to its members. Public is the default because a\nroom nobody can find is the more surprising of the two.","Required":false},{"Name":"space","Field":"space","Type":"string","Help":"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.","Required":false},{"Name":"topic","Field":"topic","Type":"string","Help":"Topic is the room's one-line subject.","Required":false}],"Example":{"bindings":["issue:1010"],"life":"bound","name":"bugfix-1010"}},{"Service":"team","Name":"rooms-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.","Method":"DELETE","Path":"/v1/team/rooms/:id/members/:account","Args":[{"Name":"id","Help":"ID is the room, from the path."},{"Name":"account","Help":"Account is the account uuid to remove, from the path. Your own is leaving."}],"Flags":[{"Name":"space","Field":"space","Type":"string","Help":"Space is the space uuid holding the room.","Required":false}],"Example":{"space":"0e3c…"}},{"Service":"team","Name":"rooms-list","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.","Method":"GET","Path":"/v1/team/rooms","Args":[],"Flags":null,"Example":null},{"Service":"team","Name":"rooms-members","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.","Method":"POST","Path":"/v1/team/rooms/:id/members","Args":[{"Name":"id","Help":"ID is the room, from the path."}],"Flags":[{"Name":"members","Field":"members","Type":"json","Help":"Members are the account uuids to add — people or agents of the space.\nNaming only yourself joins a public channel.","Required":false},{"Name":"space","Field":"space","Type":"string","Help":"Space is the space uuid holding it. Body-only.","Required":false}],"Example":{"members":["9f2c…"],"space":"0e3c…"}},{"Service":"team","Name":"rooms-members-list","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.","Method":"GET","Path":"/v1/team/rooms/:id/members","Args":[{"Name":"id","Help":"ID is the room, from the path. The URL is the authority."}],"Flags":[{"Name":"space","Field":"space","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"team","Name":"rooms-messages","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).","Method":"POST","Path":"/v1/team/rooms/:id/messages","Args":[{"Name":"id","Help":"ID is the room to say it in, from the path."}],"Flags":[{"Name":"files","Field":"files","Type":"json","Help":"Files attaches blobs already uploaded to the space. A message may be\nfiles alone, with no text.","Required":false},{"Name":"space","Field":"space","Type":"string","Help":"Space names the space holding the room. Body-only: a query string may not\nredirect a write.","Required":false},{"Name":"text","Field":"text","Type":"string","Help":"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.","Required":false}],"Example":{"space":"0e3c…","text":"deploying now, \u003c@9f2c…\u003e can you watch the dashboards?"}},{"Service":"team","Name":"rooms-messages-list","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.","Method":"GET","Path":"/v1/team/rooms/:id/messages","Args":[{"Name":"id","Help":"ID is the room, from the path. The URL is the authority."}],"Flags":[{"Name":"space","Field":"space","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"team","Name":"rooms-update","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.","Method":"PATCH","Path":"/v1/team/rooms/:id","Args":[{"Name":"id","Help":"ID is the room, from the path."}],"Flags":[{"Name":"archived","Field":"archived","Type":"boolean","Help":"Archived closes the room (true) or reopens it (false). An archived room\nkeeps its history and takes no new messages.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name renames a channel. A direct message has no name.","Required":false},{"Name":"space","Field":"space","Type":"string","Help":"Space is the space uuid holding it. Body-only.","Required":false},{"Name":"topic","Field":"topic","Type":"string","Help":"Topic sets the channel's one-line subject; \"\" clears it.","Required":false}],"Example":{"archived":true,"space":"0e3c…"}},{"Service":"team","Name":"rooms-update","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.","Method":"PUT","Path":"/v1/team/rooms/:id","Args":[{"Name":"id","Help":"ID is the room to bind, from the path. The URL is the authority; a body\ncarrying another id cannot redirect the write."}],"Flags":[{"Name":"bindings","Field":"bindings","Type":"json","Help":"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.","Required":false},{"Name":"life","Field":"life","Type":"string","Help":"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.","Required":false},{"Name":"space","Field":"space","Type":"string","Help":"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.","Required":false}],"Example":{"bindings":["repo:hanzoai/cloud","issue:1010"],"life":"bound","space":"0e3c…"}},{"Service":"team","Name":"transactor-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.","Method":"GET","Path":"/v1/team/transactor/:token","Args":[{"Name":"token","Help":""}],"Flags":null,"Example":null},{"Service":"team","Name":"transactor-statistics-list","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.","Method":"GET","Path":"/v1/team/transactor/statistics","Args":[],"Flags":[{"Name":"token","Field":"token","Type":"string","Help":"Token is the space token minted by selectWorkspace.","Required":false}],"Example":{"token":"eyJhbGciOiJIUzI1NiJ9…"}},{"Service":"tel","Name":"calls-create","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.","Method":"POST","Path":"/v1/tel/calls","Args":[],"Flags":[{"Name":"agent","Field":"agent","Type":"string","Help":"Agent hands the answered call to a Hanzo assistant by name instead of\nconnecting it to a person. Empty places an ordinary call.","Required":false},{"Name":"from","Field":"from","Type":"string","Help":"From is the number to call FROM, in E.164. It must be one this org holds.","Required":false},{"Name":"record","Field":"record","Type":"boolean","Help":"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.","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"To is the number to call, in E.164.","Required":false},{"Name":"webhook","Field":"webhook","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"tel","Name":"calls-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.","Method":"DELETE","Path":"/v1/tel/calls/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"tel","Name":"calls-list","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.","Method":"GET","Path":"/v1/tel/calls","Args":[],"Flags":null,"Example":null},{"Service":"tel","Name":"messages-create","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.","Method":"POST","Path":"/v1/tel/messages","Args":[],"Flags":[{"Name":"from","Field":"from","Type":"string","Help":"From is the number to send FROM, in E.164. It must be one this org holds and it\nmust be sms-capable.","Required":false},{"Name":"media","Field":"media","Type":"json","Help":"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.","Required":false},{"Name":"text","Field":"text","Type":"string","Help":"Text is the message body. It may be empty when Media carries the message.","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"To is the number to send to, in E.164.","Required":false}],"Example":null},{"Service":"tel","Name":"messages-list","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.","Method":"GET","Path":"/v1/tel/messages","Args":[],"Flags":null,"Example":null},{"Service":"tel","Name":"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.","Method":"GET","Path":"/v1/tel/numbers/available","Args":[],"Flags":[{"Name":"country","Field":"Country","Type":"string","Help":"","Required":false},{"Name":"area","Field":"Area","Type":"string","Help":"","Required":false},{"Name":"type","Field":"Type","Type":"string","Help":"","Required":false},{"Name":"limit","Field":"Limit","Type":"integer","Help":"","Required":false}],"Example":null},{"Service":"tel","Name":"numbers-create","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.","Method":"POST","Path":"/v1/tel/numbers","Args":[],"Flags":[{"Name":"e164","Field":"e164","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"tel","Name":"numbers-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.","Method":"DELETE","Path":"/v1/tel/numbers/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"tel","Name":"numbers-list","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.","Method":"GET","Path":"/v1/tel/numbers","Args":[],"Flags":null,"Example":null},{"Service":"tel","Name":"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.","Method":"GET","Path":"/v1/tel/summary","Args":[],"Flags":null,"Example":null},{"Service":"template","Name":"create","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.","Method":"POST","Path":"/v1/template","Args":[],"Flags":[{"Name":"category","Field":"category","Type":"string","Help":"Category groups the kit in the gallery browser.","Required":false},{"Name":"demo","Field":"demo","Type":"string","Help":"Demo is the deployed site itself, when there is one.","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"Description is the browse-card blurb, max 4096 characters.","Required":false},{"Name":"features","Field":"features","Type":"json","Help":"Features are the highlights the card lists, at most 32.","Required":false},{"Name":"framework","Field":"framework","Type":"string","Help":"Framework is the stack the kit is built on (\"Next.js 14\").","Required":false},{"Name":"preview","Field":"preview","Type":"string","Help":"Preview is the still image the browse card renders, max 4096 characters.","Required":false},{"Name":"slug","Field":"slug","Type":"string","Help":"Slug is the kit's identity — lowercase alphanumeric with dashes, max 40.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source is the repository the kit is forked from, max 4096 characters.","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"Title is the display name. Required, max 200 characters.","Required":false},{"Name":"use-case","Field":"useCase","Type":"string","Help":"UseCase is what the kit is for, in a phrase.","Required":false},{"Name":"variants","Field":"variants","Type":"json","Help":"Variants are the shapes this kit ships in, at most 32; the fork picks one.","Required":false}],"Example":{"framework":"Next.js 14","slug":"acme-portal","title":"Acme Internal Portal"}},{"Service":"template","Name":"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.","Method":"DELETE","Path":"/v1/template/:slug","Args":[{"Name":"slug","Help":"Slug is the starter kit to act on, from the path."}],"Flags":null,"Example":{"slug":"acme-portal"}},{"Service":"template","Name":"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.","Method":"GET","Path":"/v1/template/:slug","Args":[{"Name":"slug","Help":"Slug is the starter kit to act on, from the path."}],"Flags":null,"Example":{"slug":"folio"}},{"Service":"template","Name":"list","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.","Method":"GET","Path":"/v1/template","Args":[],"Flags":null,"Example":null},{"Service":"template","Name":"update","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.","Method":"PUT","Path":"/v1/template/:slug","Args":[{"Name":"slug","Help":"Slug is the kit to replace, from the path."}],"Flags":[{"Name":"category","Field":"category","Type":"string","Help":"Category groups the kit in the gallery browser.","Required":false},{"Name":"demo","Field":"demo","Type":"string","Help":"Demo is the deployed site itself, when there is one.","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"Description is the browse-card blurb, max 4096 characters.","Required":false},{"Name":"features","Field":"features","Type":"json","Help":"Features are the highlights the card lists, at most 32.","Required":false},{"Name":"framework","Field":"framework","Type":"string","Help":"Framework is the stack the kit is built on (\"Next.js 14\").","Required":false},{"Name":"preview","Field":"preview","Type":"string","Help":"Preview is the still image the browse card renders, max 4096 characters.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source is the repository the kit is forked from, max 4096 characters.","Required":false},{"Name":"title","Field":"title","Type":"string","Help":"Title is the display name. Required, max 200 characters.","Required":false},{"Name":"use-case","Field":"useCase","Type":"string","Help":"UseCase is what the kit is for, in a phrase.","Required":false},{"Name":"variants","Field":"variants","Type":"json","Help":"Variants are the shapes this kit ships in, at most 32; the fork picks one.","Required":false}],"Example":{"slug":"acme-portal","title":"Acme Internal Portal v2"}},{"Service":"tool","Name":"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.","Method":"GET","Path":"/v1/tool/activation","Args":[],"Flags":null,"Example":null},{"Service":"tool","Name":"activation-update","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.","Method":"PUT","Path":"/v1/tool/activation","Args":[],"Flags":[{"Name":"activate","Field":"activate","Type":"json","Help":"Activate switches these tool names on for the caller's org and project.","Required":false},{"Name":"deactivate","Field":"deactivate","Type":"json","Help":"Deactivate switches these tool names off.","Required":false}],"Example":{"activate":["cloud_get_ping"],"deactivate":[]}},{"Service":"tool","Name":"call-create","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.","Method":"POST","Path":"/v1/tool/call","Args":[],"Flags":[{"Name":"arguments","Field":"arguments","Type":"json","Help":"Arguments is the tool's own input object, passed through verbatim to\nwhichever source owns it.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the tool to run, exactly as GET /v1/tool reports it.","Required":false}],"Example":{"arguments":{"channel":"#general","text":"hi"},"name":"slack_post_message"}},{"Service":"tool","Name":"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.","Method":"GET","Path":"/v1/tool/catalog","Args":[],"Flags":[{"Name":"q","Field":"q","Type":"string","Help":"Q matches the name, title or description, case-insensitively.","Required":false},{"Name":"featured","Field":"featured","Type":"string","Help":"Featured keeps only the listings we put on the front of the shelf, and only\nwhen it is exactly the string \"true\".","Required":false},{"Name":"official","Field":"official","Type":"string","Help":"Official keeps only the vendors' OWN servers — not third-party copies of\nthem — and only when it is exactly the string \"true\".","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit bounds the page: default 50, maximum 200. A value that is not a\npositive integer reads as the default.","Required":false},{"Name":"offset","Field":"offset","Type":"integer","Help":"Offset skips that many listings.","Required":false}],"Example":null},{"Service":"tool","Name":"catalog-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.","Method":"GET","Path":"/v1/tool/catalog/:id","Args":[{"Name":"id","Help":"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\"."}],"Flags":null,"Example":null},{"Service":"tool","Name":"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.","Method":"GET","Path":"/v1/tool/kit","Args":[],"Flags":null,"Example":null},{"Service":"tool","Name":"kit-update","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.","Method":"PUT","Path":"/v1/tool/kit","Args":[],"Flags":[{"Name":"mute","Field":"mute","Type":"json","Help":"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.","Required":false},{"Name":"unmute","Field":"unmute","Type":"json","Help":"Unmute gives these back, as far as the org's kit carries them.","Required":false}],"Example":{"mute":["skill_deploy","linear"],"unmute":[]}},{"Service":"tool","Name":"list","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.","Method":"GET","Path":"/v1/tool","Args":[],"Flags":[{"Name":"source","Field":"source","Type":"string","Help":"Source keeps only tools from one source — connector, function, zap-service,\nagent, skill or mcp. Empty keeps every source.","Required":false},{"Name":"activated","Field":"activated","Type":"string","Help":"Activated keeps only the tools activated for the caller's org and project,\nand only when it is exactly the string \"true\".","Required":false}],"Example":null},{"Service":"tool","Name":"mcp-servers-create","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.","Method":"POST","Path":"/v1/tool/mcp/servers","Args":[],"Flags":[{"Name":"auth-header","Field":"authHeader","Type":"string","Help":"AuthHeader is the request header the credential is injected into, e.g.\n\"Authorization\". Empty means the server needs no credential.","Required":false},{"Name":"listing","Field":"listing","Type":"string","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name labels the server for the org. Required with URL; with Listing it\ndefaults to the listing's own title.","Required":false},{"Name":"secret","Field":"secret","Type":"string","Help":"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.","Required":false},{"Name":"url","Field":"url","Type":"string","Help":"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.","Required":false}],"Example":{"authHeader":"Authorization","listing":"com.stripe_mcp","secret":"Bearer …"}},{"Service":"tool","Name":"mcp-servers-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.","Method":"DELETE","Path":"/v1/tool/mcp/servers/:id","Args":[{"Name":"id","Help":"ID is the server to deregister, from the path."}],"Flags":null,"Example":null},{"Service":"tool","Name":"mcp-servers-list","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.","Method":"GET","Path":"/v1/tool/mcp/servers","Args":[],"Flags":null,"Example":null},{"Service":"tool","Name":"plugins-authored-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.","Method":"DELETE","Path":"/v1/tool/plugins/authored/:id","Args":[{"Name":"id","Help":"ID is the plugin to remove, from the path."}],"Flags":null,"Example":null},{"Service":"tool","Name":"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.","Method":"GET","Path":"/v1/tool/plugins/authored","Args":[],"Flags":null,"Example":null},{"Service":"tool","Name":"plugins-build-create","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.","Method":"POST","Path":"/v1/tool/plugins/build","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"Name is the plugin's name: one lowercase path segment (a-z0-9, _ or -),\nand the id the runtime loads it by.","Required":false},{"Name":"provider","Field":"provider","Type":"string","Help":"Provider is the connectors provider whose credential the plugin reads at\nrun time. Empty for a plugin that needs none.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source is TypeScript to build as-is. Exactly one of Source or Spec.","Required":false},{"Name":"spec","Field":"spec","Type":"string","Help":"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.","Required":false}],"Example":{"name":"acme","provider":"acme","spec":"POST /v1/things creates a thing"}},{"Service":"tool","Name":"plugins-list","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.","Method":"GET","Path":"/v1/tool/plugins","Args":[],"Flags":[{"Name":"all","Field":"all","Type":"string","Help":"All includes the configured-but-disabled subsystems too, but only when it is\nexactly the string \"true\". Otherwise only the running ones are reported.","Required":false}],"Example":null},{"Service":"tool","Name":"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.","Method":"GET","Path":"/v1/tool/skills/authored","Args":[],"Flags":null,"Example":null},{"Service":"tool","Name":"skills-create","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.","Method":"POST","Path":"/v1/tool/skills","Args":[],"Flags":[{"Name":"content","Field":"content","Type":"string","Help":"Content is the SKILL.md body. Required, at most 256 KiB.","Required":false},{"Name":"description","Field":"description","Type":"string","Help":"Description is the one-line summary discovery shows for the skill.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"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.","Required":false}],"Example":{"content":"# Triage\n…","description":"how we triage","name":"triage"}},{"Service":"tool","Name":"skills-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.","Method":"DELETE","Path":"/v1/tool/skills/:id","Args":[{"Name":"id","Help":"ID is the skill to remove, from the path. It is the skill's name."}],"Flags":null,"Example":null},{"Service":"tool","Name":"skills-list","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.","Method":"GET","Path":"/v1/tool/skills","Args":[],"Flags":[{"Name":"activated","Field":"activated","Type":"string","Help":"Activated keeps only the tools activated for the caller's org and project,\nand only when it is exactly the string \"true\".","Required":false}],"Example":null},{"Service":"train","Name":"artifacts-create","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.","Method":"POST","Path":"/v1/train/artifacts","Args":[],"Flags":[{"Name":"kind","Field":"kind","Type":"string","Help":"Kind is dataset: JSON Lines rows a job reads as `artifact:\u003csha256\u003e`.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name labels it.","Required":false},{"Name":"sha256","Field":"sha256","Type":"string","Help":"SHA256 is the hex digest of the bytes.","Required":false},{"Name":"size","Field":"size","Type":"integer","Help":"Size is the byte count.","Required":false}],"Example":{"kind":"dataset","name":"tickets","sha256":"…","size":1048576}},{"Service":"train","Name":"artifacts-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.","Method":"DELETE","Path":"/v1/train/artifacts/:sha256","Args":[{"Name":"sha256","Help":"SHA256 names the object, from the path."}],"Flags":null,"Example":null},{"Service":"train","Name":"artifacts-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.","Method":"GET","Path":"/v1/train/artifacts/:sha256","Args":[{"Name":"sha256","Help":"SHA256 names the object, from the path."}],"Flags":null,"Example":null},{"Service":"train","Name":"artifacts-list","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.","Method":"GET","Path":"/v1/train/artifacts","Args":[],"Flags":null,"Example":null},{"Service":"train","Name":"clients-create","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.","Method":"POST","Path":"/v1/train/clients","Args":[],"Flags":[{"Name":"adaptation","Field":"adaptation","Type":"json","Help":"Adaptation is lora, the one mode clients run; its shape is lora_config.","Required":false},{"Name":"base-model","Field":"base_model","Type":"string","Help":"BaseModel is a model the engine loads: a Hugging Face repo id or a local path.","Required":false},{"Name":"lora-config","Field":"lora_config","Type":"json","Help":"LoraConfig is the adapter's shape, as the engine's wire takes it.","Required":false},{"Name":"protect","Field":"protect","Type":"json","Help":"Protect is refused: clients protect nothing yet.","Required":false}],"Example":{"base_model":"HuggingFaceTB/SmolLM2-135M","lora_config":{"alpha":32,"rank":16}}},{"Service":"train","Name":"clients-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.","Method":"DELETE","Path":"/v1/train/clients/:id","Args":[{"Name":"id","Help":"ID names the client."}],"Flags":null,"Example":null},{"Service":"train","Name":"clients-forward-backward","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.","Method":"POST","Path":"/v1/train/clients/:id/forward_backward","Args":[{"Name":"id","Help":"ID names the client."}],"Flags":[{"Name":"data","Field":"data","Type":"json","Help":"Data are the examples: {prompt, completion} text, or tokenized datums.","Required":false}],"Example":{"data":[{"completion":"4","prompt":"2+2="}],"id":"tc-…"}},{"Service":"train","Name":"clients-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.","Method":"GET","Path":"/v1/train/clients/:id","Args":[{"Name":"id","Help":"ID names the client."}],"Flags":null,"Example":null},{"Service":"train","Name":"clients-list","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.","Method":"GET","Path":"/v1/train/clients","Args":[],"Flags":null,"Example":null},{"Service":"train","Name":"clients-optim-step","OperationID":"post_train_clients_by_id_optim_step","Summary":"Applies the optimizer to the accumulated gradients.","Description":"Applies the optimizer to the accumulated gradients.","Method":"POST","Path":"/v1/train/clients/:id/optim_step","Args":[{"Name":"id","Help":"ID names the client."}],"Flags":[{"Name":"adam-params","Field":"adam_params","Type":"json","Help":"AdamParams are the optimizer's parameters for this step.","Required":false}],"Example":null},{"Service":"train","Name":"clients-sample","OperationID":"post_train_clients_by_id_sample","Summary":"Decodes from the client's current weights.","Description":"Decodes from the client's current weights.","Method":"POST","Path":"/v1/train/clients/:id/sample","Args":[{"Name":"id","Help":"ID names the client."}],"Flags":[{"Name":"num-samples","Field":"num_samples","Type":"integer","Help":"NumSamples is how many sequences to decode.","Required":false},{"Name":"prompt","Field":"prompt","Type":"string","Help":"Prompt is a text prompt; exactly one of prompt and tokens.","Required":false},{"Name":"sampling-params","Field":"sampling_params","Type":"json","Help":"SamplingParams are the decoding parameters.","Required":false},{"Name":"tokens","Field":"tokens","Type":"json","Help":"Tokens is a tokenized prompt.","Required":false}],"Example":null},{"Service":"train","Name":"clients-save-weights","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.","Method":"POST","Path":"/v1/train/clients/:id/save_weights","Args":[{"Name":"id","Help":"ID names the client."}],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"Name is the adapter's name.","Required":false},{"Name":"output","Field":"output","Type":"json","Help":"Output is lora, the one kind a client writes.","Required":false}],"Example":null},{"Service":"train","Name":"jobs-artifacts","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.","Method":"POST","Path":"/v1/train/jobs/:id/artifacts","Args":[{"Name":"id","Help":"ID names the job, from the path."}],"Flags":[{"Name":"kind","Field":"kind","Type":"string","Help":"Kind is checkpoint, lora, capability, basis or merged.","Required":false},{"Name":"lease","Field":"lease","Type":"string","Help":"Lease is the task's lease.","Required":false},{"Name":"meta","Field":"meta","Type":"json","Help":"Meta describes it: its base and revision, its modules, a basis's address.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name labels it.","Required":false},{"Name":"sha256","Field":"sha256","Type":"string","Help":"SHA256 is the hex digest of the bytes.","Required":false},{"Name":"size","Field":"size","Type":"integer","Help":"Size is the byte count.","Required":false},{"Name":"task","Field":"task","Type":"string","Help":"Task is the reporting task.","Required":false}],"Example":{"id":"job_0123456789abcdef","kind":"capability","lease":"trl_…","name":"open-labels","sha256":"…","size":1048576,"task":"tsk_0123456789abcdef"}},{"Service":"train","Name":"jobs-artifacts-list","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.","Method":"GET","Path":"/v1/train/jobs/:id/artifacts","Args":[{"Name":"id","Help":"ID names the job."}],"Flags":null,"Example":null},{"Service":"train","Name":"jobs-cancel","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.","Method":"POST","Path":"/v1/train/jobs/:id/cancel","Args":[{"Name":"id","Help":"ID names the job."}],"Flags":null,"Example":null},{"Service":"train","Name":"jobs-claim-create","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.","Method":"POST","Path":"/v1/train/jobs/claim","Args":[],"Flags":[{"Name":"bases","Field":"bases","Type":"json","Help":"Bases are the base models its trainer runs.","Required":false},{"Name":"devices","Field":"devices","Type":"json","Help":"Devices are its accelerators, one entry per device: cuda, rocm, metal,\nvulkan, cpu. A task runs on those of one kind its job allows.","Required":false},{"Name":"machine","Field":"machine","Type":"string","Help":"Machine is the machine claiming, by name: one of the org's linked machines,\nor for a platform claim the Hanzo host.","Required":false},{"Name":"platform","Field":"platform","Type":"boolean","Help":"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.","Required":false},{"Name":"supports","Field":"supports","Type":"json","Help":"Supports is what its build runs.","Required":false}],"Example":{"bases":["kai"],"devices":["cuda"],"machine":"dgx","supports":{"adaptations":["full","readout"],"outputs":["capability","checkpoint"],"protect":["projection","distillation"],"terms":["pairwise_margin","hard_margin","consistency"]}}},{"Service":"train","Name":"jobs-create","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.","Method":"POST","Path":"/v1/train/jobs","Args":[],"Flags":[{"Name":"adaptation","Field":"adaptation","Type":"json","Help":"Adaptation is how the update is parameterized.","Required":false},{"Name":"base-model","Field":"base_model","Type":"string","Help":"BaseModel is the base the capability is taught to: `kai`, or a model the engine\nloads for a client.","Required":false},{"Name":"dataset","Field":"dataset","Type":"json","Help":"Dataset is what the job trains on.","Required":false},{"Name":"evaluation","Field":"evaluation","Type":"json","Help":"Evaluation names the target suites the result reports.","Required":false},{"Name":"from","Field":"from","Type":"string","Help":"From is an artifact the job starts from, by sha256.","Required":false},{"Name":"objective","Field":"objective","Type":"json","Help":"Objective is the loss and the terms beside it.","Required":false},{"Name":"output","Field":"output","Type":"json","Help":"Output is what the job produces.","Required":false},{"Name":"protect","Field":"protect","Type":"json","Help":"Protect names what the base already does that must hold, and the budget.","Required":false},{"Name":"resources","Field":"resources","Type":"json","Help":"Resources places and bounds the run.","Required":false},{"Name":"revision","Field":"revision","Type":"string","Help":"Revision pins the base. For kai: a finished run's name on the executor, or\n`hub:\u003crepo\u003e@\u003crev\u003e`.","Required":false}],"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"}},{"Service":"train","Name":"jobs-events","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.","Method":"POST","Path":"/v1/train/jobs/:id/events","Args":[{"Name":"id","Help":"ID names the job, from the path."}],"Flags":[{"Name":"events","Field":"events","Type":"json","Help":"Events are the task's new events, in order.","Required":false},{"Name":"lease","Field":"lease","Type":"string","Help":"Lease is the task's lease, as the claim answered it.","Required":false},{"Name":"task","Field":"task","Type":"string","Help":"Task is the reporting task.","Required":false}],"Example":{"events":[{"name":"nll","step":100,"type":"metric","value":0.66}],"id":"job_0123456789abcdef","lease":"trl_…","task":"tsk_0123456789abcdef"}},{"Service":"train","Name":"jobs-events-list","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.","Method":"GET","Path":"/v1/train/jobs/:id/events","Args":[{"Name":"id","Help":"ID names the job."}],"Flags":[{"Name":"after","Field":"after","Type":"integer","Help":"After is the last seq the caller holds; 0 reads from the start.","Required":false},{"Name":"wait","Field":"wait","Type":"integer","Help":"Wait is how many seconds to hold the request for a first new event, at most 25.","Required":false}],"Example":null},{"Service":"train","Name":"jobs-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.","Method":"GET","Path":"/v1/train/jobs/:id","Args":[{"Name":"id","Help":"ID names the job."}],"Flags":null,"Example":null},{"Service":"train","Name":"jobs-list","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=.","Method":"GET","Path":"/v1/train/jobs","Args":[],"Flags":[{"Name":"status","Field":"status","Type":"string","Help":"Status narrows to one status.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit bounds the answer; default 50, at most 500.","Required":false}],"Example":null},{"Service":"train","Name":"jobs-metrics-list","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].","Method":"GET","Path":"/v1/train/jobs/:id/metrics","Args":[{"Name":"id","Help":"ID names the job."}],"Flags":null,"Example":null},{"Service":"train","Name":"jobs-publish","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.","Method":"POST","Path":"/v1/train/jobs/:id/publish","Args":[{"Name":"id","Help":"ID names the job."}],"Flags":[{"Name":"force","Field":"force","Type":"boolean","Help":"Force publishes a rejected job's output, and is recorded.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the published name; the output's name when absent. Publishing a\nname the org already published replaces that capability.","Required":false},{"Name":"route","Field":"route","Type":"json","Help":"Route is which questions the capability answers: required to publish a\ncapability, refused for any other output.","Required":false}],"Example":{"id":"job_0123456789abcdef","name":"triage","route":{"keys":["topic"],"options":{"topic":{"labels":["billing","bug","other"],"type":"choice"}}}}},{"Service":"train","Name":"models-list","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.","Method":"GET","Path":"/v1/train/models","Args":[],"Flags":null,"Example":null},{"Service":"translate","Name":"create","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).","Method":"POST","Path":"/v1/translate","Args":[],"Flags":[{"Name":"batch","Field":"batch","Type":"json","Help":"","Required":false},{"Name":"format","Field":"format","Type":"string","Help":"","Required":false},{"Name":"glossary","Field":"glossary","Type":"json","Help":"","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"","Required":false},{"Name":"target","Field":"target","Type":"string","Help":"","Required":true},{"Name":"text","Field":"text","Type":"string","Help":"","Required":false},{"Name":"tier","Field":"tier","Type":"string","Help":"","Required":false}],"Example":null},{"Service":"translate","Name":"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.","Method":"GET","Path":"/v1/translate/memory","Args":[],"Flags":[{"Name":"target","Field":"target","Type":"string","Help":"Target narrows to one target language tag (BCP-47, e.g. \"es\" or \"pt-BR\").","Required":false},{"Name":"state","Field":"state","Type":"string","Help":"State narrows to one position on the review ladder: machine, suggested,\napproved or published.","Required":false},{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps the rows returned. Non-positive or unparseable means the server\ndefault (200); the ceiling is 1000.","Required":false}],"Example":null},{"Service":"translate","Name":"memory-update","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.","Method":"PUT","Path":"/v1/translate/memory","Args":[],"Flags":[{"Name":"format","Field":"format","Type":"string","Help":"Format is the markup the source carries: text (the default), html or markdown.\nPart of the entry's identity.","Required":false},{"Name":"glossary","Field":"glossary","Type":"json","Help":"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.","Required":false},{"Name":"lang","Field":"lang","Type":"string","Help":"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.","Required":false},{"Name":"model","Field":"model","Type":"string","Help":"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.","Required":false},{"Name":"source","Field":"source","Type":"string","Help":"Source is the ORIGINAL string this entry translates. Required; part of the\nentry's identity, so a different source is a different entry.","Required":false},{"Name":"state","Field":"state","Type":"string","Help":"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.","Required":false},{"Name":"target","Field":"target","Type":"string","Help":"Target is the target language tag (BCP-47, e.g. \"es\" or \"pt-BR\"). Required;\npart of the entry's identity.","Required":false},{"Name":"text","Field":"text","Type":"string","Help":"Text is the reviewed translation to store. A human write always wins over the\nstored value.","Required":false},{"Name":"tier","Field":"tier","Type":"string","Help":"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.","Required":false}],"Example":{"source":"Hello","state":"approved","target":"es","text":"Hola"}},{"Service":"treasury","Name":"accounts-list","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.","Method":"GET","Path":"/v1/treasury/accounts","Args":[],"Flags":[{"Name":"scope","Field":"scope","Type":"string","Help":"Scope is \"house\" to read the reserve/revenue/payout house accounts. SuperAdmin only.","Required":false},{"Name":"org","Field":"org","Type":"string","Help":"Org names another tenant to read. SuperAdmin only; ignored when scope=house.","Required":false}],"Example":null},{"Service":"treasury","Name":"list","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.","Method":"GET","Path":"/v1/treasury","Args":[],"Flags":null,"Example":null},{"Service":"trust","Name":"controls-get","OperationID":"get_trust_controls_by_id","Summary":"Reads one control by id.","Description":"Reads one control by id.","Method":"GET","Path":"/v1/trust/controls/:id","Args":[{"Name":"id","Help":"ID is the control's id, dotted lowercase — \"iam.pkce.s256\"."}],"Flags":null,"Example":{"id":"iam.pkce.s256"}},{"Service":"trust","Name":"controls-list","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.","Method":"GET","Path":"/v1/trust/controls","Args":[],"Flags":null,"Example":null},{"Service":"trust","Name":"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.","Method":"GET","Path":"/v1/trust/coverage","Args":[],"Flags":null,"Example":null},{"Service":"trust","Name":"coverage-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.","Method":"GET","Path":"/v1/trust/coverage/:framework","Args":[{"Name":"framework","Help":"Framework is the framework id — \"soc2\", \"iso27001\", \"nist80053\"."}],"Flags":null,"Example":{"framework":"soc2"}},{"Service":"trust","Name":"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.","Method":"DELETE","Path":"/v1/trust/:kind/:id","Args":[{"Name":"kind","Help":"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."},{"Name":"id","Help":"ID is the record's id within that section. The single-valued sections\n(profile, risk) hold one record whatever id is named."}],"Flags":null,"Example":{"id":"where-is-data-held","kind":"faq"}},{"Service":"trust","Name":"documents-list","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.","Method":"GET","Path":"/v1/trust/documents","Args":[],"Flags":null,"Example":null},{"Service":"trust","Name":"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.","Method":"GET","Path":"/v1/trust/evidence","Args":[],"Flags":[{"Name":"control","Field":"control","Type":"string","Help":"Control is the control id whose trail to read. Required.","Required":false},{"Name":"from","Field":"from","Type":"string","Help":"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.","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"To is the upper bound, same form and same tolerance.","Required":false},{"Name":"limit","Field":"limit","Type":"string","Help":"Limit caps the rows returned, 1..1000, default 100. It is a string because\nan unparseable value is refused rather than read as zero.","Required":false}],"Example":{"control":"iam.refresh.rotation","from":"2026-01-01","limit":"50"}},{"Service":"trust","Name":"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.","Method":"GET","Path":"/v1/trust/faq","Args":[],"Flags":null,"Example":null},{"Service":"trust","Name":"frameworks-list","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.","Method":"GET","Path":"/v1/trust/frameworks","Args":[],"Flags":null,"Example":null},{"Service":"trust","Name":"list","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.","Method":"GET","Path":"/v1/trust","Args":[],"Flags":null,"Example":null},{"Service":"trust","Name":"policies-list","OperationID":"get_trust_policies","Summary":"Lists your organization's published policies.","Description":"Lists your organization's published policies.","Method":"GET","Path":"/v1/trust/policies","Args":[],"Flags":null,"Example":null},{"Service":"trust","Name":"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.","Method":"GET","Path":"/v1/trust/profile","Args":[],"Flags":null,"Example":null},{"Service":"trust","Name":"published-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.","Method":"GET","Path":"/v1/trust/published/:org","Args":[{"Name":"org","Help":"Org is the organization's slug — the name in its address."}],"Flags":null,"Example":{"org":"hanzo"}},{"Service":"trust","Name":"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.","Method":"GET","Path":"/v1/trust/risk","Args":[],"Flags":null,"Example":null},{"Service":"trust","Name":"subprocessors-list","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.","Method":"GET","Path":"/v1/trust/subprocessors","Args":[],"Flags":null,"Example":null},{"Service":"trust","Name":"update","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.","Method":"PUT","Path":"/v1/trust/:kind/:id","Args":[{"Name":"kind","Help":"Kind is the section being written. The URL is the authority."},{"Name":"id","Help":"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."}],"Flags":[{"Name":"data","Field":"data","Type":"json","Help":"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.","Required":false},{"Name":"ord","Field":"ord","Type":"integer","Help":"Ord orders this record within its section, ascending, ties broken by id.\nIt is the organization's own ordering — the page renders in it.","Required":false}],"Example":{"data":{"name":"A cloud","purpose":"Compute"},"id":"acme-cloud","kind":"subprocessor"}},{"Service":"trust","Name":"updates-list","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.","Method":"GET","Path":"/v1/trust/updates","Args":[],"Flags":null,"Example":null},{"Service":"usage","Name":"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.","Method":"GET","Path":"/v1/usage/analytics/access","Args":[],"Flags":[{"Name":"plan","Field":"plan","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"usage","Name":"analytics-list","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.","Method":"GET","Path":"/v1/usage/analytics","Args":[],"Flags":[{"Name":"end","Field":"end","Type":"string","Help":"End is the exclusive window end, RFC3339. Read only when Range is custom.","Required":false},{"Name":"plan","Field":"plan","Type":"string","Help":"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.","Required":false},{"Name":"range","Field":"range","Type":"string","Help":"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.","Required":false},{"Name":"start","Field":"start","Type":"string","Help":"Start is the inclusive window start, RFC3339. Read only when Range is\ncustom, and clamped forward to the plan's retention floor.","Required":false}],"Example":null},{"Service":"usage","Name":"create","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.","Method":"POST","Path":"/v1/usage","Args":[],"Flags":[{"Name":"account","Field":"account","Type":"string","Help":"Account is the linked account the window was metered from.","Required":false},{"Name":"cached-input-tokens","Field":"cachedInputTokens","Type":"integer","Help":"CachedInputTokens is the prompt tokens the provider served from cache.","Required":false},{"Name":"confidence","Field":"confidence","Type":"string","Help":"Confidence says how much the counters below mean.","Required":false},{"Name":"cost-cents","Field":"costCents","Type":"integer","Help":"CostCents is what the window cost on the PROVIDER's own plan, in US cents.","Required":false},{"Name":"cost-limit-cents","Field":"costLimitCents","Type":"integer","Help":"CostLimitCents is the plan's spend ceiling for the window, in US cents.","Required":false},{"Name":"currency","Field":"currency","Type":"string","Help":"Currency is the provider's currency when it is not US cents.","Required":false},{"Name":"input-tokens","Field":"inputTokens","Type":"integer","Help":"InputTokens is prompt tokens consumed in the window.","Required":false},{"Name":"kind","Field":"kind","Type":"string","Help":"Kind is subscription or apikey. Empty is accepted; anything else is\nrefused.","Required":false},{"Name":"lane","Field":"lane","Type":"string","Help":"Lane is the meter lane within the account.","Required":false},{"Name":"machine","Field":"machine","Type":"string","Help":"Machine is the host whose meter read the window. Required on every sample.","Required":false},{"Name":"output-tokens","Field":"outputTokens","Type":"integer","Help":"OutputTokens is completion tokens produced in the window.","Required":false},{"Name":"plan","Field":"plan","Type":"string","Help":"Plan is the subscription plan the account is on, as the provider names it.","Required":false},{"Name":"provider","Field":"provider","Type":"string","Help":"Provider is the upstream the account belongs to, e.g. anthropic. Required\non every sample.","Required":false},{"Name":"requests","Field":"requests","Type":"integer","Help":"Requests is how many requests the window covers.","Required":false},{"Name":"resets-at","Field":"resetsAt","Type":"string","Help":"ResetsAt is when the measured window rolls over, RFC3339.","Required":false},{"Name":"samples","Field":"samples","Type":"json","Help":"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.","Required":false},{"Name":"synthetic","Field":"synthetic","Type":"boolean","Help":"Synthetic marks a window the meter inferred rather than read.","Required":false},{"Name":"total-tokens","Field":"totalTokens","Type":"integer","Help":"TotalTokens is the window's total tokens.","Required":false},{"Name":"used-pct","Field":"usedPct","Type":"number","Help":"UsedPct is how much of the window's allowance is consumed, 0–100.","Required":false},{"Name":"window","Field":"window","Type":"string","Help":"Window is the window class: 6h, day, week or month. Required, and a class\nthis surface does not know is refused rather than rewritten.","Required":false},{"Name":"window-minutes","Field":"windowMinutes","Type":"integer","Help":"WindowMinutes is the window's real length in minutes, as the meter reports\nit.","Required":false},{"Name":"window-start","Field":"windowStart","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"usage","Name":"samples-list","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.","Method":"GET","Path":"/v1/usage/samples","Args":[],"Flags":[{"Name":"account","Field":"account","Type":"string","Help":"Account narrows to ONE linked account of that provider. Empty covers every\naccount the caller has linked there.","Required":false},{"Name":"provider","Field":"provider","Type":"string","Help":"Provider is the upstream to read, e.g. anthropic. Required.","Required":false},{"Name":"range","Field":"range","Type":"string","Help":"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.","Required":false},{"Name":"window","Field":"window","Type":"string","Help":"Window narrows to ONE window class: 6h, day, week or month. Empty covers\nevery class.","Required":false}],"Example":null},{"Service":"usage","Name":"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.","Method":"GET","Path":"/v1/usage/summary","Args":[],"Flags":[{"Name":"range","Field":"range","Type":"string","Help":"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.","Required":false},{"Name":"start","Field":"start","Type":"string","Help":"Start is the inclusive window start, RFC3339. Read only when Range is\ncustom.","Required":false},{"Name":"end","Field":"end","Type":"string","Help":"End is the exclusive window end, RFC3339. Read only when Range is custom.","Required":false}],"Example":null},{"Service":"validator","Name":"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.","Method":"GET","Path":"/v1/validator/challenge","Args":[],"Flags":[{"Name":"token-id","Field":"tokenId","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"validator","Name":"create","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\".","Method":"POST","Path":"/v1/validator","Args":[],"Flags":[{"Name":"nonce","Field":"nonce","Type":"string","Help":"Nonce is the value GET /v1/validator/challenge issued for this slot.","Required":false},{"Name":"signature","Field":"signature","Type":"string","Help":"Signature is the wallet's personal_sign over the challenge message, hex with\na 0x prefix.","Required":false},{"Name":"token-id","Field":"tokenId","Type":"integer","Help":"TokenID is the Validator-tier GenesisNFT token id being claimed. It IS the\nvalidator slot.","Required":false}],"Example":{"nonce":"5f3a…","signature":"0x…","tokenId":7}},{"Service":"validator","Name":"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.","Method":"GET","Path":"/v1/validator/:tokenId","Args":[{"Name":"tokenId","Help":"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."}],"Flags":null,"Example":null},{"Service":"validator","Name":"list","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.","Method":"GET","Path":"/v1/validator","Args":[],"Flags":[{"Name":"limit","Field":"limit","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"videos","Name":"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.","Method":"GET","Path":"/v1/videos/:id/content","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"videos","Name":"generations-create","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.","Method":"POST","Path":"/v1/videos/generations","Args":[],"Flags":null,"Example":null},{"Service":"videos","Name":"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.","Method":"GET","Path":"/v1/videos/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":null},{"Service":"wallet","Name":"accounts-create","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.","Method":"POST","Path":"/v1/wallet/accounts","Args":[],"Flags":[{"Name":"name","Field":"name","Type":"string","Help":"Name is the account's label. Required, trimmed; it groups wallets and is\nnot itself a key.","Required":false}],"Example":{"name":"treasury"}},{"Service":"wallet","Name":"accounts-list","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.","Method":"GET","Path":"/v1/wallet/accounts","Args":[],"Flags":null,"Example":null},{"Service":"wallet","Name":"create","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.","Method":"POST","Path":"/v1/wallet","Args":[],"Flags":[{"Name":"account-id","Field":"accountId","Type":"string","Help":"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.","Required":false},{"Name":"agent","Field":"agent","Type":"string","Help":"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.","Required":false},{"Name":"chain","Field":"chain","Type":"string","Help":"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).","Required":false},{"Name":"custody","Field":"custody","Type":"string","Help":"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.","Required":false},{"Name":"name","Field":"name","Type":"string","Help":"Name is the wallet's display label. Optional.","Required":false},{"Name":"tier","Field":"tier","Type":"string","Help":"Tier is the MPC wallet tier: hot, warm, cold, gas, bridge, contract_admin,\nvalidator, quarantine or disaster_recovery. Empty defaults to hot.","Required":false}],"Example":{"accountId":"acct_9f8c1d","chain":"eip155:36963","custody":"kms","name":"ops hot wallet","tier":"hot"}},{"Service":"wallet","Name":"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.","Method":"GET","Path":"/v1/wallet/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":{"id":"wal_4b1e77"}},{"Service":"wallet","Name":"keys","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.","Method":"POST","Path":"/v1/wallet/:id/keys","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":{"id":"wal_4b1e77"}},{"Service":"wallet","Name":"list","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.","Method":"GET","Path":"/v1/wallet","Args":[],"Flags":[{"Name":"project","Field":"project","Type":"string","Help":"Project narrows to wallets scoped to one project. Must be a url-safe segment.","Required":false},{"Name":"agent","Field":"agent","Type":"string","Help":"Agent narrows to wallets scoped to one agent. Must be a url-safe segment.","Required":false},{"Name":"account","Field":"account","Type":"string","Help":"Account narrows to wallets under one account id. Must be a url-safe segment.","Required":false}],"Example":{"account":"acct_9f8c1d"}},{"Service":"wallet","Name":"sign","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.","Method":"POST","Path":"/v1/wallet/:id/sign","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"digest","Field":"digest","Type":"string","Help":"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.","Required":false},{"Name":"message","Field":"message","Type":"string","Help":"Message is arbitrary text to hash with Keccak256 and sign. Used only when\ndigest is empty.","Required":false}],"Example":{"id":"wal_4b1e77","message":"approve withdrawal 42"}},{"Service":"wallet","Name":"transactions","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.","Method":"POST","Path":"/v1/wallet/:id/transactions","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"chain-id","Field":"chainId","Type":"integer","Help":"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.","Required":false},{"Name":"data","Field":"data","Type":"string","Help":"Data is the call data, hex-encoded.","Required":false},{"Name":"nonce","Field":"nonce","Type":"integer","Help":"Nonce is the Safe's transaction nonce.","Required":false},{"Name":"to","Field":"to","Type":"string","Help":"To is the transaction's target address.","Required":false},{"Name":"value","Field":"value","Type":"string","Help":"Value is the native-token amount to send, as a decimal string in wei.","Required":false}],"Example":{"chainId":36963,"data":"0x","id":"wal_4b1e77","nonce":7,"to":"0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984","value":"0"}},{"Service":"web3","Name":"chains-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.","Method":"GET","Path":"/v1/web3/chains/:chain","Args":[{"Name":"chain","Help":"Chain is the registry id, as in /v1/web3/chains/lux."}],"Flags":null,"Example":null},{"Service":"web3","Name":"chains-list","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.","Method":"GET","Path":"/v1/web3/chains","Args":[],"Flags":null,"Example":null},{"Service":"web3","Name":"rpc-create","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.","Method":"POST","Path":"/v1/web3/rpc/:chain","Args":[{"Name":"chain","Help":"Chain is the registry id, from the URL."}],"Flags":[{"Name":"id","Field":"id","Type":"json","Help":"ID is echoed back untouched.","Required":false},{"Name":"jsonrpc","Field":"jsonrpc","Type":"string","Help":"JSONRPC must be \"2.0\" when present.","Required":false},{"Name":"method","Field":"method","Type":"string","Help":"Method is the RPC method, e.g. eth_getBalance.","Required":false},{"Name":"params","Field":"params","Type":"json","Help":"Params is the method's parameters, passed through unread.","Required":false}],"Example":null},{"Service":"web3","Name":"tokens-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.","Method":"GET","Path":"/v1/web3/tokens/:chain/:address","Args":[{"Name":"chain","Help":"Chain is the registry id."},{"Name":"address","Help":"Address is the account, 0x-prefixed."}],"Flags":null,"Example":null},{"Service":"webhook","Name":"create","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.","Method":"POST","Path":"/v1/webhook","Args":[],"Flags":[{"Name":"description","Field":"description","Type":"string","Help":"Description is a free-text label for the console. Optional, clipped to 1024 bytes.","Required":false},{"Name":"events","Field":"events","Type":"json","Help":"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.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"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.","Required":false},{"Name":"url","Field":"url","Type":"string","Help":"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.","Required":false}],"Example":{"description":"order pipeline","events":["commerce.order.\u003e"],"url":"https://acme.example/hooks/hanzo"}},{"Service":"webhook","Name":"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.","Method":"DELETE","Path":"/v1/webhook/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":{"id":"wh_9f8c1d2e"}},{"Service":"webhook","Name":"deliveries-list","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.","Method":"GET","Path":"/v1/webhook/:id/deliveries","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"limit","Field":"limit","Type":"integer","Help":"Limit caps how many attempts come back: default 50, maximum 200. A value\nthat is not a positive integer reads as the default.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status narrows the log to one outcome: \"ok\", \"retrying\" or \"failed\".\nEmpty returns every attempt.","Required":false}],"Example":{"id":"wh_9f8c1d2e","limit":100,"status":"failed"}},{"Service":"webhook","Name":"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.","Method":"GET","Path":"/v1/webhook/:id","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":{"id":"wh_9f8c1d2e"}},{"Service":"webhook","Name":"list","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.","Method":"GET","Path":"/v1/webhook","Args":[],"Flags":null,"Example":null},{"Service":"webhook","Name":"secret","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.","Method":"POST","Path":"/v1/webhook/:id/secret","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":{"id":"wh_9f8c1d2e"}},{"Service":"webhook","Name":"test","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.","Method":"POST","Path":"/v1/webhook/:id/test","Args":[{"Name":"id","Help":""}],"Flags":null,"Example":{"id":"wh_9f8c1d2e"}},{"Service":"webhook","Name":"update","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.","Method":"PUT","Path":"/v1/webhook/:id","Args":[{"Name":"id","Help":""}],"Flags":[{"Name":"description","Field":"description","Type":"string","Help":"Description is a free-text label for the console. Optional, clipped to 1024 bytes.","Required":false},{"Name":"events","Field":"events","Type":"json","Help":"Events are NATS subject patterns to subscribe to. An empty or omitted list\nmeans EVERY event. Max 64 patterns, each max 256 bytes.","Required":false},{"Name":"status","Field":"status","Type":"string","Help":"Status is \"active\" or \"disabled\". Empty defaults to active.","Required":false},{"Name":"url","Field":"url","Type":"string","Help":"URL is the https:// address each matching event is POSTed to. Required,\nmax 2048 bytes; http:// and every other scheme is refused.","Required":false}],"Example":{"events":["commerce.order.paid"],"id":"wh_9f8c1d2e","status":"disabled","url":"https://acme.example/hooks/v2"}},{"Service":"websearch","Name":"delete-search-engine-key","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.","Method":"DELETE","Path":"/v1/websearch/engines/:name/key","Args":[{"Name":"name","Help":"Name is the engine, from the path."}],"Flags":null,"Example":null},{"Service":"websearch","Name":"list-search-engines","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.","Method":"GET","Path":"/v1/websearch/engines","Args":[],"Flags":null,"Example":null},{"Service":"websearch","Name":"scrape-create","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.","Method":"POST","Path":"/v1/websearch/scrape","Args":[],"Flags":null,"Example":null},{"Service":"websearch","Name":"search-create","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.","Method":"POST","Path":"/v1/websearch/search","Args":[],"Flags":null,"Example":null},{"Service":"websearch","Name":"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.","Method":"DELETE","Path":"/v1/websearch/search","Args":[],"Flags":null,"Example":null},{"Service":"websearch","Name":"search-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.","Method":"GET","Path":"/v1/websearch/search","Args":[],"Flags":null,"Example":null},{"Service":"websearch","Name":"search-update","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.","Method":"PATCH","Path":"/v1/websearch/search","Args":[],"Flags":null,"Example":null},{"Service":"websearch","Name":"search-update","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.","Method":"PUT","Path":"/v1/websearch/search","Args":[],"Flags":null,"Example":null},{"Service":"websearch","Name":"search-web","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.","Method":"POST","Path":"/v1/websearch","Args":[],"Flags":[{"Name":"language","Field":"language","Type":"string","Help":"Language narrows the engines to a locale, BCP-47-ish (\"en\", \"ja\", \"de\").\nEmpty means no narrowing.","Required":false},{"Name":"q","Field":"q","Type":"string","Help":"Q is the query. Required — an empty one is refused rather than answered\nwith the whole web.","Required":false}],"Example":null},{"Service":"websearch","Name":"set-search-engine-key","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.","Method":"PUT","Path":"/v1/websearch/engines/:name/key","Args":[{"Name":"name","Help":"Name is the engine, from the path."}],"Flags":[{"Name":"key","Field":"key","Type":"string","Help":"Key is the API key. Sealed in KMS and never returned, logged or echoed.\nNever read from the query string.","Required":false}],"Example":null},{"Service":"websearch","Name":"set-search-engines","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.","Method":"PUT","Path":"/v1/websearch/engines","Args":[],"Flags":[{"Name":"enabled","Field":"enabled","Type":"json","Help":"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.","Required":false},{"Name":"options","Field":"options","Type":"json","Help":"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.","Required":false}],"Example":{"enabled":["mojeek"],"options":{"mojeek":{"count":30,"language":"en","region":"GB"}}}},{"Service":"workflow","Name":"create","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.","Method":"POST","Path":"/v1/workflow","Args":[],"Flags":null,"Example":null},{"Service":"workflow","Name":"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.","Method":"DELETE","Path":"/v1/workflow","Args":[],"Flags":null,"Example":null},{"Service":"workflow","Name":"list","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.","Method":"GET","Path":"/v1/workflow","Args":[],"Flags":null,"Example":null},{"Service":"workflow","Name":"update","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.","Method":"PATCH","Path":"/v1/workflow","Args":[],"Flags":null,"Example":null},{"Service":"workflow","Name":"update","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.","Method":"PUT","Path":"/v1/workflow","Args":[],"Flags":null,"Example":null},{"Service":"world","Name":"limits-list","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.","Method":"GET","Path":"/v1/world/limits","Args":[],"Flags":[{"Name":"plan","Field":"plan","Type":"string","Help":"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.","Required":false}],"Example":null},{"Service":"world","Name":"list","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.","Method":"GET","Path":"/v1/world","Args":[],"Flags":null,"Example":null},{"Service":"world","Name":"news-list","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.","Method":"GET","Path":"/v1/world/news","Args":[],"Flags":null,"Example":null},{"Service":"world","Name":"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.","Method":"GET","Path":"/v1/world/pipeline","Args":[],"Flags":null,"Example":null},{"Service":"world","Name":"pipeline-update","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.","Method":"PUT","Path":"/v1/world/pipeline","Args":[],"Flags":[{"Name":"feeds","Field":"feeds","Type":"json","Help":"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.","Required":false},{"Name":"filters","Field":"filters","Type":"json","Help":"Filters narrows the merged feed. Terms are trimmed, de-duplicated\ncase-insensitively, and capped at 64 per axis.","Required":false}],"Example":null},{"Service":"world","Name":"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.","Method":"GET","Path":"/v1/world/stream","Args":[],"Flags":null,"Example":null},{"Service":"x402","Name":"settlements-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.","Method":"GET","Path":"/v1/x402/settlements/:id","Args":[{"Name":"id","Help":"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)."}],"Flags":null,"Example":null},{"Service":"x402","Name":"settlements-list","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.","Method":"GET","Path":"/v1/x402/settlements","Args":[],"Flags":[{"Name":"role","Field":"role","Type":"string","Help":"Role is payer — what the caller's org paid — or payee — what it was paid.\nPayer when empty.","Required":false},{"Name":"year","Field":"year","Type":"integer","Help":"Year keeps the calendar year (UTC) the payments settled in. Zero keeps\nevery year.","Required":false}],"Example":{"role":"payee","year":2026}}]