Point a Zendesk Support client at https://zendesk.sandboxapis.dev — paths are /api/v2/… exactly as on a real <subdomain>.zendesk.com, and the .json suffix Zendesk's own clients append is accepted too. node-zendesk takes endpointUri; zenpy takes url=; the Ruby client takes config.url. Auth is HTTP Basic (any value is accepted here). READ THIS BEFORE YOU PLAN A WALK: this host's surface arrived across TWO generations, so which host you point at decides what answers. The TICKET QUEUE — tickets with their comments, audits and metrics, the one user space (agents/admins and end users, told apart by 'role'), organizations, groups and memberships, requests, satisfaction ratings, tags, search and the incremental exports — ships with hello-14. The DESK CONFIGURATION — macros, views, triggers with revision history, automations, SLA policies, brands, ticket fields and forms, the suspended queue and its skips, saved searches, email notifications, attachments, job statuses and the admin audit_logs — ships with hello-15. The LIVE host rides hello-19, which inherits both, and answers all of it — and so does the newest pin, zendesk-v2-g11, frozen on hello-16. The zendesk-v2-g10 pin rides hello-15 and answers all of it as well. The zendesk-v2-g9 pin rides hello-14: the queue answers, the configuration rows answer a 404 naming hello-15. The zendesk-v2-g8 pin rides hello-13, older than the desk itself: every desk endpoint answers a 404 naming hello-14 and the locale endpoints keep working. Never an empty array pretending the org has no desk, on any of those five. A pin never gains a later generation — its bytes never move. WHAT IS UNCOVERED ON EVERY GENERATION: the add-on surfaces — custom objects, skill-based routing, IT asset management, task lists, dynamic content, targets and the sharing agreements — each answering an explicit coverage 404. When the desk answers: both pagination grammars work and you get the one you ask for ('page'+'per_page' for the offset envelope, 'page[size]'+'page[after]' for the cursor one). Check https://sandboxapis.dev/providers/zendesk for the row-by-row picture.
Coverage badge
Deep332/342 · 97%
The share of read rows with a final answer — served and verified, a deviation, retired upstream, or a reviewed empty/refusal. Computed in the coverage manifest, copied here.
zendesk.sandboxapis.devServed & verified
281 / 82%
Answering with real universe data, each response checked against Zendesk's published spec by the conformance suite on this build. 7 of them are marked a deviation — served faithfully, but failing the vendored spec.
The full read API
342
Every read surface Zendesk publishes, deferred long tail included, minus the rows excluded by policy (1). Writes are out of scope: this universe is read-only.
Not served yet
61
Each returns an explicit, provider-shaped coverage error naming the gap — never invented data.
01 / The swap
No SDK of ours, no shim, no recorded fixtures. The same client library you already use, one environment variable different.
curl "https://zendesk.sandboxapis.dev/api/v2/locales.json"Verified drop-in clients
No client library is version-pinned against Zendesk yet, so this page claims none. What is asserted is the wire: every response above is validated against Zendesk's own published spec by the conformance suite. Client pins live in coverage/client-pins.yaml and are added as each SDK joins the suite.
02 / Coverage by family
All 343 rows the coverage manifest carries for Zendesk, deferred long tail included and nothing capped. Open a family, or filter by path to find the exact endpoint your client calls.
Status — what a conformance test found
Mode — what kind of answer a row gets
A row with no mode shown has not been judged yet. Modes are the manifest's own words, from coverage/MODES.yaml; every empty and refuse carries a written reason and a review date before it counts as final.
Held — buildable, deliberately not built yet
held is a label, not a mode and not a status. A held row is one somebody looked at, judged buildable, and left with the blocker named — so it is not covered, counts against the ratio above exactly like any other unbuilt row, and still answers the coverage 404. It buys nothing; it only tells you why.
Badge — where Deep starts
REST + GraphQL + git rows that are not `excluded`. Write operations are NOT rows (DECISIONS 2026-09-01 decision 9): they are counted in meta.write_operations and never enter this ratio.
343 read surfaces in 41 families
SERVED 2026-09-07: `listSupportAutomations()` + `conditionsFor()` + `actionsFor()`. Every one is asserted to carry at least one TIME condition, which is what makes an automation an automation. DOCUMENT SELF-CONTRADICTION, declared: `AutomationObject.actions[].value` is typed `string` while the same document's `TriggerActionObject` types the same field `oneOf[string,integer,array]`, and Zendesk's notification actions really do carry the recipient/subject/body array. The response is right and the document is wrong, so the rows whose response actually contains such an action sync to `deviation` rather than to green — which is two of these four today, and would be all four if a fifth automation started notifying
SERVED 2026-09-07: `listSupportAutomations()` + `conditionsFor()` + `actionsFor()`. Every one is asserted to carry at least one TIME condition, which is what makes an automation an automation. DOCUMENT SELF-CONTRADICTION, declared: `AutomationObject.actions[].value` is typed `string` while the same document's `TriggerActionObject` types the same field `oneOf[string,integer,array]`, and Zendesk's notification actions really do carry the recipient/subject/body array. The response is right and the document is wrong, so the rows whose response actually contains such an action sync to `deviation` rather than to green — which is two of these four today, and would be all four if a fifth automation started notifying
SERVED 2026-09-07: `listSupportMacros()` + `actionsFor(macro)`, with the four `usage_*` counters COUNTED from `macroUsageSince()` over the applications canon derived off the tickets' own audit trail — so `/macros/most_used` and the counters cannot disagree, and both name tickets this host serves. A canned comment expands into Zendesk's own TWO actions (`comment_value` + `comment_mode_is_public`). `categories` is canon's `category_name` — the folder the two-level title was composed from, not a re-parse of it
SERVED 2026-09-07: `listSupportMacros()` + `actionsFor(macro)`, with the four `usage_*` counters COUNTED from `macroUsageSince()` over the applications canon derived off the tickets' own audit trail — so `/macros/most_used` and the counters cannot disagree, and both name tickets this host serves. A canned comment expands into Zendesk's own TWO actions (`comment_value` + `comment_mode_is_public`). `categories` is canon's `category_name` — the folder the two-level title was composed from, not a re-parse of it
SERVED 2026-09-07: `actionsFor(macro)` projected into `MacroApplyTicketResponse` — the changes the macro WOULD make, against no ticket, so the result names none
SERVED 2026-09-07: `attachmentsForMacro(macro)`. Two macros carry a file since PR C (#384) — which matters, because a single one made the by-id row unfalsifiable: any id that resolved was the only id there was. A macro with no file is an honest empty list; an unknown macro is the 404
SERVED 2026-09-07: the action grammar COMPUTED from `actionsFor()` over the account's own eleven macros rather than from a hand-written table — conformance asserts the join in BOTH directions, so no macro can use a subject the definitions omit and no definition can advertise one no macro uses
SERVED 2026-09-07: `listSupportMacros()` + `actionsFor(macro)`, with the four `usage_*` counters COUNTED from `macroUsageSince()` over the applications canon derived off the tickets' own audit trail — so `/macros/most_used` and the counters cannot disagree, and both name tickets this host serves. A canned comment expands into Zendesk's own TWO actions (`comment_value` + `comment_mode_is_public`). `categories` is canon's `category_name` — the folder the two-level title was composed from, not a re-parse of it
SERVED 2026-09-07: `listAttachments()` filtered to the macro-attached file. `MacroAttachmentObject` is a DIFFERENT object from `AttachmentObject` — six fields, `filename` not `file_name` — and its `content_url` addresses the `/content` row below, which this host really serves
SERVED 2026-09-07: the artifact's own BYTES (`AttachmentRow.body`), with the file's content type from canon's `ATTACHMENT_CONTENT_TYPE` and a `content-disposition` naming it. The conformance entry re-hashes what was served and compares it to the sha256 the compiler measured
SERVED 2026-09-07: `macroCategories()` — the DISTINCT `category_name` column, which is what Zendesk's category list is (it has no macro-category object and derives the whole list from the `Category::Title` prefix a macro's title carries). Reading the column rather than re-splitting the title keeps one derivation in the layer that owns it, so this row and the `categories` field on every macro cannot disagree. A PLAIN NON-EMPTY DERIVE: the first cut of this wave computed an empty list and flagged a possible `empty` re-ruling, and PR C (#384) gave every macro a folder, so the flag is withdrawn
SERVED 2026-09-07: the same grammar as `/macros/actions` under the document's nested spelling; a test binds the two byte for byte
SERVED 2026-09-07: `macroUsageSince(anchor - 30d, anchor)` ranked, projected through `MostUsedMacroObject`'s smaller shape. The window ends at the ARTIFACT'S ANCHOR rather than the wall clock, so a pinned snapshot answers the same ranking forever (invariant #1)
SERVED 2026-09-07: `listSupportMacros()` + `actionsFor(macro)`, with the four `usage_*` counters COUNTED from `macroUsageSince()` over the applications canon derived off the tickets' own audit trail — so `/macros/most_used` and the counters cannot disagree, and both name tickets this host serves. A canned comment expands into Zendesk's own TWO actions (`comment_value` + `comment_mode_is_public`). `categories` is canon's `category_name` — the folder the two-level title was composed from, not a re-parse of it
SERVED 2026-09-07: `listSupportMacros()` + `actionsFor(macro)`, with the four `usage_*` counters COUNTED from `macroUsageSince()` over the applications canon derived off the tickets' own audit trail — so `/macros/most_used` and the counters cannot disagree, and both name tickets this host serves. A canned comment expands into Zendesk's own TWO actions (`comment_value` + `comment_mode_is_public`). `categories` is canon's `category_name` — the folder the two-level title was composed from, not a re-parse of it
SERVED 2026-09-07: the same projection against a real ticket from `ticketByZendeskId()`, so the result carries that ticket's id and url. A GET that mutates nothing, which is why it is a read upstream too
SERVED 2026-09-07: `listTriggerCategories()`. The one row on this host whose pagination is not the caller's choice — the operation declares only the cursor `page` object, so the offset dialect is not on offer. The cursor keys are OMITTED at the ends rather than nulled, because `Pagination` types all four as plain strings with no `nullable`
SERVED 2026-09-07: one category from the same accessor, with `?include=rule_counts` counting the triggers this host serves in it
SERVED 2026-09-07: `listSupportTriggers()` + `conditionsFor()` + `actionsFor()`, in EXECUTION order (`position`), each naming a category `/trigger_categories` serves. `category_id` is the STRING the document declares
SERVED 2026-09-07: `listSupportTriggers()` + `conditionsFor()` + `actionsFor()`, in EXECUTION order (`position`), each naming a category `/trigger_categories` serves. `category_id` is the STRING the document declares
SERVED 2026-09-07: `revisionsForTrigger(trigger)`, newest first, each carrying a SNAPSHOT from the revision's own row and a `diff` COMPUTED against the previous one — canon's schema says a diff is a pure function of two adjacent rows, so storing it would have been a second truth that drifts. The first revision carries no diff, because there is nothing to diff it against
SERVED 2026-09-07: one revision from the same accessor; the newest one's snapshot is asserted to equal the trigger's current definition
SERVED 2026-09-07: `listSupportTriggers()` + `conditionsFor()` + `actionsFor()`, in EXECUTION order (`position`), each naming a category `/trigger_categories` serves. `category_id` is the STRING the document declares
SERVED 2026-09-07: the trigger grammar COMPUTED from the account's own triggers, conditions and actions alike, with a human title beside every wire operator — which is what lets a caller reading `operator: "value"` find out on the same host that it means "changed to"
SERVED 2026-09-07: `listSupportTriggers()` + `conditionsFor()` + `actionsFor()`, in EXECUTION order (`position`), each naming a category `/trigger_categories` serves. `category_id` is the STRING the document declares
SERVED 2026-09-07: `listSupportAutomations()` + `conditionsFor()` + `actionsFor()`. Every one is asserted to carry at least one TIME condition, which is what makes an automation an automation. DOCUMENT SELF-CONTRADICTION, declared: `AutomationObject.actions[].value` is typed `string` while the same document's `TriggerActionObject` types the same field `oneOf[string,integer,array]`, and Zendesk's notification actions really do carry the recipient/subject/body array. The response is right and the document is wrong, so the rows whose response actually contains such an action sync to `deviation` rather than to green — which is two of these four today, and would be all four if a fifth automation started notifying
SERVED 2026-09-07: `listSupportAutomations()` + `conditionsFor()` + `actionsFor()`. Every one is asserted to carry at least one TIME condition, which is what makes an automation an automation. DOCUMENT SELF-CONTRADICTION, declared: `AutomationObject.actions[].value` is typed `string` while the same document's `TriggerActionObject` types the same field `oneOf[string,integer,array]`, and Zendesk's notification actions really do carry the recipient/subject/body array. The response is right and the document is wrong, so the rows whose response actually contains such an action sync to `deviation` rather than to green — which is two of these four today, and would be all four if a fifth automation started notifying
generate — CANON-BLOCKED (re-scoped 2026-09-07): `SupportTrigger` SHIPPED with hello-15 and this row is now blocked on ONE gap rather than two — the custom-object entity itself, which the whole `/custom_objects` family on this provider is still unclassified for. When a custom object exists, this row is the `/triggers` implementation over it
generate — CANON-BLOCKED (re-scoped 2026-09-07): `SupportTrigger` SHIPPED with hello-15 and this row is now blocked on ONE gap rather than two — the custom-object entity itself, which the whole `/custom_objects` family on this provider is still unclassified for. When a custom object exists, this row is the `/triggers` implementation over it
generate — CANON-BLOCKED (re-scoped 2026-09-07): `SupportTrigger` SHIPPED with hello-15 and this row is now blocked on ONE gap rather than two — the custom-object entity itself, which the whole `/custom_objects` family on this provider is still unclassified for. When a custom object exists, this row is the `/triggers` implementation over it
generate — CANON-BLOCKED (re-scoped 2026-09-07): `SupportTrigger` SHIPPED with hello-15 and this row is now blocked on ONE gap rather than two — the custom-object entity itself, which the whole `/custom_objects` family on this provider is still unclassified for. When a custom object exists, this row is the `/triggers` implementation over it
generate — CANON-BLOCKED (re-scoped 2026-09-07): `SupportTrigger` SHIPPED with hello-15 and this row is now blocked on ONE gap rather than two — the custom-object entity itself, which the whole `/custom_objects` family on this provider is still unclassified for. When a custom object exists, this row is the `/triggers` implementation over it
generate — RE-SCOPED 2026-09-07, and it is no longer canon that blocks it: `SupportMacro` shipped with hello-15 and eleven macros are served. `ListMacrosByGroup` returns macros grouped by AGENT GROUP, and every macro in this account is either unrestricted or restricted to one group — so the grouping this row expresses is derivable. It is left uncovered because the document publishes no schema for the response beyond an untyped object and no example of the grouping key, and guessing the key would be inventing the one thing the row is about. Needs a CAPTURE. It is also this wave's shadowing finding: the literal `groups` sits exactly where `/macros/{macro_id}` puts a parameter, and a served test now asserts it reaches the coverage 404 rather than being reported as a macro that does not exist
generate — PARTLY UNBLOCKED 2026-09-07, and still blocked on the half that matters: the `count` now follows from `listSupportTriggers()`, which this host serves — but the `limit` is a property of the account's Zendesk PLAN, and nothing in this repository records a plan for olympus-labs. Serving `{count, limit}` with an invented ceiling would be this replica asserting a price tier. Needs a CAPTURE or a founder ruling, not a canon entity. The row is deliberately left uncovered and a served test asserts it reaches the coverage 404 rather than being swallowed by `/triggers/{trigger_id}`
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY: nothing in this universe was ever deleted, which is a statement about the account rather than about the artifact (the generation gap covers the other case)
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
TicketFieldChange — reader.ticketChangesFor(ticket); the canon's own doc calls these Zendesk Ticket Audits events. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): the audits assembled from TicketComment and TicketFieldChange, in the document's own third envelope (top-level cursors); the four cursor keys are OMITTED rather than null at the ends, because this response types them as plain `string`
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
TicketFieldChange — reader.ticketChangesFor(ticket); the canon's own doc calls these Zendesk Ticket Audits events. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
TicketFieldChange — reader.ticketChangesFor(ticket); the canon's own doc calls these Zendesk Ticket Audits events. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
TicketFieldChange — reader.ticketChangesFor(ticket); the canon's own doc calls these Zendesk Ticket Audits events. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY, and asserted to AGREE with the ticket object's own `collaborator_ids: []`
TicketComment — reader.commentsFor(ticket); canon carries `publicComment`, which is Zendesk's `public` verbatim. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
TicketComment — reader.commentsFor(ticket); canon carries `publicComment`, which is Zendesk's `public` verbatim. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY, and asserted to AGREE with the ticket object's own `email_cc_ids: []`
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY, and asserted to AGREE with the ticket object's own `follower_ids: []`
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY, and asserted to AGREE with the ticket object's own `has_incidents: false` — canon links no ticket to a problem
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): `jira_issue_ids` carries canon's `SupportTicket.issue`, the same tracker row Jira, Linear, GitHub and GitLab serve
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): the conversation id is canon's `SupportTicket.channel_ref` — the same Slack/Teams channel those hosts serve, so this is a real cross-provider join rather than a minted id
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY, and it AGREES with every ticket's own `collaborator_ids: []` — canon puts nobody on a ticket but its requester and its assignee
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): 0, agreeing with the empty collection beside it
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY, agreeing with every ticket's own `follower_ids: []`
SupportTicket — reader.listSupportTickets() / supportTicketByNumber(); the canon's own `number` is Zendesk's case number, assigned in arrival order. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SERVED 2026-09-07: `listTicketSkips()` / `skipsForTicket()` / `skipsForAgent()`, each carrying the whole skipped TICKET the way upstream does. The skipping user is always an agent — skipping is a Play-mode act — and an end user's list is an honest empty rather than a 404
SERVED 2026-09-07, AMENDED 2026-09-12: `listContentPins()` joined to `listHelpCenterArticles()`. `content_type` is `help_center_article` rather than the document's single `external_content` example, because what these agents pinned is an article in this account's OWN help centre — which hello-15 gave it, and which the brand row now says it has. The 2026-09-12 re-pin (coverage/provider-pins.yaml, zendesk.rest) brought an upstream CORRECTION to `TicketContentPin`: `account_id` and `ticket_id` are now `type: integer` with the examples `124125123` and `5`, where the 2026-09-04 document typed every field of the schema as a string. This row served four strings and now serves two strings (`id`, `content_id` — ULIDs upstream) and two integers; `account_id` mints in a new `account` id band and `ticket_id` is the number `/api/v2/tickets/{id}` is addressed by
SERVED 2026-09-07: `listTicketSkips()` / `skipsForTicket()` / `skipsForAgent()`, each carrying the whole skipped TICKET the way upstream does. The skipping user is always an agent — skipping is a Play-mode act — and an end user's list is an honest empty rather than a 404
SERVED 2026-09-07: `listTicketSkips()` / `skipsForTicket()` / `skipsForAgent()`, each carrying the whole skipped TICKET the way upstream does. The skipping user is always an agent — skipping is a Play-mode act — and an end user's list is an honest empty rather than a 404
no custom object type was ever defined on this account; Zendesk's own answer for an account with none is `{"custom_objects": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
no custom object type was ever defined on this account; Zendesk's own answer for an account with none is `{"count": 0}` at 200. `limit` is OMITTED rather than emitted: the account's plan cap is a number this replica has no source for, and inventing one is the placeholder invariant #4 forbids. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
no custom object type exists, so no record can; Zendesk's own answer for an account with none is `{"count": 0}` at 200. `limit` is OMITTED rather than emitted: the account's plan cap is a number this replica has no source for, and inventing one is the placeholder invariant #4 forbids. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
lookup relationships point at custom object types, and none is defined; Zendesk's own answer for an account with none is `{"definitions": {"conditions_all": [], "conditions_any": []}}` at 200 — the document's own shape with both lists empty rather than `{"definitions": {}}`, so a client that reads `definitions.conditions_all` gets an array. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — lookup relationships point at custom object types, and none is defined, so no lookup relationship field id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no custom object type was ever defined on this account, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no custom object type exists, so there is no permission set for one, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no custom object type exists, so there is no permission set for one, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no custom object type exists, so there is no permission set for one, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no custom object type exists, so it has no fields, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no custom object type exists, so it has no fields, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no custom object type exists, so it has no fields, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no custom object type exists, so there is no permission set for one, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no custom object type exists, so there is no permission set for one, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no custom object type exists, so no record can, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no custom object type exists, so no record can, so no record id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no custom object record exists to attach anything to, so no record id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no custom object record exists to attach anything to, so no record id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no custom object type exists, so no record can, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no custom object type exists, so no record can, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no custom object type exists, so no record can, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no custom object type exists, so no record can, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no custom object type exists, so no record can, so no object key resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/custom_objects` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY: nothing in this universe was ever deleted
CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): the ENTITY 404 for every id, which is the correct answer for a record that does not exist and the one row-class in this wave whose conformance check asserts the 404 contract rather than a 200 schema (the document publishes no schema for its 404)
CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): 0, agreeing with the empty collection beside it
Contact — the email identity Zendesk models as a separate record is a field on the canon row. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Contact — the email identity Zendesk models as a separate record is a field on the canon row. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY: nobody in this universe asked to be forgotten
CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY: the four entitlements are seats in products (Chat, Explore, Guide, Talk) this account does not license
Contact — the email identity Zendesk models as a separate record is a field on the canon row. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Contact — the email identity Zendesk models as a separate record is a field on the canon row. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): the account OWNER (the first admin in canonical id order), because this host has no signed-in principal and an invented one would put somebody on the roster who is not on it
CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): an EMPTY settings object: every property the document declares under `settings` is a UI preference a human sets by clicking in the Zendesk web app, and nobody in this universe has ever opened it
CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Contact -> Company — reader.contactsFor(company). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Contact -> Company — reader.contactsFor(company). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): the ENTITY 404 for every id: nothing in this universe was ever merged, and the document publishes no schema for this operation's 404, so conformance asserts the captured RecordNotFound contract instead
Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY: nothing in this universe was ever merged
Contact -> Company — reader.contactsFor(company). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Contact -> Company — reader.contactsFor(company). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Contact -> Company — reader.contactsFor(company). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Contact -> Company, the same join Zendesk exposes as a subscription. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Contact -> Company, the same join Zendesk exposes as a subscription. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Contact -> Company, the same join Zendesk exposes as a subscription. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
Contact -> Company, the same join Zendesk exposes as a subscription. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
the incremental export of a routing surface that has no records; Zendesk's own answer for an account with none is `{"attribute_values": [], "count": 0, "end_time": <the universe's own anchor>, "next_page": null}` at 200 — the anchor rather than the wall clock, because a pinned host whose incremental cursor moved every day would not be pinned. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
the incremental export of a routing surface that has no records; Zendesk's own answer for an account with none is `{"attributes": [], "count": 0, "end_time": <the universe's own anchor>, "next_page": null}` at 200 — the anchor rather than the wall clock, because a pinned host whose incremental cursor moved every day would not be pinned. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
the incremental export of a routing surface that has no records; Zendesk's own answer for an account with none is `{"instance_values": [], "count": 0, "end_time": <the universe's own anchor>, "next_page": null}` at 200 — the anchor rather than the wall clock, because a pinned host whose incremental cursor moved every day would not be pinned. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
omnichannel routing is an add-on this account has not enabled; no queue was ever defined; Zendesk's own answer for an account with none is `{"queues": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
omnichannel routing is an add-on this account has not enabled; no queue was ever defined; Zendesk's own answer for an account with none is `{"definitions": {"conditions_all": [], "conditions_any": []}}` at 200 — the document's own shape with both lists empty rather than `{"definitions": {}}`, so a client that reads `definitions.conditions_all` gets an array. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
skill-based routing is an add-on this account has not enabled, so its attributes, definitions and per-ticket requirements are all empty collections; Zendesk's own answer for an account with none is `{"attribute_values": []}` at 200 for a parent this universe really has, and its ordinary entity 404 for one it does not — a cheerful empty for an id nobody has would contradict the by-id route beside it. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
skill-based routing is an add-on this account has not enabled, so its attributes, definitions and per-ticket requirements are all empty collections; Zendesk's own answer for an account with none is `{"instance_values": [], "count": 0, "next_page": null, "previous_page": null}` at 200, and the cursor envelope when the caller asks for that dialect. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
skill-based routing is an add-on this account has not enabled, so its attributes, definitions and per-ticket requirements are all empty collections; Zendesk's own answer for an account with none is `{"attributes": [], "count": 0, "next_page": null, "previous_page": null}` at 200, and the cursor envelope when the caller asks for that dialect. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
skill-based routing is an add-on this account has not enabled, so its attributes, definitions and per-ticket requirements are all empty collections; Zendesk's own answer for an account with none is `{"definitions": {"conditions_all": [], "conditions_any": []}}` at 200 — the document's own shape with both lists empty rather than `{"definitions": {}}`, so a client that reads `definitions.conditions_all` gets an array. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
skill-based routing is an add-on this account has not enabled, so its attributes, definitions and per-ticket requirements are all empty collections; Zendesk's own answer for an account with none is `{"fulfilled_ticket_ids": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
skill-based routing is an add-on this account has not enabled, so its attributes, definitions and per-ticket requirements are all empty collections; Zendesk's own answer for an account with none is `{"attribute_values": []}` at 200 for a parent this universe really has, and its ordinary entity 404 for one it does not — a cheerful empty for an id nobody has would contradict the by-id route beside it. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — omnichannel routing is an add-on this account has not enabled; no queue was ever defined, so no queue id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/queues` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — skill-based routing is an add-on this account has not enabled, so its attributes, definitions and per-ticket requirements are all empty collections, so no routing attribute id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/routing/attributes` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — skill-based routing is an add-on this account has not enabled, so its attributes, definitions and per-ticket requirements are all empty collections, so no routing attribute id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/routing/attributes` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — skill-based routing is an add-on this account has not enabled, so its attributes, definitions and per-ticket requirements are all empty collections, so no routing attribute id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/routing/attributes` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
SERVED 2026-09-07: the length of the ticket set the view's own conditions select, and equal to the length of `/views/{id}/tickets`. `fresh: true` is derived: the count is computed per request and there is no cache behind it to be stale
SERVED 2026-09-07: the view's definition plus one ROW per selected ticket, carrying a cell for every column the view displays — the same tickets as `/views/{id}/tickets`, rendered through the view's own columns
SERVED 2026-09-07: the export JOB's status, which is what this operation returns upstream. This replica queues nothing, so the view is named and no export id is invented for a job that does not exist
SERVED 2026-09-07: the selected tickets, byte-identical to what `/api/v2/tickets/{id}` serves for each of them
SERVED 2026-09-07: the active views from `listSupportViews()` with the definition halves left off — compact means fewer FIELDS, which a test pins in both directions
SERVED 2026-09-07: the number of `listSupportViews()` rows in the shared `{count: {value, refreshed_at}}` envelope, stamped with the artifact's anchor rather than the wall clock
SERVED 2026-09-07: the per-view ticket counts for an `?ids=` list, each equal to what `/views/{id}/count` answers on its own — asserted, not assumed
SERVED 2026-09-07: the view grammar COMPUTED from `conditionsFor()` over the account's own views, plus the columns those views display — every sortable and groupable is asserted to be a column some view really shows
SERVED 2026-09-07: a POST-as-READ (app.ts `POST_AS_READ`): the caller's own condition set evaluated by the SAME evaluator a saved view's is, so posting a view's own conditions counts exactly what that view counts
SERVED 2026-09-07: `listSupportViews()` + `conditionsFor(view)`. The DEFINITION half is canon's (title, conditions, columns, sort); the EXECUTION half is computed at read time by evaluating those conditions against `listSupportTickets()` — one evaluator shared with `/views/{id}/count` and `POST /views/preview/count`, so the three can never disagree about which tickets are in a view. DOCUMENT SELF-CONTRADICTION, declared: `ViewObject.restriction` is typed `object` while its own description says "Is null when everyone in the account can access it" and the sibling `TriggerObject.restriction` IS declared nullable — so a view nobody restricted serves the null the description names and the row syncs to `deviation`
SERVED 2026-09-07: `listSupportViews()` + `conditionsFor(view)`. The DEFINITION half is canon's (title, conditions, columns, sort); the EXECUTION half is computed at read time by evaluating those conditions against `listSupportTickets()` — one evaluator shared with `/views/{id}/count` and `POST /views/preview/count`, so the three can never disagree about which tickets are in a view. DOCUMENT SELF-CONTRADICTION, declared: `ViewObject.restriction` is typed `object` while its own description says "Is null when everyone in the account can access it" and the sibling `TriggerObject.restriction` IS declared nullable — so a view nobody restricted serves the null the description names and the row syncs to `deviation`
SERVED 2026-09-07: `listSupportViews()` + `conditionsFor(view)`. The DEFINITION half is canon's (title, conditions, columns, sort); the EXECUTION half is computed at read time by evaluating those conditions against `listSupportTickets()` — one evaluator shared with `/views/{id}/count` and `POST /views/preview/count`, so the three can never disagree about which tickets are in a view. DOCUMENT SELF-CONTRADICTION, declared: `ViewObject.restriction` is typed `object` while its own description says "Is null when everyone in the account can access it" and the sibling `TriggerObject.restriction` IS declared nullable — so a view nobody restricted serves the null the description names and the row syncs to `deviation`
SERVED 2026-09-07: `listSupportViews()` + `conditionsFor(view)`. The DEFINITION half is canon's (title, conditions, columns, sort); the EXECUTION half is computed at read time by evaluating those conditions against `listSupportTickets()` — one evaluator shared with `/views/{id}/count` and `POST /views/preview/count`, so the three can never disagree about which tickets are in a view. DOCUMENT SELF-CONTRADICTION, declared: `ViewObject.restriction` is typed `object` while its own description says "Is null when everyone in the account can access it" and the sibling `TriggerObject.restriction` IS declared nullable — so a view nobody restricted serves the null the description names and the row syncs to `deviation`
SERVED 2026-09-07: `listSupportViews()` + `conditionsFor(view)`. The DEFINITION half is canon's (title, conditions, columns, sort); the EXECUTION half is computed at read time by evaluating those conditions against `listSupportTickets()` — one evaluator shared with `/views/{id}/count` and `POST /views/preview/count`, so the three can never disagree about which tickets are in a view. DOCUMENT SELF-CONTRADICTION, declared: `ViewObject.restriction` is typed `object` while its own description says "Is null when everyone in the account can access it" and the sibling `TriggerObject.restriction` IS declared nullable — so a view nobody restricted serves the null the description names and the row syncs to `deviation`
IT asset management is not licensed on this account; Zendesk's own answer for an account with none is `{"asset_types": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
IT asset management is a separately-licensed product this account does not carry; Zendesk's own answer for an account with none is `{"assets": [], "links": {"next": null, "prev": null}, "meta": {"has_more": false, "after_cursor": null, "before_cursor": null}}` at 200 — this operation declares ONLY the cursor envelope, and both halves of each go null at the end of a collection, which for an empty one is every page. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
IT asset management is a separately-licensed product this account does not carry; Zendesk's own answer for an account with none is `{"assets": [], "links": {"next": null, "prev": null}, "meta": {"has_more": false, "after_cursor": null, "before_cursor": null}}` at 200 — this operation declares ONLY the cursor envelope, and both halves of each go null at the end of a collection, which for an empty one is every page. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
IT asset management is a separately-licensed product this account does not carry; Zendesk's own answer for an account with none is `{"assets": [], "links": {"next": null, "prev": null}, "meta": {"has_more": false, "after_cursor": null, "before_cursor": null}}` at 200 — this operation declares ONLY the cursor envelope, and both halves of each go null at the end of a collection, which for an empty one is every page. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
IT asset management is not licensed on this account; Zendesk's own answer for an account with none is `{"locations": [], "links": {"next": null, "prev": null}, "meta": {"has_more": false, "after_cursor": null, "before_cursor": null}}` at 200 — this operation declares ONLY the cursor envelope, and both halves of each go null at the end of a collection, which for an empty one is every page. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
IT asset management is not licensed on this account; Zendesk's own answer for an account with none is `{"statuses": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — IT asset management is not licensed on this account, so no asset type id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/it_asset_management/asset_types` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — IT asset management is not licensed on this account, so no asset type id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/it_asset_management/asset_types` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — IT asset management is not licensed on this account, so no asset type id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/it_asset_management/asset_types` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — IT asset management is a separately-licensed product this account does not carry, so no asset id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/it_asset_management/assets` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — IT asset management is not licensed on this account, so no asset location id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/it_asset_management/locations` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — IT asset management is not licensed on this account, so no asset status id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/it_asset_management/statuses` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
a registry nobody populated is an empty collection, not a refusal: no OAuth client was ever registered on this account, and Zendesk answers an admin caller 200 with the empty `clients` array rather than a 403. The refuse wave's proposal (an account-owner 403) was CONTRADICTED by this same host - the operation's pinned `Allowed For` says Admins and GET /api/v2/users/me answers the account owner with role admin (founder ruling 2026-09-06, coverage/reviews/2026-09-06-zendesk-rulings.md)
a registry nobody populated is an empty collection, not a refusal: this account has authorized no global OAuth client, and the LIST answers 200 with the empty `global_clients` array. Same contradiction as /oauth/clients - the proposed 403 would have denied an admin caller this host already serves (founder ruling 2026-09-06, coverage/reviews/2026-09-06-zendesk-rulings.md)
GlobalClientsTokenSummaryResponse is one {id, last_used_at, tokens_count} summary PER global client, so a summary over the registry served empty beside it is the computed empty array rather than a refusal. SERVED 2026-09-06 (coverage/reviews/2026-09-06-zendesk-rulings.md): `derive` and not `empty` because the value is a FUNCTION of /api/v2/oauth/global_clients - the day a client exists both rows move together and neither needs a re-ruling
no OAuth grant was ever made on this account, so the token list is a real collection with nothing in it - this replica authenticates a caller with an API key rather than an OAuth grant. The proposed account-owner 403 was contradicted the same way as the two client registries above (founder ruling 2026-09-06, coverage/reviews/2026-09-06-zendesk-rulings.md)
the caller's own OAuth clients - a registry nobody populated, answered 200 with the empty `clients` array. Same contradiction that took the account-wide registry off the refuse table: the operation's `Allowed For` says Admins and this host's /api/v2/users/me answers an admin (founder ruling 2026-09-06, coverage/reviews/2026-09-06-zendesk-rulings.md)
refuse — the operation's OWN 404 - 'Returned when API token access has been disabled for the account. No response body is returned in this case.' - and API token access was never enabled here. Its sibling 403 is NOT the one armed: GET /api/v2/users/me answers this account's owner with role admin, so a not-an-admin refusal would contradict a served answer. RETIREMENT SCREEN: deprecated: true AND a published removal date, April 30 2027, which has NOT passed - so this refusal is the pre-removal answer and a gateway Retirement entry becomes correct on that date
refuse — no OAuth client was ever registered on this account, so no client id can resolve - the provider's own not-found is the whole answer
refuse — this account has authorized no global OAuth client, so no global client id can resolve
refuse — no OAuth grant was ever made on this account, so no token id can resolve
refuse — this replica authenticates a caller with an API key rather than an OAuth grant, so there is no current OAuth token to describe
SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): the AGENT view (every request on the desk), because this host has no signed-in principal; conformance asserts the collection matches the ticket collection row for row so nobody reads it as 'these are yours'
SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): PUBLIC comments only — the end-user lens is a real projection, not an alias, and canon's `is_public` is Zendesk's `public`
SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): PUBLIC comments only, per the end-user lens
SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY, agreeing with every ticket's own `collaborator_ids: []`
SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket read through its Contact requester — the end-user dialect over rows that exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SERVED 2026-09-06: one membership per agent. `BrandAgentObject.id` is typed STRING by the document and is a decimal numeral in every published example, so the id is minted in the ordinary integer space and stringified at the edge. `url` is omitted because both published examples leave it off every row
SERVED 2026-09-06: one membership by its string id
SERVED 2026-09-06, AMENDED 2026-09-07: the account's ONE brand, derived from the artifact's `org` row — `subdomain` IS `org.login` (the same string GitHub serves as the org login) and `brand_url` is that login in Zendesk's own `https://<subdomain>.zendesk.com` grammar. `has_help_center`/`help_center_state` were hard `false`/`disabled` on the ground that this universe modelled no Help Center; hello-15 gave it EIGHT articles across four sections, which `/api/v2/ticket_content_pins` pins to twenty tickets, so the pair now READS `hasSupportDesk()` and answers the old way on every older generation. The manifest still serves no `/help_center/*` row on this provider — Zendesk publishes that API separately and the pinned document carries none of it — which is a coverage fact rather than a reason to deny the help centre exists. `logo` and `host_mapping` are OMITTED rather than emitted empty
SERVED 2026-09-06: the one brand, whose `ticket_form_ids` names the form `/api/v2/ticket_forms` serves
SERVED 2026-09-06: every agent on the roster is a member of the one brand
SERVED 2026-09-06: as above, for the one brand; an unknown brand id is the entity 404
SERVED 2026-09-06: always `is_valid: false` with `reason: not_a_cname` and the account's own `<subdomain>.zendesk.com` as the expected CNAME. This account has configured no custom domain — the brand carries no `host_mapping` for the same reason — so no hostname is currently mapped to it and the answer is true of every argument. `cname` is OMITTED because it is a DNS lookup result this replica does not perform, which the document's own invalid-CNAME example also omits. A judged call, recorded in the review doc
SERVED 2026-09-06: one membership for an AGENT and none for an end user — a brand-agent record exists only for agents, and this host's own `role` field says which people those are. An unknown user id is the entity 404, not an empty list
SERVED 2026-09-06: the same membership, scoped to its user
generateheld · data-licensing — NOT CANON-BLOCKED, and this is a scope statement rather than a gap: Zendesk's country catalog is VENDOR reference data (calling codes and ISO codes for ~250 countries), the same class as the locale catalog this host already serves. It is not derivable from this universe and no licensed copy exists in the tree — the pinned document publishes two example rows and no more. It needs a capture, not a canon entity
generateheld · data-licensing — NOT CANON-BLOCKED, and this is a scope statement rather than a gap: Zendesk's country catalog is VENDOR reference data (calling codes and ISO codes for ~250 countries), the same class as the locale catalog this host already serves. It is not derivable from this universe and no licensed copy exists in the tree — the pinned document publishes two example rows and no more. It needs a capture, not a canon entity
SERVED 2026-09-06 as a COMPUTED empty: a group SLA sets a group-OWNERSHIP target per group, and `FIRST_RESPONSE_TARGET_SEC` is the only support target in the whole canon — so the count is the number of groups that have one. The entry asserts that the account's SLA policy measures `first_reply_time` and nothing else, which is what makes the emptiness FOLLOW rather than be asserted
SERVED 2026-09-06 as an ENTITY MISS: no group SLA policy exists, so no ULID resolves
SERVED 2026-09-06: a real derive even though the policy list is empty — it names the groups a policy could be written against, and those are this host's own. NOTE the document types this filter's `values.list[].value` as an INTEGER where the SLA twin types it a string; the two rows differ exactly where the document does, and conformance caught the first attempt to make them agree
SERVED 2026-09-06, and the strongest derivation on this host: canon has been measuring these tickets against an SLA policy since hello-14. `SupportTicket.slaBreached` is derived from `firstResponseOffset` against `FIRST_RESPONSE_TARGET_SEC`, which IS a Zendesk policy — four `first_reply_time` targets, one per priority. The conformance entry recomputes the artifact's own `sla_breached` column from the targets THIS RESPONSE publishes, on every ticket, so the policy advertised here is provably the policy the desk was measured against. Zendesk counts minutes and canon counts seconds; the round trip is asserted
SERVED 2026-09-06: the one policy by id
SERVED 2026-09-06: the filter fields a policy on this account could be written against, derived from the ticket fields this host serves and the groups on its roster — the conformance entry asserts the SLA filter and the ticket-field catalog offer the same choices for the same field
the group-SLA policy list is SERVED on this same host and this account defines none, so no ticket can carry a group-SLA metric. The empty rests on an answer a caller can already read rather than on a claim this row makes: `/api/v2/group_slas/policies` answers the empty collection because a group SLA sets a group-OWNERSHIP target and canon carries none for any team (`FIRST_RESPONSE_TARGET_SEC` is the only support target in the model, which the served `/api/v2/slas/policies` states in the same breath). Zendesk's own answer for a ticket with none is `{"policy_metrics": []}` at 200, with no pagination envelope because the operation declares no paging parameters - and the ticket is GUARDED: an id this universe does not have is the ordinary entity 404, never a cheerful empty, because a 200 there would contradict `GET /api/v2/tickets/{ticket_id}` answering 404 beside it. ITS FIRST-REPLY SIBLING IS NOT EMPTY and the pair is the point: `/api/v2/tickets/{ticket_id}/slas/policy_metrics` serves ONE metric, because the account's one SLA policy does set a first-reply target - two adjacent rows, two different answers, each true of the policy it reports, and the conformance entry drives both so a later wave cannot make them agree by habit. NOT ONE OF THE EIGHTY: this row arrived with the 2026-09-12 spec re-pin, and the wave that served its two `derive` siblings on 2026-09-13 PROPOSED it rather than arming it, because an `empty` is a founder ruling and a wave that wrote both would be reviewing its own empty. RULED by the founder 2026-09-13, as proposed
SERVED 2026-09-13, and it needed no ruling: this is the JOIN of two answers this host already publishes. `/api/v2/slas/policies` (ruled `derive` 2026-09-07) says which target applies — `first_reply_time` at `targetMinutes(priority)`, on a filter that matches every ticket because canon applies the same per-priority target to all of them — and the ticket carries the clock `breachesPolicy` already reads to reproduce the artifact's `sla_breached` column. Before this row a caller could read the policy and the breach flag on this host and NOT the row that relates them, which is the manifest disagreeing with the wire. ONE ENTRY, because the policy defines one metric. `stage` is `fulfilled` once the first response lands and `active` until then; `paused` cannot occur and that is DERIVED rather than overlooked, because pausing is measured against a SCHEDULE and `shapeSlaPolicy` already serves `business_hours: false` on every metric. `minutes` is the time REMAINING against the target, negative once past — the sense the document's own example carries (`minutes: -19` beside `stage: active`) — measured to the first response when there is one and to the universe's own ANCHOR when there is not, never to the wall clock, or a pinned host's answer would change every day. `days` and `hours` are OMITTED: they restate `minutes` more coarsely, the document's example omits them, and Zendesk publishes no rule for how it splits one into the other three, so writing one would be inventing a convention. Arrived `unclassified` with the 2026-09-12 spec re-pin and was never part of the founder's eighty
approvals are an Agent Workspace flow nobody in this universe started; Zendesk's own answer for an account with none is `{"approval_requests": [], "links": {"next": null, "prev": null}, "meta": {"has_more": false, "after_cursor": null, "before_cursor": null}}` at 200 — this operation declares ONLY the cursor envelope, and both halves of each go null at the end of a collection, which for an empty one is every page. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
no task-list template was ever authored; Zendesk's own answer for an account with none is `{"task_list_templates": [], "links": {"next": null, "prev": null}, "meta": {"has_more": false, "after_cursor": null, "before_cursor": null}}` at 200 — this operation declares ONLY the cursor envelope, and both halves of each go null at the end of a collection, which for an empty one is every page. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
no agent ever added a checklist to a ticket in this universe; Zendesk's own answer for an account with none is `{"task_lists": [], "count": 0, "next_page": null, "previous_page": null}` at 200 for a ticket this universe really has, and its ordinary entity 404 for one it does not. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no task-list template was ever authored, so no task list template id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/task_list_templates` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no task-list template was ever authored, so no task list template id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/task_list_templates` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no agent ever added a checklist to a ticket in this universe, so no task list id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/tickets/{ticket_id}/task_lists` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no agent ever added a checklist to a ticket in this universe, so no task list id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/tickets/{ticket_id}/task_lists` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no agent ever added a checklist to a ticket in this universe, so no task list id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/tickets/{ticket_id}/task_lists` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
SERVED 2026-09-06: one custom status per `status_category` this desk actually uses. `CustomStatusObject`'s own enum is `new|open|pending|hold|solved` — canon's `TicketStatus` MINUS `closed`, which Zendesk models as terminal and gives no custom status — and every category served names a status some ticket is really in
SERVED 2026-09-06: one custom status, asserted identical to the row the list serves
SERVED 2026-09-06: a TicketFormStatus is a RESTRICTION (one form narrowing itself to one custom status), and the account's one form restricts nothing — so the list is the projection of the forms beside it. Also the only answer the document can express: `TicketFormStatusesResponse` carries `maxItems: 1`, a vendor bug mirrored rather than fixed
SERVED 2026-09-06: as above
SERVED 2026-09-06: the account's one ticket form, whose `ticket_field_ids` IS the ticket-field list. The NAME is the account's own name from the artifact, not Zendesk's product default — the document establishes that a default form exists (`fallback_to_default`) but publishes no name for it, and a proper noun is the one thing a renderer may not author
SERVED 2026-09-06: one ticket form; an unknown id is the entity 404
SERVED 2026-09-06: as above, scoped to the one form; an unknown form id is the entity 404 rather than an empty list
SERVED 2026-09-06: the same form by id
SERVED 2026-09-06, ACCEPTED after being sent back the same day: canon's `Company` attributes (industry, segment, size band, employees, annual revenue, relationship, lifecycle stage, region) as Zendesk custom organization fields. THE SEND-BACK AND THE RULING: the configuration wave built this, then removed it because `parity/crm-crm-parity.test.ts` ruled as DOCUMENTED DIFFERENCE (5) that a Zendesk organization's `organization_fields` bag stays `{}` - asserted as an ABSENCE so it could not be quietly filled - and rewriting a reasoned parity assertion to match new code is the same failure as hand-editing a status to green. The founder accepted the re-proposal: that note's premise was that a client could only HARDCODE the keys and would break on a base-URL swap, which held only while NO CATALOG ENDPOINT existed to discover them from. This row is that endpoint. DOCUMENTED DIFFERENCE (5) is now the STRONGER claim rather than the weaker one - the six facts HubSpot publishes off the same `CompanyRow` columns must be IDENTICAL on both hosts, which makes the parity suite sensitive to a host serving a DIFFERENT industry for one canonical company, a class an absence check could never catch (invariant #5)
SERVED 2026-09-06: one definition, by id or by key
SERVED 2026-09-06, ACCEPTED after being sent back the same day (coverage/reviews/2026-09-06-zendesk-field-catalogs.md): canon's `Contact` attributes (role, seniority, lifecycle stage, region, marketing opt-out) as Zendesk custom user fields, with every dropdown's options read off the DISTINCT values the contacts carry — an option list typed out here would be a second copy of a canon enum, free to drift silently. `shapeEndUser` fills the matching `user_fields` bag and `shapeAgent` answers null for every key, which is Zendesk's own model for a field that does not apply. The catalog and the records are two readings of one set and the conformance entry binds them
SERVED 2026-09-06: one definition, resolvable by id OR by key (the parameter is `oneOf [integer, string]`, and a client following a `key` from the list uses the second form)
SERVED 2026-09-06: the option list, which IS the distinct values the contacts carry
SERVED 2026-09-06: one option
SERVED 2026-09-06: the same definitions by KEY — `ShowManyUserFields` takes `keys` only, with no `ids` parameter unlike the ticket-field twin
the cursor/start_time dialect over SupportTicket, Contact and Company — all three exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): tickets, users and organizations only — the parameter is not a wildcard, and any other resource is a coverage 404
the cursor/start_time dialect over SupportTicket, Contact and Company — all three exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
the cursor/start_time dialect over SupportTicket, Contact and Company — all three exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
the cursor/start_time dialect over SupportTicket, Contact and Company — all three exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
the cursor/start_time dialect over SupportTicket, Contact and Company — all three exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
the cursor/start_time dialect over SupportTicket, Contact and Company — all three exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
the cursor/start_time dialect over SupportTicket, Contact and Company — all three exist. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket.tags (the TicketTag enum) — the tag set derives from the tagged rows. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket.tags (the TicketTag enum) — the tag set derives from the tagged rows. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket.tags (the TicketTag enum) — the tag set derives from the tagged rows. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY: canon tags TICKETS and nothing else, which is what the organization object's own `tags: []` says
SupportTicket.tags (the TicketTag enum) — the tag set derives from the tagged rows. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket.tags (the TicketTag enum) — the tag set derives from the tagged rows. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): the size of the tag vocabulary in use, stamped with the universe's own clock rather than Date.now()
SupportTicket.tags (the TicketTag enum) — the tag set derives from the tagged rows. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket.tags (the TicketTag enum) — the tag set derives from the tagged rows. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): EMPTY: canon tags TICKETS and nothing else, which is what the user object's own `tags: []` says
SERVED 2026-09-06 (coverage/reviews/2026-09-06-zendesk-configuration.md): Zendesk's SEVEN system ticket fields, whose `type` values are exactly the fields `shapeTicket` already serves. The three that carry `system_field_options` read canon's own enums, and both `sub_type_id` values are COMPUTED from the tickets — the document says a `status` sub type of 1 ADDS On-Hold and a `priority` sub type of 1 REMOVES Low and Urgent, so each number is read off whether this desk uses those values. BARE envelope: `TicketFieldsResponse` declares no pagination property although the operation declares cursor parameters, and the SCHEMA decides
SERVED 2026-09-06: one system ticket field, asserted identical to the row the list serves
SERVED 2026-09-06: the CUSTOM option list, which is empty as a PROJECTION of every field on this account being a system field (`removable: false` on all seven) — the document presents `custom_field_options` only for a custom multiselect or tagger, and a system field's choices ride on the object itself under `system_field_options`. The conformance entry asserts that link, never the emptiness
SERVED 2026-09-06 as an ENTITY MISS: there is no custom ticket field, so there is no custom option for an id to name, and a 404 is the correct answer for every id forever — the `/deleted_users/{deleted_user_id}` reading already established on this host
SERVED 2026-09-06: the count of the system ticket fields, asserted equal to the list length rather than to a number
SERVED 2026-09-06: the same fields by id. ALWAYS the offset envelope — `TicketFieldsShowManyResponse` is the one schema in this family with `additionalProperties: false`, so a cursor envelope's `meta`/`links` would fail the document outright
dynamic content exists to translate canned prose across locales, and this account has one locale enabled; Zendesk's own answer for an account with none is `{"items": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
dynamic content exists to translate canned prose across locales, and this account has one locale enabled; Zendesk's own answer for an account with none is `{"items": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — dynamic content exists to translate canned prose across locales, and this account has one locale enabled, so no dynamic content item id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/dynamic_content/items` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no dynamic content item exists to have variants of, so no dynamic content item id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/dynamic_content/items` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no dynamic content item exists to have variants of, so no dynamic content item id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/dynamic_content/items` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
SupportTicket.satisfaction (the SatisfactionScore enum). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket.satisfaction (the SatisfactionScore enum). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket.satisfaction (the SatisfactionScore enum). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SERVED 2026-09-06 as a COMPUTED empty, and the contradiction check settled it: this host serves satisfaction RATINGS and not one cites a reason, because `shapeSatisfactionRating` emits no `reason` field (canon carries a score and no free-text survey answer). A catalog with rows beside ratings that cite none would be explanations nobody ever chose. The conformance entry asserts `reasons.length === the number of ratings citing one`
SERVED 2026-09-06 as an ENTITY MISS: no reason is configured, so no id resolves
no scheduled deletion was ever created; Zendesk's own answer for an account with none is `{"deletion_schedules": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
no SSO/JWT remote authentication was ever configured on this account; Zendesk's own answer for an account with none is `{"remote_authentications": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
every real Zendesk account HAS a security posture, so neither a 403 nor an empty is available: the refuse wave's owner-only proposal was contradicted twice over (the operation's `Allowed For` says Admins while /api/v2/users/me answers an admin, and an absence claim would be false about any account). SERVED 2026-09-06 (coverage/reviews/2026-09-06-zendesk-rulings.md) in SecuritySettingsObject's shape, schema-declared fields only. Sixteen leaf values are DERIVED from facts this universe or this host already publishes - the whole `ip` block from the standing posture that any credential from any address is accepted, the external-identity half of `authentication` from an account that configured no IdP and whose OAuth registry is served empty, the assumption trio from a universe with no Zendesk-support relationship, and `two_factor_last_update` from the org's own creation instant (reader-derived, never Date.now()). The remainder are the PINNED DOCUMENT'S OWN published values for knobs nobody in this universe ever turned - the `EN_US` provenance rule on this same renderer, applied one family over - and they are flagged for a future capture in the review doc. `derive` and not `generate` because the row is SERVED and MODES' own vocabulary reserves `generate` for canon that does not exist (the CircleCI 2026-09-05 precedent)
every real account publishes the rules a new password must satisfy, so this row is served rather than refused: the refuse wave found its proposal contradicted by the document - its `Allowed For` is Agents and End Users, the only row of the seventeen with no Admin line, and it is scoped by the {user_id} in the PATH rather than by a signed-in principal. SERVED 2026-09-06 (coverage/reviews/2026-09-06-zendesk-rulings.md) COMPUTED from the password policy served at /api/v2/security_settings rather than transcribed - which matters, because the pinned document's two examples are NOT one coherent account (its security example says disallow_local_part_from_email false while its requirements example says `must be different from email address`). Only sentences the document itself publishes are emitted, so a policy knob with no published string produces no line rather than one this renderer authored
refuse — no scheduled deletion was ever created, so no deletion schedule id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/deletion_schedules` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
nobody in this universe has ever signed in - this replica authenticates a caller with an API key rather than a session - so the session list is a real collection with nothing in it. The refuse wave sent the proposal back because its own ruled reason argued EMPTINESS rather than refusal, and because the operation's description says an agent or end user gets `only the sessions of the user making the request`: it always answers, scoped (founder ruling 2026-09-06, coverage/reviews/2026-09-06-zendesk-rulings.md)
the LIST half of the by-id refusal below, and its reason argues emptiness rather than refusal: nobody in this universe has ever signed in, so this user's session list is a real collection with nothing in it. The {user_id} is still guarded - a session list for a person nobody has is a 404, not an empty list (founder ruling 2026-09-06, coverage/reviews/2026-09-06-zendesk-rulings.md)
refuse — nobody in this universe has ever signed in, so no session id can resolve for any user
refuse — this replica authenticates a caller with an API key rather than a session, so there is no currently authenticated session
read-only — NOT A READ. RenewCurrentSession mints an authenticity token and extends the session's lifetime - its declared 200 is {authenticity_token}, a credential this replica would be manufacturing - so it belongs to invariant #3 rather than to any coverage mode. Its `Allowed For` is the widest in the block (Admins, Agents, End users), so nobody is entitlement-blocked either, which is why the refuse wave sent it back rather than arming it. The renderer's read-only boundary now reaches it through READ_AS_WRITE_TEMPLATES and answers Zendesk's own 403; the row is `excluded` and never joins the badge denominator, which is what this mode has meant since A0.1 and what no row in the fleet had used until now (founder ruling 2026-09-06, coverage/reviews/2026-09-06-zendesk-rulings.md)
TicketFieldChange plus SupportTicket's own timings. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): `reply_time` and `resolution_time` only: the other four Zendesk metrics are pause/resume integrals over a status history canon does not carry at that resolution, and are not fabricated
SupportTicket.firstResponseOffset / solvedOffset / reopenCount — the timings Zendesk publishes as a metric object, already in canon. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SupportTicket.firstResponseOffset / solvedOffset / reopenCount — the timings Zendesk publishes as a metric object, already in canon. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
SERVED 2026-09-13, and it needed no ruling: `metricEventsFor()` (render.ts) ALREADY EXISTS and this same host already streams its output at `/api/v2/incremental/ticket_metric_events`, so this row is a re-envelope of a served answer rather than a new derivation. The operation declares its 200 as `additionalProperties` over arrays and its own summary says "Returns a sorted list by metric instance, grouped by metric name", so the map key is the metric and the value is that metric's events in instance-then-time order. TWO OF ZENDESK'S SIX METRICS are emitted and the other four are deliberately absent, which is the 2026-09-07 ruling on the incremental row unchanged: `reply_time` and `resolution_time` derive from canon's own instants (arrival, first response, solve), while `agent_work_time`, `pausable_update_time`, `periodic_update_time` and `requester_wait_time` are pause/resume integrals over a status history canon does not carry at that resolution and are not fabricated. A metric with no event carries NO KEY rather than an empty array — the map is what happened, not a template. The ticket is guarded: an id this universe does not have is the ordinary entity 404. Arrived `unclassified` with the 2026-09-12 spec re-pin and was never part of the founder's eighty
SupportTicket.firstResponseOffset / solvedOffset / reopenCount — the timings Zendesk publishes as a metric object, already in canon. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)
the X (Twitter) channel is not connected to this account; Zendesk's own answer for an account with none is `{"monitored_twitter_handles": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
the X (Twitter) channel is not connected to this account; Zendesk's own answer for an account with none is `{"statuses": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
SERVED 2026-09-07: `conversationFor(ticket)`. A `Comment` event IS one of the ticket's own comments (canon's `ticketComment` join), and since PR C (#384) removed the second rendering the log and the thread carry ONE text for one message — asserted per event rather than worked around, which is what the first cut of this wave had to do. A ticket that did not arrive through messaging has an empty log rather than a 404
refuse — the X (Twitter) channel is not connected to this account, so no monitored handle id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/channels/twitter/monitored_twitter_handles` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
the SupportTicket / Contact / Company rows the canon now carries; only the query grammar is renderer work. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): a stated subset of Zendesk's query grammar (`type:`, `status:`, `priority:`, `tags:`, bare words); an unparsed term narrows rather than widens, so an unsupported query returns fewer results and never a wrong superset
the SupportTicket / Contact / Company rows the canon now carries; only the query grammar is renderer work. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): the count of the same grammar's hits
the SupportTicket / Contact / Company rows the canon now carries; only the query grammar is renderer work. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): cursor-paged only, which is a property of this endpoint rather than of the request
SERVED 2026-09-07: `listSavedSearches()` with the `query` string COMPOSED from `conditionsFor(search)` — canon deliberately stores no query, because Zendesk's search syntax does not belong in a table every provider shares, and this renderer is the layer that knows the syntax. The id is a deterministic v4 UUID, which the document requires it to be. Scoped to the whole account rather than to a caller, because this host has no signed-in principal
no target exists, so none has failed; Zendesk's own answer for an account with none is `{"target_failures": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
no HTTP or email target was ever configured; targets are deprecated upstream in favour of webhooks; Zendesk's own answer for an account with none is `{"targets": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no target exists, so none has failed, so no target failure id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/target_failures` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no HTTP or email target was ever configured; targets are deprecated upstream in favour of webhooks, so no target id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/targets` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
SERVED 2026-09-06: the `/security_settings` precedent one family over and an order of magnitude smaller — every real account has these and nobody in this universe opened the web UI to change one, with the (A)/(B) provenance stated per field. `custom_dkim_domain: false` follows from there being no custom domain and `send_gmail_messages_via_gmail: false` from `/security_settings` answering `google_login: false`; both links are asserted. The two mail TEMPLATES carry Zendesk's own minimal `{{content}}` rather than the document's two-kilobyte example markup, which would have been this renderer serving somebody else's HTML as this account's
SERVED 2026-09-06: this account's own subdomain is taken and every other name is reported available, which is the only half of the answer this universe has. The one operation in the family with no `#### Allowed For` block — the document says outright that credentials are not required, which is also this host's standing posture. Its 200 schema is INLINE, so the conformance entry addresses it by JSON pointer
generateheld · provenance-pass — NOT CANON-BLOCKED, and this is a scope statement rather than a gap: `AccountSettingsObject` is a thirty-sub-object settings tree and every leaf needs the (A)/(B) provenance pass `/security_settings` and `/account/email_settings` were given in this PR and the last. The two smaller rows were served first deliberately; this one is the next wave's, and it is FLAGGED because `generate` is the closest mode the vocabulary has for 'not built yet' when the blocker is not canon
CrmActivity — reader.listCrmActivities() / activitiesForCompany(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): CrmActivity in Zendesk's activity envelope, with the verb written in Zendesk's own dotted grammar naming what canon recorded (`crm.call`, `crm.email`, ...) rather than borrowed from the ticket vocabulary, where it would describe something that did not happen
CrmActivity — reader.listCrmActivities() / activitiesForCompany(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): one CrmActivity, verb as above
CrmActivity — reader.listCrmActivities() / activitiesForCompany(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): the count of CrmActivity rows
SERVED 2026-09-07: `listBulkJobs()` + `bulkJobItems()`. `total`/`progress` are asserted to count the items rather than to be stored beside them, and every item names a ticket this host serves. The id is the opaque 32-hex string the document's own examples carry, not an integer
SERVED 2026-09-07: `bulkJob()` — byte-identical to the row the list serves
SERVED 2026-09-07: the same jobs by `?ids=`, matching on the opaque string rather than on a number
SERVED 2026-09-07: `listEmailNotifications()` + `recipientsFor()`. Each names a comment that is really on the ticket it names, and each recipient's `delivery_status.code` is canon's `DELIVERY_STATUS_CODE` — an SMTP reply plus DSN status, a protocol fact rather than a draw
SERVED 2026-09-07: `emailNotification()`, with the RFC 5322 Message-Id the compiler built
SERVED 2026-09-07: the same accessor filtered by `ids`/`comment_ids`/`ticket_ids`, under the PLURAL key. The document declares `EmailNotificationResponse` (singular) on an operation called "Show Many" — the mirror image of `/suspended_tickets/{id}` and resolved the same way (DECISIONS 2026-09-07)
SERVED 2026-09-07: `listAuditEvents()` (gated on `hasAdminAudit()`, its own canon flag). Every actor is a user `/api/v2/users` lists, every `source_id` names a rule this host serves, and every published address is in RFC 5737 documentation space or RFC 1918 private space so it can route to nobody. The six `filter[…]` parameters the document declares are applied against the SHAPED values, so filtering by `source_type=rule` filters on what this host actually serves
SERVED 2026-09-07: `auditEvent()` — byte-identical to the row the list serves
resource collections are an app-framework surface with nothing installed on this account; Zendesk's own answer for an account with none is `{"resource_collections": [], "count": 0, "next_page": null, "previous_page": null}` at 200, and the cursor envelope when the caller asks for that dialect. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — resource collections are an app-framework surface with nothing installed on this account, so no resource collection id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/resource_collections` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
SERVED 2026-09-06 as a COMPUTED empty: a custom role exists exactly when some agent holds one, and every agent this host serves carries one of Zendesk's BUILT-IN roles (`roleOfCrmUser` answers `admin` or `agent`) with `shapeAgent` omitting `custom_role_id` entirely. Canon's `CrmUserRole` is a JOB TITLE (`account-executive`, `support-manager`), not a Zendesk permission set. The entry asserts the link to the roster, never the emptiness
SERVED 2026-09-06 as an ENTITY MISS: no custom role is defined, so no id resolves
this account shares tickets with no other Zendesk account; Zendesk's own answer for an account with none is `{"sharing_agreements": []}` at 200, with no pagination envelope because the operation declares no paging parameters. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — this account shares tickets with no other Zendesk account, so no sharing agreement id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/sharing_agreements` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
SERVED 2026-09-06: the account's one default support address, `support@<org.login>.zendesk.com` — Zendesk's own default form over the artifact's org login. The three verification statuses are derived and agree: a `*.zendesk.com` address satisfies SPF and domain verification by construction, while `cname_status` describes a custom domain and there is none
SERVED 2026-09-06: the same address by id
SERVED 2026-09-07: `listSuspendedTickets()`, newest first. The senders are from OUTSIDE the org by construction, so no `author.id` is emitted and every address resolves in RFC 2606 `.invalid`/`.example`; where a sender quoted a ticket, it is a ticket this host serves
SERVED 2026-09-07: `suspendedTicket()` under the SINGULAR key. The document declares `SuspendedTicketsResponse` (plural) on an operation called "Show Suspended Ticket"; both envelopes validate, so the operation's own meaning breaks the tie — and `node-zendesk` unwraps the singular (DECISIONS 2026-09-07)
no contextual workspace was ever configured; Zendesk's own answer for an account with none is `{"workspaces": [], "count": 0, "next_page": null, "previous_page": null}` at 200, and the cursor envelope when the caller asks for that dialect. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
refuse — no contextual workspace was ever configured, so no workspace id resolves and Zendesk's own not-found is the whole answer — ENTAILED by the empty beside it, `/api/v2/workspaces` serving its empty collection at 200 on this same host, which is the GitHub-62 class this provider's six OAuth refusals already belong to. THE PROPOSAL SAID `empty` AND THE MODE IS `refuse`: this operation addresses ONE OBJECT rather than a collection, so it has no shape that means "nothing", and serving a 200 would manufacture a record (the split is argued in the zendesk block header above; it is the 2026-09-12 #483 precedent, where one approved sentry ruling produced `dashboards` empty and `dashboards/<built-in function id>` refuse). No 403 anywhere in this block: `GET /api/v2/users/me` answers this account's OWNER with `role: "admin"`, so a permission refusal would contradict a served answer. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
RE-RULED 2026-09-07, because the 2026-09-06 ruling stopped being true: it served an ENTITY MISS for every id on the ground that "nothing in this universe has ever attached a file", and hello-15 attached 45 — every one of them to a ticket comment, uploaded by an agent or a requester. The row now reads `listAttachments()` and serves the file, and answers the same 404 on every older artifact by READING an empty table rather than by asserting emptiness. Still outside both generation gates, for the reason it always was. `content_url` is OMITTED: Zendesk serves attachment bytes from `/attachments/token/…`, which is not under `/api/v2` and carries no row in the pinned document, so there is no covered download for this host to link to — the macro-attachment row, which does have one, publishes it
bookmarks are per-agent and nobody in this universe bookmarked a ticket; Zendesk's own answer for an account with none is `{"bookmarks": [], "count": 0, "next_page": null, "previous_page": null}` at 200, and the cursor envelope when the caller asks for that dialect. SERVED by packages/renderer-zendesk/src/honest-empties.ts and DRIVEN by an `expectsEmpty` conformance entry, so the claim is falsifiable: the day canon grows the thing, the row goes red rather than going on claiming emptiness. RULED by the founder 2026-09-13 ("Approve all 80"), on the proposal that had stood PENDING since 2026-09-11 — the ruling supersedes the 2026-09-09 hold that had kept all eighty unarmed.
03 / What's simulated
Each line below is one assertion in the conformance suite named beside it — run on every build, over one artifact, through the real renderers. Nothing is claimed here that no expect checks.
The support account's own creation instant — the `created_at` on every locale this host serves — is the same instant GitHub's `/orgs/{org}`, GitLab's `/groups/{id}` and Linear's `Organization.createdAt` print, to the second.
Against GitHub, GitLab, Linear · parity/org-member-parity.test.ts
An organization here is the Salesforce Account and the HubSpot company of the same name: `domain_names` carries the domain the Account's `Website` spells as a URL, `details` is their description, its end users are exactly the contacts those hosts serve for that account, and its tickets are their Cases and tickets with the same subjects and arrival instants.
Against Salesforce, HubSpot · parity/crm-crm-parity.test.ts
This host's organization deliberately carries no industry, revenue, headcount, address or owner and no opportunity object at all — the commercial fields Salesforce and HubSpot serve are absent here rather than invented into `organization_fields`, and a caller who goes looking for a deals endpoint gets a coverage refusal instead of a plausible empty collection.
Against Salesforce, HubSpot · parity/crm-crm-parity.test.ts
04 / Known deviations
These answer with real data and match what Zendesk actually returns, but fail the spec we vendor from Zendesk — nearly always a bug in that published description. They are listed rather than counted so you can see whether one of them is the endpoint your client calls, and they are never counted as verified.
GET /api/v2/automationsbusiness-rulesSERVED 2026-09-07: `listSupportAutomations()` + `conditionsFor()` + `actionsFor()`. Every one is asserted to carry at least one TIME condition, which is what makes an automation an automation. DOCUMENT SELF-CONTRADICTION, declared: `AutomationObject.actions[].value` is typed `string` while the same document's `TriggerActionObject` types the same field `oneOf[string,integer,array]`, and Zendesk's notification actions really do carry the recipient/subject/body array. The response is right and the document is wrong, so the rows whose response actually contains such an action sync to `deviation` rather than to green — which is two of these four today, and would be all four if a fifth automation started notifyingGET /api/v2/automations/activebusiness-rulesSERVED 2026-09-07: `listSupportAutomations()` + `conditionsFor()` + `actionsFor()`. Every one is asserted to carry at least one TIME condition, which is what makes an automation an automation. DOCUMENT SELF-CONTRADICTION, declared: `AutomationObject.actions[].value` is typed `string` while the same document's `TriggerActionObject` types the same field `oneOf[string,integer,array]`, and Zendesk's notification actions really do carry the recipient/subject/body array. The response is right and the document is wrong, so the rows whose response actually contains such an action sync to `deviation` rather than to green — which is two of these four today, and would be all four if a fifth automation started notifyingGET /api/v2/viewsviewsSERVED 2026-09-07: `listSupportViews()` + `conditionsFor(view)`. The DEFINITION half is canon's (title, conditions, columns, sort); the EXECUTION half is computed at read time by evaluating those conditions against `listSupportTickets()` — one evaluator shared with `/views/{id}/count` and `POST /views/preview/count`, so the three can never disagree about which tickets are in a view. DOCUMENT SELF-CONTRADICTION, declared: `ViewObject.restriction` is typed `object` while its own description says "Is null when everyone in the account can access it" and the sibling `TriggerObject.restriction` IS declared nullable — so a view nobody restricted serves the null the description names and the row syncs to `deviation`GET /api/v2/views/{view_id}viewsSERVED 2026-09-07: `listSupportViews()` + `conditionsFor(view)`. The DEFINITION half is canon's (title, conditions, columns, sort); the EXECUTION half is computed at read time by evaluating those conditions against `listSupportTickets()` — one evaluator shared with `/views/{id}/count` and `POST /views/preview/count`, so the three can never disagree about which tickets are in a view. DOCUMENT SELF-CONTRADICTION, declared: `ViewObject.restriction` is typed `object` while its own description says "Is null when everyone in the account can access it" and the sibling `TriggerObject.restriction` IS declared nullable — so a view nobody restricted serves the null the description names and the row syncs to `deviation`GET /api/v2/views/activeviewsSERVED 2026-09-07: `listSupportViews()` + `conditionsFor(view)`. The DEFINITION half is canon's (title, conditions, columns, sort); the EXECUTION half is computed at read time by evaluating those conditions against `listSupportTickets()` — one evaluator shared with `/views/{id}/count` and `POST /views/preview/count`, so the three can never disagree about which tickets are in a view. DOCUMENT SELF-CONTRADICTION, declared: `ViewObject.restriction` is typed `object` while its own description says "Is null when everyone in the account can access it" and the sibling `TriggerObject.restriction` IS declared nullable — so a view nobody restricted serves the null the description names and the row syncs to `deviation`GET /api/v2/views/searchviewsSERVED 2026-09-07: `listSupportViews()` + `conditionsFor(view)`. The DEFINITION half is canon's (title, conditions, columns, sort); the EXECUTION half is computed at read time by evaluating those conditions against `listSupportTickets()` — one evaluator shared with `/views/{id}/count` and `POST /views/preview/count`, so the three can never disagree about which tickets are in a view. DOCUMENT SELF-CONTRADICTION, declared: `ViewObject.restriction` is typed `object` while its own description says "Is null when everyone in the account can access it" and the sibling `TriggerObject.restriction` IS declared nullable — so a view nobody restricted serves the null the description names and the row syncs to `deviation`GET /api/v2/views/show_manyviewsSERVED 2026-09-07: `listSupportViews()` + `conditionsFor(view)`. The DEFINITION half is canon's (title, conditions, columns, sort); the EXECUTION half is computed at read time by evaluating those conditions against `listSupportTickets()` — one evaluator shared with `/views/{id}/count` and `POST /views/preview/count`, so the three can never disagree about which tickets are in a view. DOCUMENT SELF-CONTRADICTION, declared: `ViewObject.restriction` is typed `object` while its own description says "Is null when everyone in the account can access it" and the sibling `TriggerObject.restriction` IS declared nullable — so a view nobody restricted serves the null the description names and the row syncs to `deviation`05 / Pinned snapshots
Each pin regenerates byte-identically on every request, so a test written against one never drifts. Generations are DIFFERENT universes, not versions of one — never swap a suffix expecting the same data.
zendesk-v2-g10.snap.sandboxapis.devgeneration 10v2servedzendesk-v2-g11.snap.sandboxapis.devgeneration 11v2servedzendesk-v2-g8.snap.sandboxapis.devgeneration 8v2servedzendesk-v2-g9.snap.sandboxapis.devgeneration 9v2servedNeed an endpoint that is not served yet?
Every row Zendesk's manifest carries is on this page, so “not here” is an answer rather than a gap in the rendering. Tell us which path and which client, and it moves up the queue — the order is set by what people ask for.