{"info":{"title":"HANK Documentation Platform API","version":"1.0.0","description":"The publish/integration REST API for the HANK documentation platform. Every endpoint requires a Hank-issued bearer token carrying the `hank-docs` scope (operator-only routes noted). Request bodies, query params, and path params are generated directly from the schemas the routes validate against, so this contract cannot drift from the implementation. Error responses are the uniform `{ \"error\": string }` envelope (with a stable machine-readable `code`). Write responses additionally carry `X-RateLimit-Limit`/`-Remaining`/`-Reset` headers: the caller's remaining write budget, for proactive pacing. Success-body object shapes are enumerated from response DTO schemas and drift-guarded against what the routes actually return."},"tags":[{"name":"me","description":"Token introspection (who am I)."},{"name":"products","description":"Product catalog."},{"name":"manuals","description":"Manuals within a product."},{"name":"chapters","description":"Chapters within a manual."},{"name":"topics","description":"Documentation topics (CRUD + the publish pipeline)."},{"name":"media","description":"Image uploads."},{"name":"changelog","description":"Product release notes."},{"name":"specs","description":"Product OpenAPI specs."},{"name":"analytics","description":"Docs-quality signals."},{"name":"tickets","description":"Per-organization support tickets."},{"name":"audit","description":"Operator-only audit trail (compliance / SIEM)."}],"paths":{"/me":{"get":{"tags":["me"],"summary":"Token introspection: the caller's OWN validated identity (audit-actor email, actor type, granted scopes, owning organization, and the admin/operator flag) plus its standing write budget (`rateLimit`, peeked; a GET spends nothing), so an integrator can pace a publish burst before it trips a 429. The first call an integrator makes to confirm a token works.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeResponse"},"example":{"email":"autocoder@hank.ai","scopes":["hank-docs"],"isAdmin":false,"actorType":"autocoder","rateLimit":{"limit":120,"remaining":118,"resetSeconds":1767312000},"organizationId":"hank"}}},"description":"The caller's own token identity."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."}}}},"/audit":{"get":{"tags":["audit"],"summary":"OPERATOR-ONLY: read the platform audit trail (compliance / SIEM). Returns a keyset page of audit entries, newest first. `actor`/`actorType` are deliberately omitted (staff-identity defense) and `metadata` is a boundary-scrubbed STRING, never the raw object. A customer token (valid `hank-docs` scope but not an operator) is 403, never a cross-tenant read. Pass `?include=digest` to additionally return each entry's `digest`/`prevDigest`/`seq` (hash-chain continuity for external anchoring); `actor`/`actorType` stay omitted regardless.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditListResponse"}}},"description":"A page of audit entries."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."}},"parameters":[{"in":"query","name":"actor","schema":{"type":"string"},"required":false,"description":"Exact-match actor (the validated email/id stamped on the row)."},{"in":"query","name":"actorType","schema":{"type":"string"},"required":false,"description":"Exact-match actor class (`admin` / `autocoder` / `system` / `mcp`)."},{"in":"query","name":"action","schema":{"type":"string"},"required":false,"description":"Exact-match dotted action (e.g. `topic.publish`)."},{"in":"query","name":"entityType","schema":{"type":"string"},"required":false,"description":"Exact-match entity kind (e.g. `topic`)."},{"in":"query","name":"entityId","schema":{"type":"string"},"required":false,"description":"Exact-match affected row id, an ENTITY-HISTORY read: everything that ever touched this one entity (pair with `entityType` when ids could collide across kinds)."},{"in":"query","name":"from","schema":{"type":"string"},"required":false,"description":"Inclusive lower bound on `created_at` (a `YYYY-MM-DD` calendar date)."},{"in":"query","name":"to","schema":{"type":"string"},"required":false,"description":"Inclusive upper bound on `created_at` (a `YYYY-MM-DD` calendar date)."},{"in":"query","name":"limit","schema":{"type":"integer","maximum":100,"minimum":1},"required":false,"description":"Page size, clamped to [1, 100]."},{"in":"query","name":"cursor","schema":{"type":"string"},"required":false,"description":"Opaque keyset cursor from a prior page."},{"in":"query","name":"include","schema":{"enum":["digest"],"type":"string"},"required":false,"description":"Set to `digest` to additionally return each entry's `digest`, `prevDigest`, and `seq` (hash-chain continuity values for external anchoring). `actor`/`actorType` remain omitted."}]}},"/media":{"post":{"tags":["media"],"summary":"Upload an image (multipart). Idempotent by `sourceUrl`. Alt text is required.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaResponse"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Existing media for this `sourceUrl`."},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaResponse"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Created media."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid file, missing alt text, or unknown product."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"File exceeds the maximum upload size."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}},"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","required":["file","alt"],"properties":{"alt":{"type":"string","description":"Required alt text (accessibility gate)."},"file":{"type":"string","format":"binary","description":"The image file."},"productId":{"type":"string","format":"uuid","description":"Optional owning product."},"sourceUrl":{"type":"string","description":"Optional idempotency key. Re-posting the same URL returns the same media."}}}}},"required":true}}},"/specs":{"get":{"tags":["specs"],"summary":"List a PRODUCT's stored spec VERSION HISTORY, newest first. Metadata only (`id`/`version`/`sourceHash`/`createdAt`), never the spec document itself. The returned `id` is the version handle `GET /specs/diff` compares by. An unknown (or non-public) product is an empty page.","responses":{"200":{"content":{"application/json":{"schema":{"type":"object","required":["items","limit","offset","total","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SpecVersionMeta"}},"limit":{"type":"integer"},"total":{"type":"integer"},"offset":{"type":"integer"},"hasMore":{"type":"boolean"}},"additionalProperties":false}}},"description":"A page of spec versions (newest first)."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing/malformed product slug or invalid pagination query."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."}},"parameters":[{"in":"query","name":"product","schema":{"type":"string"},"required":true,"description":"The owning product slug (REQUIRED; history is per-product). A malformed slug is a 400; an unknown or non-public product is an empty page."},{"in":"query","name":"limit","schema":{"type":"integer","default":20,"maximum":100,"exclusiveMinimum":0},"required":false},{"in":"query","name":"offset","schema":{"type":"integer","default":0,"maximum":9007199254740991,"minimum":0},"required":false}]},"post":{"tags":["specs"],"summary":"Upload a PRODUCT's OpenAPI document (idempotent by content hash).","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpecUpsertResponse"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Stored spec (a fresh version, or an idempotent no-op)."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Unknown product slug or implausible spec."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Spec exceeds the maximum size."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiSpecUpsert"}}},"required":true}}},"/topics":{"get":{"tags":["topics"],"summary":"List topics (optionally filtered by status / source key / parent manual / chapter).","responses":{"200":{"content":{"application/json":{"schema":{"type":"object","required":["items","limit","offset","total","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/TopicListItem"}},"limit":{"type":"integer"},"total":{"type":"integer"},"offset":{"type":"integer"},"hasMore":{"type":"boolean"}},"additionalProperties":false}}},"description":"A page of topics."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid pagination query."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."}},"parameters":[{"in":"query","name":"limit","schema":{"type":"integer","default":20,"maximum":100,"exclusiveMinimum":0},"required":false},{"in":"query","name":"offset","schema":{"type":"integer","default":0,"maximum":9007199254740991,"minimum":0},"required":false},{"in":"query","name":"status","schema":{"enum":["draft","pending","published"],"type":"string"},"required":false},{"in":"query","name":"sourceKey","schema":{"type":"string","maxLength":512,"minLength":1},"required":false},{"in":"query","name":"manualId","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional: return only topics under this manual."},{"in":"query","name":"chapterId","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional: return only topics under this chapter."},{"in":"query","name":"updatedSince","schema":{"type":"string","format":"date-time"},"required":false,"description":"INCREMENTAL SYNC: return only rows whose `updatedAt` is at or after this ISO-8601 instant. Poll with the instant of your last sync (pair with `order=updated`) to fetch only what changed since, instead of re-pulling the whole corpus. `total` reflects the filter. A malformed timestamp is a 400."},{"in":"query","name":"order","schema":{"enum":["updated"],"type":"string"},"required":false,"description":"INCREMENTAL SYNC: set to `updated` to order newest-changed-first (`updated_at DESC, id DESC`, a stable tiebreak) for change-polling; pair with `updatedSince=<last sync instant>`. Absent → the default position order. Only the value `updated` is accepted (any other is a 400)."}]},"post":{"tags":["topics"],"summary":"Create a DRAFT topic (CRUD only; does NOT run the publish pipeline).","responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicListItem"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"The created draft topic."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid body, unknown parent, duplicate slug, or malformed Idempotency-Key."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"An in-flight request already holds this `Idempotency-Key`; retry shortly."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"This `Idempotency-Key` was already used for a request with a different body."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}},"parameters":[{"in":"header","name":"Idempotency-Key","schema":{"type":"string","maxLength":255},"required":false,"description":"Opt-in safe-retry key (up to 255 chars). A retry with the SAME key and body replays the original response (marked `Idempotency-Replayed: true`) instead of creating a duplicate. Reusing a key with a DIFFERENT body is a 422; a retry while the first is still in flight is a 409."}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicCreate"},"example":{"slug":"rate-limits","title":"Rate limits","bodyMdx":"# Rate limits\n\nEach API token is capped per minute. On a 429, back off and retry.","excerpt":"How per-token request quotas and 429 backoff work.","manualId":"7c2f9d13-4e8a-4b6c-9d20-1a3b5c7d9e02","position":0,"visibility":"public"}}},"required":true}}},"/manuals":{"get":{"tags":["manuals"],"summary":"List manuals (optionally scoped to one product).","responses":{"200":{"content":{"application/json":{"schema":{"type":"object","required":["items","limit","offset","total","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ManualResponse"}},"limit":{"type":"integer"},"total":{"type":"integer"},"offset":{"type":"integer"},"hasMore":{"type":"boolean"}},"additionalProperties":false}}},"description":"A page of manuals."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid pagination query."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."}},"parameters":[{"in":"query","name":"limit","schema":{"type":"integer","default":20,"maximum":100,"exclusiveMinimum":0},"required":false},{"in":"query","name":"offset","schema":{"type":"integer","default":0,"maximum":9007199254740991,"minimum":0},"required":false},{"in":"query","name":"productId","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional: return only manuals under this product."},{"in":"query","name":"updatedSince","schema":{"type":"string","format":"date-time"},"required":false,"description":"INCREMENTAL SYNC: return only rows whose `updatedAt` is at or after this ISO-8601 instant. Poll with the instant of your last sync (pair with `order=updated`) to fetch only what changed since, instead of re-pulling the whole corpus. `total` reflects the filter. A malformed timestamp is a 400."},{"in":"query","name":"order","schema":{"enum":["updated"],"type":"string"},"required":false,"description":"INCREMENTAL SYNC: set to `updated` to order newest-changed-first (`updated_at DESC, id DESC`, a stable tiebreak) for change-polling; pair with `updatedSince=<last sync instant>`. Absent → the default position order. Only the value `updated` is accepted (any other is a 400)."}]},"post":{"tags":["manuals"],"summary":"Create a manual under a verified product.","responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManualResponse"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"The created manual."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid body, unknown parent product, duplicate slug, or malformed Idempotency-Key."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"An in-flight request already holds this `Idempotency-Key`; retry shortly."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"This `Idempotency-Key` was already used for a request with a different body."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}},"parameters":[{"in":"header","name":"Idempotency-Key","schema":{"type":"string","maxLength":255},"required":false,"description":"Opt-in safe-retry key (up to 255 chars). A retry with the SAME key and body replays the original response (marked `Idempotency-Replayed: true`) instead of creating a duplicate. Reusing a key with a DIFFERENT body is a 422; a retry while the first is still in flight is a 409."}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManualCreate"},"example":{"slug":"getting-started","title":"Getting started","position":0,"productId":"3b1e8c2a-9f4d-4a7b-bc11-2d5e6f7a8b90"}}},"required":true}}},"/tickets":{"get":{"tags":["tickets"],"summary":"Read the caller's own organization's tickets (org-scoped).","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketListResponse"}}},"description":"A page of tickets."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid status/scope filter or malformed updatedSince timestamp."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."}},"parameters":[{"in":"query","name":"limit","schema":{"type":"integer","default":20,"maximum":100,"exclusiveMinimum":0},"required":false},{"in":"query","name":"cursor","schema":{"type":"string"},"required":false,"description":"Opaque keyset cursor from a prior page."},{"in":"query","name":"q","schema":{"type":"string"},"required":false,"description":"Free-text filter over title / summary / external ref."},{"in":"query","name":"status","schema":{"enum":["open","in_progress","resolved","deployed","closed"],"type":"string"},"required":false,"description":"Optional lifecycle-status filter: return only tickets in this status. Narrows within the caller's own org (never widens tenancy). A value outside the enum is a 400."},{"in":"query","name":"updatedSince","schema":{"type":"string","format":"date-time"},"required":false,"description":"INCREMENTAL SYNC: return only tickets whose `updatedAt` is at or after this ISO-8601 instant. Poll with the instant of your last sync to fetch only what changed since, instead of re-pulling the whole feed. No `order` param is needed here: the feed is already ordered newest-updated first. Narrows within the resolved org (never widens tenancy); combinable with `q`/`status`. A malformed timestamp is a 400."},{"in":"query","name":"scope","schema":{"enum":["all","global","org"],"type":"string"},"required":false,"description":"Feed scope: 'all' (the default) unions the caller's own org with the platform-wide (global) product-work rows; 'global' returns only the platform rows; 'org' returns only the caller's own rows. A value outside the enum is a 400. Never widens tenancy: only the resolved org and the platform sentinel are reachable."},{"in":"query","name":"org","schema":{"type":"string"},"required":false,"description":"Operator-only org override (ignored for non-operator callers)."}]},"post":{"tags":["tickets"],"summary":"OPERATOR-ONLY ticket ingestion (idempotent upsert).","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketUpsertResponse"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Updated existing ticket (`created: false`)."},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketUpsertResponse"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Created ticket (`created: true`)."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid body."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Caller is not an operator."},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Payload too large."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketUpsert"}}},"required":true}}},"/chapters":{"get":{"tags":["chapters"],"summary":"List chapters (optionally scoped to one manual).","responses":{"200":{"content":{"application/json":{"schema":{"type":"object","required":["items","limit","offset","total","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ChapterResponse"}},"limit":{"type":"integer"},"total":{"type":"integer"},"offset":{"type":"integer"},"hasMore":{"type":"boolean"}},"additionalProperties":false}}},"description":"A page of chapters."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid pagination query."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."}},"parameters":[{"in":"query","name":"limit","schema":{"type":"integer","default":20,"maximum":100,"exclusiveMinimum":0},"required":false},{"in":"query","name":"offset","schema":{"type":"integer","default":0,"maximum":9007199254740991,"minimum":0},"required":false},{"in":"query","name":"manualId","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional: return only chapters under this manual."},{"in":"query","name":"updatedSince","schema":{"type":"string","format":"date-time"},"required":false,"description":"INCREMENTAL SYNC: return only rows whose `updatedAt` is at or after this ISO-8601 instant. Poll with the instant of your last sync (pair with `order=updated`) to fetch only what changed since, instead of re-pulling the whole corpus. `total` reflects the filter. A malformed timestamp is a 400."},{"in":"query","name":"order","schema":{"enum":["updated"],"type":"string"},"required":false,"description":"INCREMENTAL SYNC: set to `updated` to order newest-changed-first (`updated_at DESC, id DESC`, a stable tiebreak) for change-polling; pair with `updatedSince=<last sync instant>`. Absent → the default position order. Only the value `updated` is accepted (any other is a 400)."}]},"post":{"tags":["chapters"],"summary":"Create a chapter under a verified manual.","responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChapterResponse"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"The created chapter."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid body, unknown parent manual, duplicate slug, or malformed Idempotency-Key."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"An in-flight request already holds this `Idempotency-Key`; retry shortly."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"This `Idempotency-Key` was already used for a request with a different body."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}},"parameters":[{"in":"header","name":"Idempotency-Key","schema":{"type":"string","maxLength":255},"required":false,"description":"Opt-in safe-retry key (up to 255 chars). A retry with the SAME key and body replays the original response (marked `Idempotency-Replayed: true`) instead of creating a duplicate. Reusing a key with a DIFFERENT body is a 422; a retry while the first is still in flight is a 409."}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChapterCreate"},"example":{"slug":"basics","title":"Basics","manualId":"7c2f9d13-4e8a-4b6c-9d20-1a3b5c7d9e02","position":0}}},"required":true}}},"/me/usage":{"get":{"tags":["me"],"summary":"The caller's OWN recorded API activity over a trailing window (`?days=`, default 30, max 365): a per-action breakdown, a daily trend, and how many `access.denied` (403) rows the token generated, so an integrator can watch its own throughput and catch a token that is silently getting denied. Self-scoped: only ever the caller’s own actor rows.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiUsageResponse"},"example":{"days":30,"actor":"autocoder@hank.ai","total":42,"trend":[{"date":"2026-07-01","count":12},{"date":"2026-07-02","count":18},{"date":"2026-07-03","count":12}],"denied":1,"byAction":[{"count":38,"action":"topic.upsert"},{"count":3,"action":"changelog.create"},{"count":1,"action":"access.denied"}],"generatedAt":"2026-07-03T19:40:00.000Z"}}},"description":"The caller's own recorded API activity over the window."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."}},"parameters":[{"in":"query","name":"days","schema":{"type":"integer","default":30,"maximum":365,"minimum":1},"required":false,"description":"Trailing window in days (clamped to [1, 365]; a missing/invalid value = 30)."}]}},"/products":{"get":{"tags":["products"],"summary":"List products.","responses":{"200":{"content":{"application/json":{"schema":{"type":"object","required":["items","limit","offset","total","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ProductResponse"}},"limit":{"type":"integer"},"total":{"type":"integer"},"offset":{"type":"integer"},"hasMore":{"type":"boolean"}},"additionalProperties":false}}},"description":"A page of products."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid pagination query."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."}},"parameters":[{"in":"query","name":"limit","schema":{"type":"integer","default":20,"maximum":100,"exclusiveMinimum":0},"required":false},{"in":"query","name":"offset","schema":{"type":"integer","default":0,"maximum":9007199254740991,"minimum":0},"required":false},{"in":"query","name":"updatedSince","schema":{"type":"string","format":"date-time"},"required":false,"description":"INCREMENTAL SYNC: return only rows whose `updatedAt` is at or after this ISO-8601 instant. Poll with the instant of your last sync (pair with `order=updated`) to fetch only what changed since, instead of re-pulling the whole corpus. `total` reflects the filter. A malformed timestamp is a 400."},{"in":"query","name":"order","schema":{"enum":["updated"],"type":"string"},"required":false,"description":"INCREMENTAL SYNC: set to `updated` to order newest-changed-first (`updated_at DESC, id DESC`, a stable tiebreak) for change-polling; pair with `updatedSince=<last sync instant>`. Absent → the default position order. Only the value `updated` is accepted (any other is a 400)."}]},"post":{"tags":["products"],"summary":"Create a product.","responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductResponse"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"The created product."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid body, duplicate slug, or malformed Idempotency-Key."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"An in-flight request already holds this `Idempotency-Key`; retry shortly."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"This `Idempotency-Key` was already used for a request with a different body."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}},"parameters":[{"in":"header","name":"Idempotency-Key","schema":{"type":"string","maxLength":255},"required":false,"description":"Opt-in safe-retry key (up to 255 chars). A retry with the SAME key and body replays the original response (marked `Idempotency-Replayed: true`) instead of creating a duplicate. Reusing a key with a DIFFERENT body is a 422; a retry while the first is still in flight is a 409."}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductCreate"},"example":{"kind":"standalone","name":"Medical Auto Coding","slug":"auto-coding","tagline":"Autonomous medical coding, end to end.","position":0}}},"required":true}}},"/analytics":{"get":{"tags":["analytics"],"summary":"Bot-readable docs-quality signals. Without `topicId` → the SITE summary (helpful backlog, most-viewed axis, daily momentum, search gaps, scrubbed comments, stale backlog). With `topicId=<uuid>` → a PER-TOPIC drill-down (that topic's view trend + vote counts + scrubbed comments). Aggregate-only; never PHI.","responses":{"200":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/AnalyticsSummaryResponse"},{"$ref":"#/components/schemas/AnalyticsTopicDrilldownResponse"}]}}},"description":"The site analytics summary, or (with `topicId`) a per-topic drill-down."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid limit or non-uuid topicId."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."}},"parameters":[{"in":"query","name":"limit","schema":{"type":"integer","minimum":1},"required":false,"description":"Max rows per embedded list (clamped to [1, 100], default 20). Out of range is a 400."},{"in":"query","name":"topicId","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional topic id (uuid). Present → the response is the PER-TOPIC drill-down (`AnalyticsTopicDrilldownResponse`) for that topic instead of the site summary. A non-uuid value is a 400; an unknown (or non-public) topic yields a zeroed drill-down."},{"in":"query","name":"days","schema":{"type":"integer","maximum":365,"minimum":1},"required":false,"description":"Trailing window in DAYS for the view-trend/momentum series, CLAMPED to [1, 365] (default 30). Out-of-range values clamp (they are not a 400). Applies to the summary `trends` and the drill-down `trend`/`totalViews`."}]}},"/changelog":{"get":{"tags":["changelog"],"summary":"List PUBLIC changelog entries (metadata + deepLink permalink), newest first; optionally scoped to one product via `?product=<slug>` (absent → the global cross-product feed). Lean: no entry body; the deepLink points at the rendered entry.","responses":{"200":{"content":{"application/json":{"schema":{"type":"object","required":["items","limit","offset","total","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ChangelogListItem"}},"limit":{"type":"integer"},"total":{"type":"integer"},"offset":{"type":"integer"},"hasMore":{"type":"boolean"}},"additionalProperties":false}}},"description":"A page of public changelog entries."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid pagination query or malformed product slug."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."}},"parameters":[{"in":"query","name":"limit","schema":{"type":"integer","default":20,"maximum":100,"exclusiveMinimum":0},"required":false},{"in":"query","name":"offset","schema":{"type":"integer","default":0,"maximum":9007199254740991,"minimum":0},"required":false},{"in":"query","name":"product","schema":{"type":"string"},"required":false,"description":"Optional product slug: scope the feed to one product. Absent → the global cross-product feed; a malformed slug is a 400; an unknown slug is an empty page."}]},"post":{"tags":["changelog"],"summary":"Publish a dated changelog entry. Idempotent on (product, date, version); auto-publishes after a strict leak + PHI scan. Returns the entry id + its deepLink permalink.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangelogCreateResponse"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Updated existing entry."},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangelogCreateResponse"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Created entry."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid body, unknown product, or content failed the leak/PHI scan."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangelogCreate"},"example":{"tags":["api","feature"],"title":"Batch claim submission","bodyMdx":"- Added `POST /claims/batch`\n- Fixed a 429 edge case on burst submits","version":"2.1.0","entryDate":"2026-07-01","productId":"3b1e8c2a-9f4d-4a7b-bc11-2d5e6f7a8b90","visibility":"public"}}},"required":true}}},"/compliance":{"get":{"tags":["audit"],"summary":"OPERATOR-ONLY: the governance rollups the /admin/compliance dashboard shows, as JSON for a SIEM/GRC pull: review-queue health, rejection-feedback quality, access-control events, the rejection overview, force-pend analysis, and Ask-AI refusals over a trailing `?days=` window. Aggregate-only (counts + stable codes + day buckets + durations): no note text, actor, or content. A customer token (valid `hank-docs` scope but not an operator) is 403.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComplianceResponse"}}},"description":"The governance rollups over the window."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."}},"parameters":[{"in":"query","name":"days","schema":{"type":"integer","default":30,"maximum":365,"minimum":1},"required":false,"description":"Trailing window in DAYS (clamped to [1, 365], default 30) applied to every rollup."}]}},"/specs/diff":{"get":{"tags":["specs"],"summary":"Structured diff between two stored spec versions: added/removed/changed operation, parameter, security, and response-shape labels + a single `breaking` verdict + a deterministic summary. `to` defaults to the LATEST stored version: \"diff my pinned version against current\" in one call.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpecDiffResponse"}}},"description":"The two sides' version metadata + the classified diff."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing/malformed product slug or a non-uuid version id."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such product/version combination (unknown product, unknown version id, or no history)."}},"parameters":[{"in":"query","name":"product","schema":{"type":"string"},"required":true,"description":"The owning product slug (REQUIRED). Malformed → 400; unknown/non-public → 404."},{"in":"query","name":"from","schema":{"type":"string","format":"uuid"},"required":true,"description":"The OLD side: a spec version ROW id (uuid) from `GET /specs`. Version LABELS are not accepted (they can repeat); the row id is the only collision-free handle. Non-uuid → 400; unknown / another product's id → 404."},{"in":"query","name":"to","schema":{"type":"string","format":"uuid"},"required":false,"description":"The NEW side: a spec version ROW id (uuid). Omitted → the product's latest stored version. Equal to `from` is legal (an empty, non-breaking diff)."}]}},"/topics/{id}":{"get":{"tags":["topics"],"summary":"Get one topic (includes a derived, scrubbed review note when in draft).","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicDetailWithReview"}}},"description":"The topic (with the derived `reviewNote`)."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid id."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such topic."}}},"patch":{"tags":["topics"],"summary":"Partially update topic METADATA only. Content fields are rejected (400) so content can never bypass the publish pipeline. Use `POST /topics/upsert` for content.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicDetail"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"The updated topic."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid body, a content field was supplied, or invalid id."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such topic."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicUpdate"}}},"required":true}},"delete":{"tags":["topics"],"summary":"Delete a topic.","responses":{"204":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Deleted; no content."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid id."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such topic."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}}},"parameters":[{"in":"path","name":"id","schema":{"type":"string","format":"uuid"},"required":true,"description":"Resource id (uuid)."}]},"/audit/verify":{"get":{"tags":["audit"],"summary":"OPERATOR-ONLY: programmatically verify the audit hash-chain integrity (compliance / SIEM monitoring). Read-only recompute over the stored chain. Returns `status` (connected / broken / empty), the mutation count, the head digest/seq (the value to pin to an external anchor), and, when broken, the earliest break (seq + reason + derived-vs-stored hashes). Carries NO actor/actorType, metadata, or content. A customer token (valid `hank-docs` scope but not an operator) is 403, never a cross-tenant read.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditVerifyResponse"}}},"description":"The hash-chain verification result."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."}}}},"/manuals/{id}":{"get":{"tags":["manuals"],"summary":"Get one manual.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManualResponse"}}},"description":"The manual."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid id."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such manual."}}},"patch":{"tags":["manuals"],"summary":"Partially update a manual.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManualResponse"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"The updated manual."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid body or id."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such manual."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManualUpdate"}}},"required":true}},"delete":{"tags":["manuals"],"summary":"Delete a manual.","responses":{"204":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Deleted; no content."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid id."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such manual."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}}},"parameters":[{"in":"path","name":"id","schema":{"type":"string","format":"uuid"},"required":true,"description":"Resource id (uuid)."}]},"/topics/batch":{"post":{"tags":["topics"],"summary":"Bulk upsert up to 25 topics in one request (corpus migration). Each item runs the SAME publish pipeline as /topics/upsert; results are PER-ITEM (created/updated/rejected/rate_limited/error) so one bad item never fails the batch. Each item is charged against the per-identity write budget, NOT a rate-limit bypass; a partial batch returns Retry-After.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchUpsertResponse"},"example":{"results":[{"id":"a4d8e6f2-1b3c-4d5e-8f90-2c4a6b8d0e13","index":0,"status":"created","sourceKey":"kb/rate-limits"},{"code":"content_rejected","index":1,"status":"rejected","message":"a link points at a missing anchor","sourceKey":"kb/webhooks"}],"summary":{"total":2,"created":1,"errored":0,"updated":0,"rejected":1,"rateLimited":0}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Per-item results + a roll-up summary (a partial batch is normal, so inspect each `status`)."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Malformed or empty/oversize batch envelope (max 25 items)."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicBatchUpsert"},"example":{"items":[{"slug":"rate-limits","title":"Rate limits","bodyMdx":"# Rate limits\n\nEach API token is capped per minute. On a 429, back off and retry.","excerpt":"How per-token request quotas and 429 backoff work.","manualId":"7c2f9d13-4e8a-4b6c-9d20-1a3b5c7d9e02","sourceKey":"kb/rate-limits","visibility":"public"},{"slug":"webhooks","title":"Webhooks","bodyMdx":"# Webhooks\n\nRegister a URL to receive event callbacks.","excerpt":"Subscribe to publish + review events.","manualId":"7c2f9d13-4e8a-4b6c-9d20-1a3b5c7d9e02","sourceKey":"kb/webhooks","visibility":"public"}]}}},"required":true}}},"/chapters/{id}":{"get":{"tags":["chapters"],"summary":"Get one chapter.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChapterResponse"}}},"description":"The chapter."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid id."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such chapter."}}},"patch":{"tags":["chapters"],"summary":"Partially update a chapter.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChapterResponse"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"The updated chapter."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid body or id."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such chapter."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChapterUpdate"}}},"required":true}},"delete":{"tags":["chapters"],"summary":"Delete a chapter.","responses":{"204":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Deleted; no content."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid id."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such chapter."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}}},"parameters":[{"in":"path","name":"id","schema":{"type":"string","format":"uuid"},"required":true,"description":"Resource id (uuid)."}]},"/products/{id}":{"get":{"tags":["products"],"summary":"Get one product.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductResponse"},"example":{"id":"3b1e8c2a-9f4d-4a7b-bc11-2d5e6f7a8b90","icon":null,"kind":"standalone","name":"Medical Auto Coding","slug":"auto-coding","tagline":"Autonomous medical coding, end to end.","position":0,"updatedAt":"2026-07-01T18:24:00.000Z","visibility":"public","description":null,"isPublished":true,"isSensitive":false}}},"description":"The product."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid id."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such product."}}},"patch":{"tags":["products"],"summary":"Partially update a product.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductResponse"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"The updated product."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid body or id."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such product."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductUpdate"}}},"required":true}},"delete":{"tags":["products"],"summary":"Delete a product.","responses":{"204":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Deleted; no content."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid id."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such product."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}}},"parameters":[{"in":"path","name":"id","schema":{"type":"string","format":"uuid"},"required":true,"description":"Resource id (uuid)."}]},"/topics/status":{"get":{"tags":["topics"],"summary":"Poll one bot submission's review status by its `(manualId, sourceKey)` upsert handle. Is it still `pending`, did it go `published`, or was it sent back to `draft` (with the reviewer's `rejectReason`)? The REST twin of the MCP `get_topic_status` tool; scoped to bot-authored topics only.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionStatusResponse"},"example":{"id":"a4d8e6f2-1b3c-4d5e-8f90-2c4a6b8d0e13","slug":"rate-limits","found":true,"title":"Rate limits","status":"draft","rejected":true,"visibility":"public","rejectReason":"Please cite the CPT source for the coding table."}}},"description":"The submission's review status (or `found:false` if no bot topic carries that handle)."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing/invalid `manualId`, or a blank `sourceKey`."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."}},"parameters":[{"in":"query","name":"manualId","schema":{"type":"string","format":"uuid"},"required":true,"description":"The manual UUID the topic was upserted under."},{"in":"query","name":"sourceKey","schema":{"type":"string"},"required":true,"description":"The idempotency source key the topic was upserted under."}]}},"/topics/upsert":{"post":{"tags":["topics"],"summary":"Primary content-publish path: idempotent on `sourceKey`, runs the full publish pipeline (leak/link/alt-text scan + policy gate) and force-pends sensitive/bot content for review.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicUpsertResponse"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"The updated topic (existing `sourceKey`)."},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicUpsertResponse"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"The created topic (new `sourceKey`)."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid body, unknown parent, rejected content, or slug clash."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicUpsert"},"example":{"slug":"rate-limits","title":"Rate limits","bodyMdx":"# Rate limits\n\nEach API token is capped per minute. On a 429, back off and retry.","excerpt":"How per-token request quotas and 429 backoff work.","manualId":"7c2f9d13-4e8a-4b6c-9d20-1a3b5c7d9e02","sourceKey":"kb/rate-limits","visibility":"public"}}},"required":true}}},"/tickets/summary":{"get":{"tags":["tickets"],"summary":"Per-status rollup of the caller's own organization's tickets.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketStatusSummaryResponse"}}},"description":"The per-status ticket rollup."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."}},"parameters":[{"in":"query","name":"scope","schema":{"enum":["all","global","org"],"type":"string"},"required":false,"description":"Rollup scope: 'all' (the default) unions the caller's own org with the platform-wide (global) rows so the counts match the default feed; 'global' counts only the platform rows; 'org' counts only the caller's own rows. A value outside the enum is a 400."},{"in":"query","name":"org","schema":{"type":"string"},"required":false,"description":"Operator-only org override (ignored for non-operator callers)."}],"description":"The caller's own-org ticket portfolio counted by lifecycle status: total, the non-terminal open count, and a zero-filled per-status breakdown. The programmatic twin of the /updates status chips: a poller gets the whole breakdown in one call instead of paging the feed. Aggregate-only (status codes + counts, no ticket content). Org-scoped off the validated token."}},"/topics/submissions":{"get":{"tags":["topics"],"summary":"List the programmatic authoring surface’s OWN submissions (a thin worklist: what’s `pending`, sent back to `draft`, or `published`). The REST twin of the MCP `list_my_submissions` tool; hardcoded to bot-authored topics only, newest-changed first.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionsListResponse"},"example":{"items":[{"slug":"rate-limits","title":"Rate limits","status":"pending","manualId":"3f1a9c2e-7b4d-4e6a-9c1f-2d5b8e0a3c47","sourceKey":"kb/rate-limits","updatedAt":"2026-07-01T18:22:05.000Z","visibility":"public"}],"limit":20}}},"description":"The bot-authored submissions worklist (thin projection: no body/PHI)."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid `manualId`, or an unknown `status`."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."}},"parameters":[{"in":"query","name":"manualId","schema":{"type":"string","format":"uuid"},"required":false,"description":"Optional: restrict to one parent manual."},{"in":"query","name":"status","schema":{"enum":["draft","pending","published"],"type":"string"},"required":false,"description":"Optional: restrict to one lifecycle status."},{"in":"query","name":"limit","schema":{"type":"integer","default":20,"maximum":100,"minimum":1},"required":false,"description":"Page size (newest-changed first). Bounded; there is no unbounded scan."}]}},"/products/{id}/members":{"get":{"tags":["products"],"summary":"List the member products of a PLATFORM product (its service directory), in curated order. Members of EVERY status are returned, so a `coming_soon` service is visible to an integrator before it goes live. A product whose `kind` is not `platform` has no member collection and answers 404.","responses":{"200":{"content":{"application/json":{"schema":{"type":"object","required":["items","limit","offset","total","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PlatformMemberResponse"}},"limit":{"type":"integer"},"total":{"type":"integer"},"offset":{"type":"integer"},"hasMore":{"type":"boolean"}},"additionalProperties":false}}},"description":"A page of platform members."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid id or pagination query."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such product, or the product is not a platform."}},"parameters":[{"in":"query","name":"limit","schema":{"type":"integer","default":20,"maximum":100,"exclusiveMinimum":0},"required":false},{"in":"query","name":"offset","schema":{"type":"integer","default":0,"maximum":9007199254740991,"minimum":0},"required":false}]},"post":{"tags":["products"],"summary":"Add a member product to a platform. The member must be a `standalone` product and must not already be a member (platforms do not nest). An omitted `position` appends the member at the end of the platform's list; `status` defaults to `coming_soon`.","responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformMemberResponse"},"example":{"id":"f0e1d2c3-b4a5-4968-9788-6a5b4c3d2e1f","status":"available","position":0,"createdAt":"2026-07-01T18:24:00.000Z","memberName":"HANK AutoCoder API","memberSlug":"auto-coding","platformId":"3b1e8c2a-9f4d-4a7b-bc11-2d5e6f7a8b90","memberProductId":"d9a0b1c2-3e4f-4a5b-8c6d-7e8f9a0b1c2d"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"The created membership."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid body, unknown member product (`unknown_parent`), a member that is the platform itself or is not standalone, a product already a member (`duplicate_member`), or a malformed Idempotency-Key."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such product, or the product is not a platform."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"An in-flight request already holds this `Idempotency-Key`; retry shortly."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"This `Idempotency-Key` was already used for a request with a different body."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}},"parameters":[{"in":"header","name":"Idempotency-Key","schema":{"type":"string","maxLength":255},"required":false,"description":"Opt-in safe-retry key (up to 255 chars). A retry with the SAME key and body replays the original response (marked `Idempotency-Replayed: true`) instead of creating a duplicate. Reusing a key with a DIFFERENT body is a 422; a retry while the first is still in flight is a 409."}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformMemberCreate"},"example":{"status":"coming_soon","memberProductId":"d9a0b1c2-3e4f-4a5b-8c6d-7e8f9a0b1c2d"}}},"required":true}},"parameters":[{"in":"path","name":"id","schema":{"type":"string","format":"uuid"},"required":true,"description":"The PLATFORM product id (uuid). A non-platform product answers 404 here."}]},"/tickets/{externalRef}":{"get":{"tags":["tickets"],"summary":"Read ONE of the caller's own organization's tickets by external ref: the single-resource REST twin of the MCP `get_ticket` tool. Same org scoping / customer-safe projection as the list; 404 when no such ticket exists in the resolved org.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketSummary"}}},"description":"The ticket."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Empty or whitespace external ref."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such ticket in the caller's organization."}},"parameters":[{"in":"path","name":"externalRef","schema":{"type":"string"},"required":true,"description":"The ticket's customer-facing reference (HANK's own ticket id). Resolved WITHIN the caller's org. A ref that is not the caller's org's is a 404, never a cross-tenant read."},{"in":"query","name":"org","schema":{"type":"string"},"required":false,"description":"Operator-only org override (ignored for non-operator callers)."}]}},"/products/{id}/members/{membershipId}":{"patch":{"tags":["products"],"summary":"Update one membership's `status` and/or `position`. The member product itself is immutable on a membership: to point a slot at another product, remove it and add one.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformMemberResponse"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"The updated membership."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid body or id."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such membership on this platform."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformMemberUpdate"}}},"required":true}},"delete":{"tags":["products"],"summary":"Remove a membership. The member PRODUCT is untouched: only its place in the platform goes away, so the product returns to the top-level catalog.","responses":{"204":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Removed; no content."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid id."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid bearer token."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Token lacks the required scope."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such membership on this platform."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"}},"description":"Write rate limit exceeded; retry after the `Retry-After` interval."}}},"parameters":[{"in":"path","name":"id","schema":{"type":"string","format":"uuid"},"required":true,"description":"The PLATFORM product id (uuid). A non-platform product answers 404 here."},{"in":"path","name":"membershipId","schema":{"type":"string","format":"uuid"},"required":true,"description":"The membership row id (uuid). It must belong to the platform in the path; a membership of a different platform answers 404."}]}},"openapi":"3.1.0","servers":[{"url":"https://newdocs.hank.ai/api/v1","description":"The platform REST API."}],"security":[{"bearerAuth":[]}],"components":{"headers":{"RetryAfter":{"schema":{"type":"integer"},"description":"Seconds to wait before retrying, on a 429 (mirrors X-RateLimit-Reset)."},"XRateLimitLimit":{"schema":{"type":"integer"},"description":"The per-identity write rate-limit cap for the current window."},"XRateLimitReset":{"schema":{"type":"integer"},"description":"UNIX epoch SECONDS at which the current rate-limit window resets."},"XRateLimitRemaining":{"schema":{"type":"integer"},"description":"Writes remaining in the current window (0 once the cap is hit)."}},"schemas":{"Error":{"type":"object","required":["error","code"],"properties":{"code":{"enum":["invalid_request","duplicate_slug","duplicate_member","unknown_parent","content_rejected","unauthorized","forbidden","not_found","payload_too_large","rate_limited","invalid_idempotency_key","idempotency_in_progress","idempotency_key_conflict"],"type":"string","description":"Stable machine-readable error code. Branch on this, not the message text."},"error":{"type":"string","description":"Human-readable failure reason."}},"additionalProperties":false},"AuditEntry":{"type":"object","required":["id","createdAt","action","entityType","entityId","metadata"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"seq":{"anyOf":[{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},{"type":"null"}]},"action":{"type":"string"},"digest":{"type":"string"},"entityId":{"anyOf":[{"type":"string"},{"type":"null"}]},"metadata":{"type":"string"},"createdAt":{"type":"string"},"entityType":{"anyOf":[{"type":"string"},{"type":"null"}]},"prevDigest":{"type":"string"}},"additionalProperties":false},"MeResponse":{"type":"object","required":["email","actorType","scopes","organizationId","isAdmin","rateLimit"],"properties":{"email":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"isAdmin":{"type":"boolean"},"actorType":{"enum":["autocoder","mcp"],"type":"string"},"rateLimit":{"type":"object","required":["limit","remaining","resetSeconds"],"properties":{"limit":{"type":"integer","maximum":9007199254740991,"minimum":0},"remaining":{"type":"integer","maximum":9007199254740991,"minimum":0},"resetSeconds":{"type":"integer","maximum":9007199254740991,"minimum":0}},"additionalProperties":false},"organizationId":{"type":"string"}},"additionalProperties":false},"TopicCreate":{"type":"object","required":["manualId","slug","title"],"properties":{"slug":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","maxLength":128,"minLength":1},"title":{"type":"string","maxLength":300,"minLength":1},"bodyMdx":{"type":"string","default":"","maxLength":200000},"excerpt":{"anyOf":[{"type":"string","pattern":"^[^\\n\\r]*$","maxLength":2000},{"type":"null"}]},"manualId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"position":{"type":"integer","default":0,"maximum":9007199254740991,"minimum":0},"chapterId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"sourceKey":{"anyOf":[{"type":"string","maxLength":512},{"type":"null"}]},"versionTag":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}]},"visibility":{"enum":["public","internal"],"type":"string","default":"public"},"frontmatter":{"type":"object","default":{},"propertyNames":{"type":"string"},"additionalProperties":{}}},"additionalProperties":false},"TopicDetail":{"type":"object","required":["id","manualId","chapterId","slug","title","excerpt","position","status","visibility","sourceKey","createdByBot","updatedAt","bodyMdx","lastReviewedAt"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"slug":{"type":"string"},"title":{"type":"string"},"status":{"enum":["draft","pending","published"],"type":"string"},"bodyMdx":{"type":"string"},"excerpt":{"anyOf":[{"type":"string"},{"type":"null"}]},"manualId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"position":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"chapterId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"sourceKey":{"anyOf":[{"type":"string"},{"type":"null"}]},"updatedAt":{"type":"string"},"visibility":{"enum":["public","internal"],"type":"string"},"createdByBot":{"type":"boolean"},"lastReviewedAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false},"TopicUpdate":{"type":"object","properties":{"slug":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","maxLength":128,"minLength":1},"position":{"type":"integer","maximum":9007199254740991,"minimum":0},"chapterId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"sourceKey":{"anyOf":[{"type":"string","maxLength":512},{"type":"null"}]},"versionTag":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}]}},"additionalProperties":false},"TopicUpsert":{"type":"object","required":["manualId","slug","title"],"properties":{"slug":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","maxLength":128,"minLength":1},"title":{"type":"string","maxLength":300,"minLength":1},"bodyMdx":{"type":"string","default":"","maxLength":200000},"excerpt":{"anyOf":[{"type":"string","pattern":"^[^\\n\\r]*$","maxLength":2000},{"type":"null"}]},"manualId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"position":{"type":"integer","default":0,"maximum":9007199254740991,"minimum":0},"chapterId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"sourceKey":{"anyOf":[{"type":"string","maxLength":512},{"type":"null"}]},"versionTag":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}]},"visibility":{"enum":["public","internal"],"type":"string","default":"public"},"frontmatter":{"type":"object","default":{},"propertyNames":{"type":"string"},"additionalProperties":{}},"requireReview":{"type":"boolean"}},"additionalProperties":false},"ManualCreate":{"type":"object","required":["productId","slug","title"],"properties":{"slug":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","maxLength":128,"minLength":1},"title":{"type":"string","maxLength":200,"minLength":1},"position":{"type":"integer","default":0,"maximum":9007199254740991,"minimum":0},"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]}},"additionalProperties":false},"ManualUpdate":{"type":"object","properties":{"slug":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","maxLength":128,"minLength":1},"title":{"type":"string","maxLength":200,"minLength":1},"position":{"type":"integer","maximum":9007199254740991,"minimum":0},"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]}},"additionalProperties":false},"TicketUpsert":{"type":"object","required":["organization_id","external_ref","title","status"],"properties":{"title":{"type":"string","maxLength":500,"minLength":1},"status":{"enum":["open","in_progress","resolved","deployed","closed"],"type":"string"},"product":{"type":"string","maxLength":128},"summary":{"type":"string","maxLength":20000},"priority":{"type":"string","maxLength":64},"deployed_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"external_ref":{"type":"string","maxLength":256,"minLength":1},"external_url":{"type":"string","format":"uri","maxLength":2048},"organization_id":{"type":"string","maxLength":128,"minLength":1},"target_deploy_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},"additionalProperties":false},"ApiSpecUpsert":{"type":"object","required":["productSlug","spec"],"properties":{"spec":{"type":"object","required":["openapi","info","paths"],"properties":{"info":{"type":"object","required":["title"],"properties":{"title":{"type":"string","minLength":1}}},"paths":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"openapi":{"type":"string","minLength":1}},"additionalProperties":{}},"version":{"type":"string","default":"","maxLength":64},"productSlug":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","maxLength":128,"minLength":1}},"additionalProperties":false},"ChapterCreate":{"type":"object","required":["manualId","slug","title"],"properties":{"slug":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","maxLength":128,"minLength":1},"title":{"type":"string","maxLength":200,"minLength":1},"manualId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"position":{"type":"integer","default":0,"maximum":9007199254740991,"minimum":0}},"additionalProperties":false},"ChapterUpdate":{"type":"object","properties":{"slug":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","maxLength":128,"minLength":1},"title":{"type":"string","maxLength":200,"minLength":1},"position":{"type":"integer","maximum":9007199254740991,"minimum":0}},"additionalProperties":false},"MediaResponse":{"type":"object","required":["id","url"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"url":{"type":"string"}},"additionalProperties":false},"ProductCreate":{"type":"object","required":["slug","name"],"properties":{"icon":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}]},"kind":{"enum":["standalone","platform"],"type":"string","default":"standalone"},"name":{"type":"string","maxLength":200,"minLength":1},"slug":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","maxLength":128,"minLength":1},"tagline":{"anyOf":[{"type":"string","maxLength":300},{"type":"null"}]},"position":{"type":"integer","default":0,"maximum":9007199254740991,"minimum":0},"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]}},"additionalProperties":false},"ProductUpdate":{"type":"object","properties":{"icon":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}]},"kind":{"enum":["standalone","platform"],"type":"string"},"name":{"type":"string","maxLength":200,"minLength":1},"slug":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","maxLength":128,"minLength":1},"tagline":{"anyOf":[{"type":"string","maxLength":300},{"type":"null"}]},"position":{"type":"integer","maximum":9007199254740991,"minimum":0},"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]}},"additionalProperties":false},"TicketSummary":{"type":"object","required":["id","externalRef","title","status","summary","product","priority","targetDeployDate","deployedAt","updatedAt","isGlobal"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"title":{"type":"string"},"status":{"enum":["open","in_progress","resolved","deployed","closed"],"type":"string"},"product":{"anyOf":[{"type":"string"},{"type":"null"}]},"summary":{"anyOf":[{"type":"string"},{"type":"null"}]},"isGlobal":{"type":"boolean"},"priority":{"anyOf":[{"type":"string"},{"type":"null"}]},"updatedAt":{"type":"string"},"deployedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"externalRef":{"type":"string"},"targetDeployDate":{"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false},"TopicListItem":{"type":"object","required":["id","manualId","chapterId","slug","title","excerpt","position","status","visibility","sourceKey","createdByBot","updatedAt"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"slug":{"type":"string"},"title":{"type":"string"},"status":{"enum":["draft","pending","published"],"type":"string"},"excerpt":{"anyOf":[{"type":"string"},{"type":"null"}]},"manualId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"position":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"chapterId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"sourceKey":{"anyOf":[{"type":"string"},{"type":"null"}]},"updatedAt":{"type":"string"},"visibility":{"enum":["public","internal"],"type":"string"},"createdByBot":{"type":"boolean"}},"additionalProperties":false},"ManualResponse":{"type":"object","required":["id","productId","slug","title","description","position","publishPolicy","isSensitive","updatedAt"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"slug":{"type":"string"},"title":{"type":"string"},"position":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"updatedAt":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"isSensitive":{"type":"boolean"},"publishPolicy":{"type":"string"}},"additionalProperties":false},"ChangelogCreate":{"type":"object","required":["productId","entryDate","version","title"],"properties":{"tags":{"type":"array","items":{"type":"string","minLength":1},"default":[]},"title":{"type":"string","maxLength":300,"minLength":1},"bodyMdx":{"type":"string","default":"","maxLength":200000},"version":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}]},"entryKey":{"type":"string","maxLength":200,"minLength":1},"entryDate":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"lifecycle":{"enum":["planned","in_progress","released"],"type":"string","default":"released"},"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ticketRef":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}]},"releasedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]},"visibility":{"enum":["public","internal"],"type":"string","default":"public"},"effectiveFrom":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]}}},"ChapterResponse":{"type":"object","required":["id","manualId","slug","title","position","updatedAt"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"slug":{"type":"string"},"title":{"type":"string"},"manualId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"position":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"updatedAt":{"type":"string"}},"additionalProperties":false},"ProductResponse":{"type":"object","required":["id","slug","name","kind","tagline","description","icon","position","visibility","isPublished","isSensitive","updatedAt"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}]},"kind":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"tagline":{"anyOf":[{"type":"string"},{"type":"null"}]},"position":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"updatedAt":{"type":"string"},"visibility":{"enum":["public","internal"],"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"isPublished":{"type":"boolean"},"isSensitive":{"type":"boolean"}},"additionalProperties":false},"SpecVersionMeta":{"type":"object","required":["id","version","sourceHash","createdAt"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"version":{"type":"string"},"createdAt":{"type":"string"},"sourceHash":{"type":"string"}},"additionalProperties":false},"ApiUsageResponse":{"type":"object","required":["generatedAt","actor","days","total","denied","byAction","trend"],"properties":{"days":{"type":"integer","maximum":9007199254740991,"exclusiveMinimum":0},"actor":{"type":"string"},"total":{"type":"integer","maximum":9007199254740991,"minimum":0},"trend":{"type":"array","items":{"type":"object","required":["date","count"],"properties":{"date":{"type":"string"},"count":{"type":"integer","maximum":9007199254740991,"minimum":0}},"additionalProperties":false}},"denied":{"type":"integer","maximum":9007199254740991,"minimum":0},"byAction":{"type":"array","items":{"type":"object","required":["action","count"],"properties":{"count":{"type":"integer","maximum":9007199254740991,"minimum":0},"action":{"type":"string"}},"additionalProperties":false}},"generatedAt":{"type":"string"}},"additionalProperties":false},"SpecDiffResponse":{"type":"object","required":["from","to","diff"],"properties":{"to":{"type":"object","required":["id","version","sourceHash","createdAt"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"version":{"type":"string"},"createdAt":{"type":"string"},"sourceHash":{"type":"string"}},"additionalProperties":false},"diff":{"type":"object","required":["added","removed","changed","breaking","summary"],"properties":{"added":{"type":"array","items":{"type":"string"}},"changed":{"type":"array","items":{"type":"string"}},"removed":{"type":"array","items":{"type":"string"}},"summary":{"type":"string"},"breaking":{"type":"boolean"}},"additionalProperties":false},"from":{"type":"object","required":["id","version","sourceHash","createdAt"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"version":{"type":"string"},"createdAt":{"type":"string"},"sourceHash":{"type":"string"}},"additionalProperties":false}},"additionalProperties":false},"TopicBatchUpsert":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"type":"object","required":["manualId","slug","title"],"properties":{"slug":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","maxLength":128,"minLength":1},"title":{"type":"string","maxLength":300,"minLength":1},"bodyMdx":{"type":"string","default":"","maxLength":200000},"excerpt":{"anyOf":[{"type":"string","pattern":"^[^\\n\\r]*$","maxLength":2000},{"type":"null"}]},"manualId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"position":{"type":"integer","default":0,"maximum":9007199254740991,"minimum":0},"chapterId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"sourceKey":{"anyOf":[{"type":"string","maxLength":512},{"type":"null"}]},"versionTag":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}]},"visibility":{"enum":["public","internal"],"type":"string","default":"public"},"frontmatter":{"type":"object","default":{},"propertyNames":{"type":"string"},"additionalProperties":{}},"requireReview":{"type":"boolean"}},"additionalProperties":false},"maxItems":25,"minItems":1}},"additionalProperties":false},"AuditListResponse":{"type":"object","required":["items","nextCursor"],"properties":{"items":{"type":"array","items":{"type":"object","required":["id","createdAt","action","entityType","entityId","metadata"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"seq":{"anyOf":[{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},{"type":"null"}]},"action":{"type":"string"},"digest":{"type":"string"},"entityId":{"anyOf":[{"type":"string"},{"type":"null"}]},"metadata":{"type":"string"},"createdAt":{"type":"string"},"entityType":{"anyOf":[{"type":"string"},{"type":"null"}]},"prevDigest":{"type":"string"}},"additionalProperties":false}},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false},"ChangelogListItem":{"type":"object","required":["id","productSlug","productName","entryDate","version","title","deepLink"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"title":{"type":"string"},"version":{"type":"string"},"deepLink":{"type":"string"},"entryDate":{"type":"string"},"productName":{"type":"string"},"productSlug":{"type":"string"}},"additionalProperties":false},"ComplianceResponse":{"type":"object","required":["generatedAt","days","reviewQueue","rejectionFeedback","accessControl","rejectionOverview","forcePend","askAi"],"properties":{"days":{"type":"integer","maximum":9007199254740991,"exclusiveMinimum":0},"askAi":{"type":"object","required":["total","byReason","trend"],"properties":{"total":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"trend":{"type":"array","items":{"type":"object","required":["date","count"],"properties":{"date":{"type":"string"},"count":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991}},"additionalProperties":false}},"byReason":{"type":"array","items":{"type":"object","required":["reason","count"],"properties":{"count":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"reason":{"type":"string"}},"additionalProperties":false}}},"additionalProperties":false},"forcePend":{"type":"object","required":["totalPublishEvents","byStatus","pendingByReason"],"properties":{"byStatus":{"type":"array","items":{"type":"object","required":["status","count"],"properties":{"count":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"status":{"type":"string"}},"additionalProperties":false}},"pendingByReason":{"type":"array","items":{"type":"object","required":["reason","count"],"properties":{"count":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"reason":{"type":"string"}},"additionalProperties":false}},"totalPublishEvents":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991}},"additionalProperties":false},"generatedAt":{"type":"string"},"reviewQueue":{"type":"object","required":["approved","rejected","resolved","approvalRate","pairedResolutions","avgDaysInQueue","medianDaysInQueue"],"properties":{"approved":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"rejected":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"resolved":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"approvalRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"avgDaysInQueue":{"anyOf":[{"type":"number"},{"type":"null"}]},"medianDaysInQueue":{"anyOf":[{"type":"number"},{"type":"null"}]},"pairedResolutions":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991}},"additionalProperties":false},"accessControl":{"type":"object","required":["total","byReason","trend"],"properties":{"total":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"trend":{"type":"array","items":{"type":"object","required":["date","count"],"properties":{"date":{"type":"string"},"count":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991}},"additionalProperties":false}},"byReason":{"type":"array","items":{"type":"object","required":["reason","count"],"properties":{"count":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"reason":{"type":"string"}},"additionalProperties":false}}},"additionalProperties":false},"rejectionFeedback":{"type":"object","required":["totalRejections","withNote","notePresentRate"],"properties":{"withNote":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"notePresentRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"totalRejections":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991}},"additionalProperties":false},"rejectionOverview":{"type":"object","required":["contentRejected","leakRejected","total","byReason","trend"],"properties":{"total":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"trend":{"type":"array","items":{"type":"object","required":["date","count"],"properties":{"date":{"type":"string"},"count":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991}},"additionalProperties":false}},"byReason":{"type":"array","items":{"type":"object","required":["reason","count"],"properties":{"count":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"reason":{"type":"string"}},"additionalProperties":false}},"leakRejected":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"contentRejected":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991}},"additionalProperties":false}},"additionalProperties":false},"SpecUpsertResponse":{"type":"object","required":["productId","apiSpecId","versionId","sourceHash","changed"],"properties":{"changed":{"type":"boolean"},"apiSpecId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"productId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"versionId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"sourceHash":{"type":"string"}},"additionalProperties":false},"TicketListResponse":{"type":"object","required":["items","nextCursor"],"properties":{"items":{"type":"array","items":{"type":"object","required":["id","externalRef","title","status","summary","product","priority","targetDeployDate","deployedAt","updatedAt","isGlobal"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"title":{"type":"string"},"status":{"enum":["open","in_progress","resolved","deployed","closed"],"type":"string"},"product":{"anyOf":[{"type":"string"},{"type":"null"}]},"summary":{"anyOf":[{"type":"string"},{"type":"null"}]},"isGlobal":{"type":"boolean"},"priority":{"anyOf":[{"type":"string"},{"type":"null"}]},"updatedAt":{"type":"string"},"deployedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"externalRef":{"type":"string"},"targetDeployDate":{"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false}},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false},"AuditVerifyResponse":{"type":"object","required":["status","mutationCount","headDigest","headSeq","anchorRegression"],"properties":{"status":{"enum":["connected","broken","empty"],"type":"string"},"headSeq":{"anyOf":[{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},{"type":"null"}]},"firstBreak":{"type":"object","required":["seq","reason","expected","actual"],"properties":{"seq":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"actual":{"type":"string"},"reason":{"enum":["digest_mismatch","broken_link"],"type":"string"},"expected":{"type":"string"}},"additionalProperties":false},"headDigest":{"anyOf":[{"type":"string"},{"type":"null"}]},"mutationCount":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"anchorRegression":{"type":"object","required":["status","reason","baseline"],"properties":{"reason":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"enum":["ok","no-baseline","regressed"],"type":"string"},"baseline":{"anyOf":[{"type":"object","required":["headSeq","headDigest","recordedAt"],"properties":{"headSeq":{"anyOf":[{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},{"type":"null"}]},"headDigest":{"anyOf":[{"type":"string"},{"type":"null"}]},"recordedAt":{"type":"string"}},"additionalProperties":false},{"type":"null"}]}},"additionalProperties":false}},"additionalProperties":false},"BatchUpsertResponse":{"type":"object","required":["results","summary"],"properties":{"results":{"type":"array","items":{"type":"object","required":["index","sourceKey","status"],"properties":{"id":{"type":"string"},"code":{"type":"string"},"index":{"type":"integer","maximum":9007199254740991,"minimum":0},"status":{"enum":["created","updated","rejected","rate_limited","error"],"type":"string"},"message":{"type":"string"},"sourceKey":{"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false}},"summary":{"type":"object","required":["total","created","updated","rejected","rateLimited","errored"],"properties":{"total":{"type":"integer","maximum":9007199254740991,"minimum":0},"created":{"type":"integer","maximum":9007199254740991,"minimum":0},"errored":{"type":"integer","maximum":9007199254740991,"minimum":0},"updated":{"type":"integer","maximum":9007199254740991,"minimum":0},"rejected":{"type":"integer","maximum":9007199254740991,"minimum":0},"rateLimited":{"type":"integer","maximum":9007199254740991,"minimum":0}},"additionalProperties":false}},"additionalProperties":false},"TopicUpsertResponse":{"type":"object","required":["id","manualId","chapterId","slug","title","excerpt","bodyMdx","position","status","visibility","isSensitive","sourceKey","createdByBot"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"slug":{"type":"string"},"title":{"type":"string"},"status":{"enum":["draft","pending","published"],"type":"string"},"bodyMdx":{"type":"string"},"excerpt":{"anyOf":[{"type":"string"},{"type":"null"}]},"manualId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"position":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"chapterId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"sourceKey":{"anyOf":[{"type":"string"},{"type":"null"}]},"visibility":{"enum":["public","internal"],"type":"string"},"isSensitive":{"type":"boolean"},"createdByBot":{"type":"boolean"}},"additionalProperties":false},"PlatformMemberCreate":{"type":"object","required":["memberProductId"],"properties":{"status":{"enum":["available","coming_soon"],"type":"string","default":"coming_soon"},"position":{"type":"integer","maximum":9007199254740991,"minimum":0},"memberProductId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"additionalProperties":false},"PlatformMemberUpdate":{"type":"object","properties":{"status":{"enum":["available","coming_soon"],"type":"string"},"position":{"type":"integer","maximum":9007199254740991,"minimum":0}},"additionalProperties":false},"TicketUpsertResponse":{"type":"object","required":["id","created"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"created":{"type":"boolean"}},"additionalProperties":false},"TopicDetailWithReview":{"type":"object","required":["id","manualId","chapterId","slug","title","excerpt","position","status","visibility","sourceKey","createdByBot","updatedAt","bodyMdx","lastReviewedAt","reviewNote"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"slug":{"type":"string"},"title":{"type":"string"},"status":{"enum":["draft","pending","published"],"type":"string"},"bodyMdx":{"type":"string"},"excerpt":{"anyOf":[{"type":"string"},{"type":"null"}]},"manualId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"position":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"chapterId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"sourceKey":{"anyOf":[{"type":"string"},{"type":"null"}]},"updatedAt":{"type":"string"},"reviewNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"visibility":{"enum":["public","internal"],"type":"string"},"createdByBot":{"type":"boolean"},"lastReviewedAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false},"PlatformMemberResponse":{"type":"object","required":["id","platformId","memberProductId","memberSlug","memberName","position","status","createdAt"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"enum":["available","coming_soon"],"type":"string"},"position":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"createdAt":{"type":"string"},"memberName":{"type":"string"},"memberSlug":{"type":"string"},"platformId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"memberProductId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"additionalProperties":false},"ChangelogCreateResponse":{"type":"object","required":["id","deepLink"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"deepLink":{"type":"string"}},"additionalProperties":false},"SubmissionsListResponse":{"type":"object","required":["items","limit"],"properties":{"items":{"type":"array","items":{"type":"object","required":["manualId","sourceKey","slug","title","status","visibility","updatedAt"],"properties":{"slug":{"type":"string"},"title":{"type":"string"},"status":{"enum":["draft","pending","published"],"type":"string"},"manualId":{"type":"string"},"sourceKey":{"anyOf":[{"type":"string"},{"type":"null"}]},"updatedAt":{"type":"string"},"visibility":{"enum":["public","internal"],"type":"string"}},"additionalProperties":false}},"limit":{"type":"integer","maximum":9007199254740991,"exclusiveMinimum":0}},"additionalProperties":false},"AnalyticsSummaryResponse":{"type":"object","required":["generatedAt","limit","days","topics","trendingTopics","trends","searchGaps","recentComments","staleTopics"],"properties":{"days":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"limit":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"topics":{"type":"array","items":{"type":"object","required":["topicId","topicSlug","manualSlug","productSlug","title","helpful","totalVotes","helpfulRatio","views"],"properties":{"title":{"type":"string"},"views":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"helpful":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"topicId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"topicSlug":{"type":"string"},"manualSlug":{"type":"string"},"totalVotes":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"productSlug":{"type":"string"},"helpfulRatio":{"anyOf":[{"type":"number"},{"type":"null"}]}},"additionalProperties":false}},"trends":{"type":"array","items":{"type":"object","required":["date","views"],"properties":{"date":{"type":"string"},"views":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991}},"additionalProperties":false}},"searchGaps":{"type":"array","items":{"type":"object","required":["query","occurrences"],"properties":{"query":{"type":"string"},"occurrences":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991}},"additionalProperties":false}},"generatedAt":{"type":"string"},"staleTopics":{"type":"array","items":{"type":"object","required":["topicId","topicSlug","manualSlug","productSlug","title","updatedAt","lastReviewedAt"],"properties":{"title":{"type":"string"},"topicId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"topicSlug":{"type":"string"},"updatedAt":{"type":"string"},"manualSlug":{"type":"string"},"productSlug":{"type":"string"},"lastReviewedAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false}},"recentComments":{"type":"array","items":{"type":"object","required":["topicId","topicSlug","manualSlug","productSlug","title","helpful","comment","createdAt"],"properties":{"title":{"type":"string"},"comment":{"type":"string"},"helpful":{"type":"boolean"},"topicId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"createdAt":{"type":"string"},"topicSlug":{"type":"string"},"manualSlug":{"type":"string"},"productSlug":{"type":"string"}},"additionalProperties":false}},"trendingTopics":{"type":"array","items":{"type":"object","required":["topicId","topicSlug","manualSlug","productSlug","title","views"],"properties":{"title":{"type":"string"},"views":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"topicId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"topicSlug":{"type":"string"},"manualSlug":{"type":"string"},"productSlug":{"type":"string"}},"additionalProperties":false}}},"additionalProperties":false},"SubmissionStatusResponse":{"type":"object","required":["found"],"properties":{"id":{"type":"string"},"slug":{"type":"string"},"found":{"type":"boolean"},"title":{"type":"string"},"status":{"enum":["draft","pending","published"],"type":"string"},"rejected":{"type":"boolean"},"visibility":{"enum":["public","internal"],"type":"string"},"rejectReason":{"type":"string"}},"additionalProperties":false},"TicketStatusSummaryResponse":{"type":"object","required":["total","open","byStatus"],"properties":{"open":{"type":"integer","maximum":9007199254740991,"minimum":0},"total":{"type":"integer","maximum":9007199254740991,"minimum":0},"byStatus":{"type":"array","items":{"type":"object","required":["status","count"],"properties":{"count":{"type":"integer","maximum":9007199254740991,"minimum":0},"status":{"enum":["open","in_progress","resolved","deployed","closed"],"type":"string"}},"additionalProperties":false}}},"additionalProperties":false},"AnalyticsTopicDrilldownResponse":{"type":"object","required":["generatedAt","topicId","days","limit","totalViews","helpful","totalVotes","helpfulRatio","trend","recentComments"],"properties":{"days":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"limit":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"trend":{"type":"array","items":{"type":"object","required":["date","views"],"properties":{"date":{"type":"string"},"views":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991}},"additionalProperties":false}},"helpful":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"topicId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"totalViews":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"totalVotes":{"type":"integer","maximum":9007199254740991,"minimum":-9007199254740991},"generatedAt":{"type":"string"},"helpfulRatio":{"anyOf":[{"type":"number"},{"type":"null"}]},"recentComments":{"type":"array","items":{"type":"object","required":["topicId","topicSlug","manualSlug","productSlug","title","helpful","comment","createdAt"],"properties":{"title":{"type":"string"},"comment":{"type":"string"},"helpful":{"type":"boolean"},"topicId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"createdAt":{"type":"string"},"topicSlug":{"type":"string"},"manualSlug":{"type":"string"},"productSlug":{"type":"string"}},"additionalProperties":false}}},"additionalProperties":false}},"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Hank-issued API token. The token must carry the `hank-docs` scope (operator-only routes additionally require operator privilege)."}}},"x-errorCatalog":{"forbidden":{"status":403,"meaning":"A valid token lacking the required scope / admin / operator privilege (authenticated, denied)."},"not_found":{"status":404,"meaning":"The addressed resource does not exist."},"rate_limited":{"status":429,"meaning":"The per-identity write rate limit was exceeded. Back off and retry after the Retry-After header."},"unauthorized":{"status":401,"meaning":"No, malformed, or unrecognized bearer token (unauthenticated)."},"duplicate_slug":{"status":400,"meaning":"A unique field (a slug, or a topic source key) collides with an existing row."},"unknown_parent":{"status":400,"meaning":"A referenced parent (product / manual / chapter) does not exist or was concurrently deleted."},"invalid_request":{"status":400,"meaning":"The request body, query, or path parameter failed validation (the catch-all bad-input code)."},"content_rejected":{"status":400,"meaning":"The submitted CONTENT failed the publish pipeline (leak/PHI scan, MDX compile, link/alt gate, or policy gate). Fix the content, not the request shape."},"duplicate_member":{"status":400,"meaning":"The product is already a member of this platform (the platform+member pair is unique)."},"payload_too_large":{"status":413,"meaning":"The request body exceeds the configured size cap."},"idempotency_in_progress":{"status":409,"meaning":"A request with the same Idempotency-Key is still in progress; retry after Retry-After."},"invalid_idempotency_key":{"status":400,"meaning":"The Idempotency-Key header is present but malformed (empty or over the length cap)."},"idempotency_key_conflict":{"status":422,"meaning":"The Idempotency-Key was already used for a request with a DIFFERENT body (no safe replay)."}}}