Founding keys are opena year free at 6,000 req/hour, for the first 1,000 developersClaim yours

Zendesk

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.

REST · 343 endpointsMCP-ready

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.

Live host
zendesk.sandboxapis.dev
Pinned hosts
4 — generation 8, 9, 10, 11
Serving since
2026-09-04
Lifecycle
Live

Served & 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

Point your client at a different base URL.

No SDK of ours, no shim, no recorded fixtures. The same client library you already use, one environment variable different.

shell
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

Every read surface, grouped the way Zendesk groups it.

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

served & verified
answers with real universe data, and this build checked that response against the vendor's spec.
deviation
served and faithful to the real provider, but failing the vendored spec — usually a bug in the spec.
retired
the vendor removed the endpoint; snapshots pinned before that date still serve it.
planned / deferred
not served yet — an explicit coverage error naming the gap, never invented data.
excluded
out of the claim by policy (writes, and surfaces we refuse); not in any denominator on this page.

Mode — what kind of answer a row gets

derive
the response is computed from artifact rows that already exist
generate
canon does not carry this yet; the generator will produce it, then derive
empty
the true answer for this universe is an empty collection — reason + reviewed date required
refuse
mirror the provider's OWN refusal (e.g. its 403 for a non-admin token) — reason + reviewed date required
read-only
a write named in the manifest because clients probe it; the read-only 403 IS its final response, and it never joins the badge denominator

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

provenance-pass
every field needs a stated (A)/(B) provenance ruling before the response can be served honestly. The outstanding work is a review pass over the shape, not a canon entity and not renderer code.
data-licensing
the values are VENDOR reference data this project holds no grant to redistribute. Serving needs an independently licensed source, so the outstanding work is a licensing answer, not code.

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

Full
every published read row has a final answer
Deep
60% up to 100%
Partial
25% up to 60%
Preview
under 25%

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

business-rules25 of 34 served & verified · 2 deviations
GET
/api/v2/automations/{automation_id}

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 & verified
Next
GET
/api/v2/automations/search

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 & verified
Next
GET
/api/v2/macros

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 & verified
Next
GET
/api/v2/macros/{macro_id}

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 & verified
Next
GET
/api/v2/macros/{macro_id}/apply

SERVED 2026-09-07: `actionsFor(macro)` projected into `MacroApplyTicketResponse` — the changes the macro WOULD make, against no ticket, so the result names none

served & verified
Next
GET
/api/v2/macros/{macro_id}/attachments

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 & verified
Next
GET
/api/v2/macros/actions

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 & verified
Next
GET
/api/v2/macros/active

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 & verified
Next
GET
/api/v2/macros/attachments/{attachment_id}

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 & verified
Next
GET
/api/v2/macros/attachments/{attachment_id}/content

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 & verified
Next
GET
/api/v2/macros/categories

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 & verified
Next
GET
/api/v2/macros/definitions

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 & verified
Next
GET
/api/v2/macros/most_used

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 & verified
Next
GET
/api/v2/macros/new

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 & verified
Next
GET
/api/v2/macros/search

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 & verified
Next
GET
/api/v2/tickets/{ticket_id}/macros/{macro_id}/apply

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 & verified
Next
GET
/api/v2/trigger_categories

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 & verified
Next
GET
/api/v2/trigger_categories/{trigger_category_id}

SERVED 2026-09-07: one category from the same accessor, with `?include=rule_counts` counting the triggers this host serves in it

served & verified
Next
GET
/api/v2/triggers

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 & verified
Next
GET
/api/v2/triggers/{trigger_id}

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 & verified
Next
GET
/api/v2/triggers/{trigger_id}/revisions

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 & verified
Next
GET
/api/v2/triggers/{trigger_id}/revisions/{trigger_revision_id}

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 & verified
Next
GET
/api/v2/triggers/active

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 & verified
Next
GET
/api/v2/triggers/definitions

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 & verified
Next
GET
/api/v2/triggers/search

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 & verified
Next
GET
/api/v2/automations

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

deviation
Next
GET
/api/v2/automations/active

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

deviation
Next
GET
/api/v2/custom_objects/{custom_object_key}/triggers

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

deferred
Next
GET
/api/v2/custom_objects/{custom_object_key}/triggers/{trigger_id}

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

deferred
Next
GET
/api/v2/custom_objects/{custom_object_key}/triggers/active

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

deferred
Next
GET
/api/v2/custom_objects/{custom_object_key}/triggers/definitions

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

deferred
Next
GET
/api/v2/custom_objects/{custom_object_key}/triggers/search

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

deferred
Next
GET
/api/v2/macros/groups

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

deferred
Next
GET
/api/v2/triggers/limits

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}`

deferred
Next
tickets33 of 33 served & verified
GET
/api/v2/deleted_tickets

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)

served & verified
Core
GET
/api/v2/organizations/{organization_id}/tickets

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 & verified
Core
GET
/api/v2/organizations/{organization_id}/tickets/count

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 & verified
Core
GET
/api/v2/problems

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 & verified
Core
POST
/api/v2/problems/autocomplete

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 & verified
Core
GET
/api/v2/ticket_audits

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`

served & verified
Core
GET
/api/v2/tickets

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 & verified
Core
GET
/api/v2/tickets/{ticket_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)

served & verified
Core
GET
/api/v2/tickets/{ticket_id}/audits

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)

served & verified
Core
GET
/api/v2/tickets/{ticket_id}/audits/{ticket_audit_id}

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)

served & verified
Core
GET
/api/v2/tickets/{ticket_id}/audits/count

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)

served & verified
Core
GET
/api/v2/tickets/{ticket_id}/collaborators

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: []`

served & verified
Core
GET
/api/v2/tickets/{ticket_id}/comments

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)

served & verified
Core
GET
/api/v2/tickets/{ticket_id}/comments/count

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)

served & verified
Core
GET
/api/v2/tickets/{ticket_id}/email_ccs

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: []`

served & verified
Core
GET
/api/v2/tickets/{ticket_id}/followers

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: []`

served & verified
Core
GET
/api/v2/tickets/{ticket_id}/incidents

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

served & verified
Core
GET
/api/v2/tickets/{ticket_id}/related

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

served & verified
Core
GET
/api/v2/tickets/autocomplete

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 & verified
Core
GET
/api/v2/tickets/count

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 & verified
Core
GET
/api/v2/tickets/messaging/conversations/{conversation_id}/ticket

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

served & verified
Core
GET
/api/v2/tickets/recent

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 & verified
Core
GET
/api/v2/tickets/show_many

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 & verified
Core
GET
/api/v2/users/{user_id}/tickets/assigned

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 & verified
Core
GET
/api/v2/users/{user_id}/tickets/assigned/count

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 & verified
Core
GET
/api/v2/users/{user_id}/tickets/ccd

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

served & verified
Core
GET
/api/v2/users/{user_id}/tickets/ccd/count

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

served & verified
Core
GET
/api/v2/users/{user_id}/tickets/followed

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: []`

served & verified
Core
GET
/api/v2/users/{user_id}/tickets/requested

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 & verified
Core
GET
/api/v2/skips

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 & verified
Long tail
GET
/api/v2/ticket_content_pins

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 & verified
Long tail
GET
/api/v2/tickets/{ticket_id}/skips

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 & verified
Long tail
GET
/api/v2/users/{user_id}/skips

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 & verified
Long tail
custom-objects4 of 23 served & verified
GET
/api/v2/custom_objects

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.

served & verified
Long tail
GET
/api/v2/custom_objects/limits/object_limit

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.

served & verified
Long tail
GET
/api/v2/custom_objects/limits/record_limit

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.

served & verified
Long tail
GET
/api/v2/relationships/definitions/{target_type}

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.

served & verified
Long tail
GET
/api/v2/{target_type}/{target_id}/relationship_fields/{field_id}/{source_type}

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.

deferred
Long tail
GET
/api/v2/custom_objects/{custom_object_key}

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.

deferred
Long tail
GET
/api/v2/custom_objects/{custom_object_key}/access_rules

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.

deferred
Long tail
GET
/api/v2/custom_objects/{custom_object_key}/access_rules/{id}

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.

deferred
Long tail
GET
/api/v2/custom_objects/{custom_object_key}/access_rules/definitions

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.

deferred
Long tail
GET
/api/v2/custom_objects/{custom_object_key}/fields

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.

deferred
Long tail
GET
/api/v2/custom_objects/{custom_object_key}/fields/{custom_object_field_key_or_id}

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.

deferred
Long tail
GET
/api/v2/custom_objects/{custom_object_key}/limits/field_limit

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.

deferred
Long tail
GET
/api/v2/custom_objects/{custom_object_key}/permission_policies

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.

deferred
Long tail
GET
/api/v2/custom_objects/{custom_object_key}/permission_policies/{id}

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.

deferred
Long tail
GET
/api/v2/custom_objects/{custom_object_key}/records

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.

deferred
Long tail
GET
/api/v2/custom_objects/{custom_object_key}/records/{custom_object_record_id}

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.

deferred
Long tail
GET
/api/v2/custom_objects/{custom_object_key}/records/{record_id}/attachments

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.

deferred
Long tail
GET
/api/v2/custom_objects/{custom_object_key}/records/{record_id}/attachments/{id}/download

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.

deferred
Long tail
GET
/api/v2/custom_objects/{custom_object_key}/records/autocomplete

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.

deferred
Long tail
GET
/api/v2/custom_objects/{custom_object_key}/records/count

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.

deferred
Long tail
GET
/api/v2/custom_objects/{custom_object_key}/records/search

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.

deferred
Long tail
POST
/api/v2/custom_objects/{custom_object_key}/records/search

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.

deferred
Long tail
GET
/api/v2/incremental/custom_objects/{custom_object_key}/cursor

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.

deferred
Long tail
users23 of 23 served & verified
GET
/api/v2/deleted_users

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

served & verified
Core
GET
/api/v2/deleted_users/{deleted_user_id}

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)

served & verified
Core
GET
/api/v2/deleted_users/count

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

served & verified
Core
GET
/api/v2/end_users/{user_id}/identities

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)

served & verified
Core
GET
/api/v2/end_users/{user_id}/identities/{user_identity_id}

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)

served & verified
Core
GET
/api/v2/groups/{group_id}/users

CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/groups/{group_id}/users/count

CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/organizations/{organization_id}/users

CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/organizations/{organization_id}/users/count

CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/users

CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/users/{user_id}

CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/users/{user_id}/compliance_deletion_statuses

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

served & verified
Core
GET
/api/v2/users/{user_id}/entitlements/full

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

served & verified
Core
GET
/api/v2/users/{user_id}/identities

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)

served & verified
Core
GET
/api/v2/users/{user_id}/identities/{user_identity_id}

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)

served & verified
Core
GET
/api/v2/users/{user_id}/related

CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/users/autocomplete

CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
POST
/api/v2/users/autocomplete

CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/users/count

CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/users/me

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

served & verified
Core
GET
/api/v2/users/me/settings

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

served & verified
Core
GET
/api/v2/users/search

CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/users/show_many

CrmUser (agents and admins) and Contact (end users) — reader.listCrmUsers() / listContacts(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
organizations20 of 20 served & verified
GET
/api/v2/organization_memberships

Contact -> Company — reader.contactsFor(company). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/organization_memberships/{organization_membership_id}

Contact -> Company — reader.contactsFor(company). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/organization_merges/{organization_merge_id}

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

served & verified
Core
GET
/api/v2/organizations

Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/organizations/{organization_id}

Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/organizations/{organization_id}/merges

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

served & verified
Core
GET
/api/v2/organizations/{organization_id}/organization_memberships

Contact -> Company — reader.contactsFor(company). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/organizations/{organization_id}/related

Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/organizations/autocomplete

Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/organizations/count

Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/organizations/search

Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/organizations/show_many

Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/users/{user_id}/organization_memberships

Contact -> Company — reader.contactsFor(company). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/users/{user_id}/organization_memberships/{organization_membership_id}

Contact -> Company — reader.contactsFor(company). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/users/{user_id}/organizations

Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/users/{user_id}/organizations/count

Company — reader.listCompanies() / companyByDomain(); Zendesk organizations ARE the customer companies. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/organization_subscriptions

Contact -> Company, the same join Zendesk exposes as a subscription. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Long tail
GET
/api/v2/organization_subscriptions/{organization_subscription_id}

Contact -> Company, the same join Zendesk exposes as a subscription. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Long tail
GET
/api/v2/organizations/{organization_id}/subscriptions

Contact -> Company, the same join Zendesk exposes as a subscription. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Long tail
GET
/api/v2/users/{user_id}/organization_subscriptions

Contact -> Company, the same join Zendesk exposes as a subscription. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Long tail
groups16 of 16 served & verified
GET
/api/v2/group_memberships

CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/group_memberships/{group_membership_id}

CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/group_memberships/assignable

CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/groups

CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/groups/{group_id}

CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/groups/{group_id}/memberships

CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/groups/{group_id}/memberships/assignable

CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/groups/assignable

CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/groups/autocomplete

CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/groups/available_agents

CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/groups/count

CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/groups/default

CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/users/{user_id}/group_memberships

CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/users/{user_id}/group_memberships/{group_membership_id}

CrmUser.team — the same join, in Zendesk's membership dialect. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/users/{user_id}/groups

CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
GET
/api/v2/users/{user_id}/groups/count

CrmUser.team (the `sales`/`support`/`success` CrmTeam) — Zendesk's agent groups. SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Core
routing11 of 15 served & verified
GET
/api/v2/incremental/routing/attribute_values

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.

served & verified
Long tail
GET
/api/v2/incremental/routing/attributes

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.

served & verified
Long tail
GET
/api/v2/incremental/routing/instance_values

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.

served & verified
Long tail
GET
/api/v2/queues

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.

served & verified
Long tail
GET
/api/v2/queues/definitions

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.

served & verified
Long tail
GET
/api/v2/routing/agents/{user_id}/instance_values

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.

served & verified
Long tail
GET
/api/v2/routing/agents/instance_values

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.

served & verified
Long tail
GET
/api/v2/routing/attributes

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.

served & verified
Long tail
GET
/api/v2/routing/attributes/definitions

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.

served & verified
Long tail
GET
/api/v2/routing/requirements/fulfilled

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.

served & verified
Long tail
GET
/api/v2/routing/tickets/{ticket_id}/instance_values

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.

served & verified
Long tail
GET
/api/v2/queues/{queue_id}

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.

deferred
Long tail
GET
/api/v2/routing/attributes/{attribute_id}

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.

deferred
Long tail
GET
/api/v2/routing/attributes/{attribute_id}/values

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.

deferred
Long tail
GET
/api/v2/routing/attributes/{attribute_id}/values/{attribute_value_id}

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.

deferred
Long tail
views9 of 14 served & verified · 5 deviations
GET
/api/v2/views/{view_id}/count

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 & verified
Core
GET
/api/v2/views/{view_id}/execute

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 & verified
Core
GET
/api/v2/views/{view_id}/export

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 & verified
Core
GET
/api/v2/views/{view_id}/tickets

SERVED 2026-09-07: the selected tickets, byte-identical to what `/api/v2/tickets/{id}` serves for each of them

served & verified
Core
GET
/api/v2/views/compact

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 & verified
Core
GET
/api/v2/views/count

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 & verified
Core
GET
/api/v2/views/count_many

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 & verified
Core
GET
/api/v2/views/definitions

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 & verified
Core
POST
/api/v2/views/preview/count

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 & verified
Core
GET
/api/v2/views

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`

deviation
Core
GET
/api/v2/views/{view_id}

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`

deviation
Core
GET
/api/v2/views/active

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`

deviation
Core
GET
/api/v2/views/search

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`

deviation
Core
GET
/api/v2/views/show_many

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`

deviation
Core
itam6 of 12 served & verified
GET
/api/v2/it_asset_management/asset_types

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.

served & verified
Long tail
GET
/api/v2/it_asset_management/assets

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.

served & verified
Long tail
GET
/api/v2/it_asset_management/assets/search

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.

served & verified
Long tail
POST
/api/v2/it_asset_management/assets/search

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.

served & verified
Long tail
GET
/api/v2/it_asset_management/locations

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.

served & verified
Long tail
GET
/api/v2/it_asset_management/statuses

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.

served & verified
Long tail
GET
/api/v2/it_asset_management/asset_types/{asset_type_id}

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.

deferred
Long tail
GET
/api/v2/it_asset_management/asset_types/{asset_type_id}/fields

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.

deferred
Long tail
GET
/api/v2/it_asset_management/asset_types/{asset_type_id}/fields/{asset_type_field_id}

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.

deferred
Long tail
GET
/api/v2/it_asset_management/assets/{asset_id}

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.

deferred
Long tail
GET
/api/v2/it_asset_management/locations/{location_id}

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.

deferred
Long tail
GET
/api/v2/it_asset_management/statuses/{status_id}

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.

deferred
Long tail
oauth5 of 10 served & verified
GET
/api/v2/oauth/clients

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)

served & verified
Long tail
GET
/api/v2/oauth/global_clients

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)

served & verified
Long tail
GET
/api/v2/oauth/global_clients/token_summary

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

served & verified
Long tail
GET
/api/v2/oauth/tokens

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)

served & verified
Long tail
GET
/api/v2/users/me/oauth/clients

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)

served & verified
Long tail
GET
/api/v2/api_tokens

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

deferred
Long tail
GET
/api/v2/oauth/clients/{oauth_client_id}

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

deferred
Long tail
GET
/api/v2/oauth/global_clients/{global_client_id}

refuse — this account has authorized no global OAuth client, so no global client id can resolve

deferred
Long tail
GET
/api/v2/oauth/tokens/{oauth_token_id}

refuse — no OAuth grant was ever made on this account, so no token id can resolve

deferred
Long tail
GET
/api/v2/oauth/tokens/current

refuse — this replica authenticates a caller with an API key rather than an OAuth grant, so there is no current OAuth token to describe

deferred
Long tail
requests10 of 10 served & verified
GET
/api/v2/organizations/{organization_id}/requests

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 & verified
Core
GET
/api/v2/requests

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'

served & verified
Core
GET
/api/v2/requests/{request_id}

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 & verified
Core
GET
/api/v2/requests/{request_id}/comments

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`

served & verified
Core
GET
/api/v2/requests/{request_id}/comments/{ticket_comment_id}

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

served & verified
Core
GET
/api/v2/requests/ccd

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: []`

served & verified
Core
GET
/api/v2/requests/open

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 & verified
Core
GET
/api/v2/requests/search

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 & verified
Core
GET
/api/v2/requests/solved

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 & verified
Core
GET
/api/v2/users/{user_id}/requests

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 & verified
Core
brands9 of 9 served & verified
GET
/api/v2/brand_agents

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 & verified
Next
GET
/api/v2/brand_agents/{brand_agent_id}

SERVED 2026-09-06: one membership by its string id

served & verified
Next
GET
/api/v2/brands

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 & verified
Next
GET
/api/v2/brands/{brand_id}

SERVED 2026-09-06: the one brand, whose `ticket_form_ids` names the form `/api/v2/ticket_forms` serves

served & verified
Next
GET
/api/v2/brands/{brand_id}/agents

SERVED 2026-09-06: every agent on the roster is a member of the one brand

served & verified
Next
GET
/api/v2/brands/{brand_id}/check_host_mapping

SERVED 2026-09-06: as above, for the one brand; an unknown brand id is the entity 404

served & verified
Next
GET
/api/v2/brands/check_host_mapping

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 & verified
Next
GET
/api/v2/users/{user_id}/brand_agents

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 & verified
Next
GET
/api/v2/users/{user_id}/brand_agents/{brand_agent_id}

SERVED 2026-09-06: the same membership, scoped to its user

served & verified
Next
locales6 of 8 served & verified
GET
/api/v2/locales
served & verified
Next
GET
/api/v2/locales/{locale_id}
served & verified
Next
GET
/api/v2/locales/agent
served & verified
Next
GET
/api/v2/locales/current
served & verified
Next
GET
/api/v2/locales/detect_best_locale
served & verified
Next
GET
/api/v2/locales/public
served & verified
Next
GET
/api/v2/countries.json

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

deferred
Next
GET
/api/v2/countries/{id}.json

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

deferred
Next
sla8 of 8 served & verified
GET
/api/v2/group_slas/policies

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 & verified
Next
GET
/api/v2/group_slas/policies/{group_sla_policy_id}

SERVED 2026-09-06 as an ENTITY MISS: no group SLA policy exists, so no ULID resolves

served & verified
Next
GET
/api/v2/group_slas/policies/definitions

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 & verified
Next
GET
/api/v2/slas/policies

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 & verified
Next
GET
/api/v2/slas/policies/{sla_policy_id}

SERVED 2026-09-06: the one policy by id

served & verified
Next
GET
/api/v2/slas/policies/definitions

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

served & verified
Next
GET
/api/v2/tickets/{ticket_id}/group_slas/policy_metrics

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 & verified
Next
GET
/api/v2/tickets/{ticket_id}/slas/policy_metrics

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

served & verified
Next
task-lists3 of 8 served & verified
GET
/api/v2/approval_requests

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.

served & verified
Long tail
GET
/api/v2/task_list_templates

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.

served & verified
Long tail
GET
/api/v2/tickets/{ticket_id}/task_lists

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.

served & verified
Long tail
GET
/api/v2/task_list_templates/{task_list_template_id}

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.

deferred
Long tail
GET
/api/v2/task_list_templates/{task_list_template_id}/tasks

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.

deferred
Long tail
GET
/api/v2/task_lists/{task_list_id}

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.

deferred
Long tail
GET
/api/v2/task_lists/{task_list_id}/task_items

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.

deferred
Long tail
GET
/api/v2/task_lists/{task_list_id}/task_items/{task_item_id}

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.

deferred
Long tail
ticket-forms8 of 8 served & verified
GET
/api/v2/custom_statuses

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 & verified
Next
GET
/api/v2/custom_statuses/{custom_status_id}

SERVED 2026-09-06: one custom status, asserted identical to the row the list serves

served & verified
Next
GET
/api/v2/ticket_form_statuses

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 & verified
Next
GET
/api/v2/ticket_form_statuses/show_many

SERVED 2026-09-06: as above

served & verified
Next
GET
/api/v2/ticket_forms

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 & verified
Next
GET
/api/v2/ticket_forms/{ticket_form_id}

SERVED 2026-09-06: one ticket form; an unknown id is the entity 404

served & verified
Next
GET
/api/v2/ticket_forms/{ticket_form_id}/ticket_form_statuses

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 & verified
Next
GET
/api/v2/ticket_forms/show_many

SERVED 2026-09-06: the same form by id

served & verified
Next
custom-fields7 of 7 served & verified
GET
/api/v2/organization_fields

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 & verified
Next
GET
/api/v2/organization_fields/{organization_field_id}

SERVED 2026-09-06: one definition, by id or by key

served & verified
Next
GET
/api/v2/user_fields

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 & verified
Next
GET
/api/v2/user_fields/{user_field_id}

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 & verified
Next
GET
/api/v2/user_fields/{user_field_id}/options

SERVED 2026-09-06: the option list, which IS the distinct values the contacts carry

served & verified
Next
GET
/api/v2/user_fields/{user_field_id}/options/{user_field_option_id}

SERVED 2026-09-06: one option

served & verified
Next
GET
/api/v2/user_fields/show_many

SERVED 2026-09-06: the same definitions by KEY — `ShowManyUserFields` takes `keys` only, with no `ids` parameter unlike the ticket-field twin

served & verified
Next
incremental-export7 of 7 served & verified
GET
/api/v2/incremental/{incremental_resource}/sample

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

served & verified
Next
GET
/api/v2/incremental/organizations

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)

served & verified
Next
GET
/api/v2/incremental/ticket_events

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)

served & verified
Next
GET
/api/v2/incremental/tickets

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)

served & verified
Next
GET
/api/v2/incremental/tickets/cursor

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)

served & verified
Next
GET
/api/v2/incremental/users

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)

served & verified
Next
GET
/api/v2/incremental/users/cursor

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)

served & verified
Next
tags7 of 7 served & verified
GET
/api/v2/autocomplete/tags

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)

served & verified
Next
POST
/api/v2/autocomplete/tags

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)

served & verified
Next
GET
/api/v2/organizations/{organization_id}/tags

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

served & verified
Next
GET
/api/v2/tags

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)

served & verified
Next
GET
/api/v2/tags/count

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()

served & verified
Next
GET
/api/v2/tickets/{ticket_id}/tags

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)

served & verified
Next
GET
/api/v2/users/{user_id}/tags

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 & verified
Next
ticket-fields6 of 6 served & verified
GET
/api/v2/ticket_fields

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 & verified
Core
GET
/api/v2/ticket_fields/{ticket_field_id}

SERVED 2026-09-06: one system ticket field, asserted identical to the row the list serves

served & verified
Core
GET
/api/v2/ticket_fields/{ticket_field_id}/options

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 & verified
Core
GET
/api/v2/ticket_fields/{ticket_field_id}/options/{ticket_field_option_id}

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 & verified
Core
GET
/api/v2/ticket_fields/count

SERVED 2026-09-06: the count of the system ticket fields, asserted equal to the list length rather than to a number

served & verified
Core
GET
/api/v2/ticket_fields/show_many

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

served & verified
Core
dynamic-content2 of 5 served & verified
GET
/api/v2/dynamic_content/items

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.

served & verified
Long tail
GET
/api/v2/dynamic_content/items/show_many

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.

served & verified
Long tail
GET
/api/v2/dynamic_content/items/{dynamic_content_item_id}

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.

deferred
Long tail
GET
/api/v2/dynamic_content/items/{dynamic_content_item_id}/variants

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.

deferred
Long tail
GET
/api/v2/dynamic_content/items/{dynamic_content_item_id}/variants/{dynamic_content_variant_id}

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.

deferred
Long tail
satisfaction5 of 5 served & verified
GET
/api/v2/satisfaction_ratings

SupportTicket.satisfaction (the SatisfactionScore enum). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Next
GET
/api/v2/satisfaction_ratings/{satisfaction_rating_id}

SupportTicket.satisfaction (the SatisfactionScore enum). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Next
GET
/api/v2/satisfaction_ratings/count

SupportTicket.satisfaction (the SatisfactionScore enum). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md)

served & verified
Next
GET
/api/v2/satisfaction_reasons

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 & verified
Next
GET
/api/v2/satisfaction_reasons/{satisfaction_reason_id}

SERVED 2026-09-06 as an ENTITY MISS: no reason is configured, so no id resolves

served & verified
Next
security4 of 5 served & verified
GET
/api/v2/deletion_schedules

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.

served & verified
Long tail
GET
/api/v2/remote_authentications

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.

served & verified
Long tail
GET
/api/v2/security_settings

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)

served & verified
Long tail
GET
/api/v2/users/{user_id}/password/requirements

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

served & verified
Long tail
GET
/api/v2/deletion_schedules/{deletion_schedule_id}

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.

deferred
Long tail
sessions2 of 5 served & verified
GET
/api/v2/sessions

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)

served & verified
Long tail
GET
/api/v2/users/{user_id}/sessions

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)

served & verified
Long tail
GET
/api/v2/users/{user_id}/sessions/{session_id}

refuse — nobody in this universe has ever signed in, so no session id can resolve for any user

deferred
Long tail
GET
/api/v2/users/me/session

refuse — this replica authenticates a caller with an API key rather than a session, so there is no currently authenticated session

deferred
Long tail
GET
/api/v2/users/me/session/renew

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)

excluded
Long tail
ticket-metrics5 of 5 served & verified
GET
/api/v2/incremental/ticket_metric_events

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

served & verified
Next
GET
/api/v2/ticket_metrics

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 & verified
Next
GET
/api/v2/ticket_metrics/{ticket_metric_id}

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 & verified
Next
GET
/api/v2/tickets/{ticket_id}/metric_events

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

served & verified
Next
GET
/api/v2/tickets/{ticket_id}/metrics

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 & verified
Next
channels3 of 4 served & verified
GET
/api/v2/channels/twitter/monitored_twitter_handles

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.

served & verified
Long tail
GET
/api/v2/channels/twitter/tickets/{comment_id}/statuses

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 & verified
Long tail
GET
/api/v2/tickets/{ticket_id}/conversation_log

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

served & verified
Long tail
GET
/api/v2/channels/twitter/monitored_twitter_handles/{monitored_twitter_handle_id}

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.

deferred
Long tail
search4 of 4 served & verified
GET
/api/v2/search

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

served & verified
Core
GET
/api/v2/search/count

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

served & verified
Core
GET
/api/v2/search/export

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 & verified
Core
GET
/api/v2/saved_searches

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

served & verified
Next
targets2 of 4 served & verified
GET
/api/v2/target_failures

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.

served & verified
Long tail
GET
/api/v2/targets

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.

served & verified
Long tail
GET
/api/v2/target_failures/{target_failure_id}

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.

deferred
Long tail
GET
/api/v2/targets/{target_id}

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.

deferred
Long tail
account2 of 3 served & verified
GET
/api/v2/account/email_settings

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 & verified
Next
GET
/api/v2/accounts/available

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

served & verified
Long tail
GET
/api/v2/account/settings

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

deferred
Next
activity3 of 3 served & verified
GET
/api/v2/activities

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

served & verified
Next
GET
/api/v2/activities/{activity_id}

CrmActivity — reader.listCrmActivities() / activitiesForCompany(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): one CrmActivity, verb as above

served & verified
Next
GET
/api/v2/activities/count

CrmActivity — reader.listCrmActivities() / activitiesForCompany(). SERVED 2026-09-04 (coverage/reviews/2026-09-04-zendesk-serving.md): the count of CrmActivity rows

served & verified
Next
job-statuses3 of 3 served & verified
GET
/api/v2/job_statuses

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 & verified
Next
GET
/api/v2/job_statuses/{job_status_id}

SERVED 2026-09-07: `bulkJob()` — byte-identical to the row the list serves

served & verified
Next
GET
/api/v2/job_statuses/show_many

SERVED 2026-09-07: the same jobs by `?ids=`, matching on the opaque string rather than on a number

served & verified
Next
notifications3 of 3 served & verified
GET
/api/v2/email_notifications

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 & verified
Next
GET
/api/v2/email_notifications/{notification_id}

SERVED 2026-09-07: `emailNotification()`, with the RFC 5322 Message-Id the compiler built

served & verified
Next
GET
/api/v2/email_notifications/show_many

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 & verified
Next
audit-logs2 of 2 served & verified
GET
/api/v2/audit_logs

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 & verified
Next
GET
/api/v2/audit_logs/{audit_log_id}

SERVED 2026-09-07: `auditEvent()` — byte-identical to the row the list serves

served & verified
Next
resource-collections1 of 2 served & verified
GET
/api/v2/resource_collections

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.

served & verified
Long tail
GET
/api/v2/resource_collections/{resource_collection_id}

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.

deferred
Long tail
roles2 of 2 served & verified
GET
/api/v2/custom_roles

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 & verified
Next
GET
/api/v2/custom_roles/{custom_role_id}

SERVED 2026-09-06 as an ENTITY MISS: no custom role is defined, so no id resolves

served & verified
Next
sharing1 of 2 served & verified
GET
/api/v2/sharing_agreements

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.

served & verified
Long tail
GET
/api/v2/sharing_agreements/{sharing_agreement_id}

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.

deferred
Long tail
support-addresses2 of 2 served & verified
GET
/api/v2/recipient_addresses

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 & verified
Next
GET
/api/v2/recipient_addresses/{support_address_id}

SERVED 2026-09-06: the same address by id

served & verified
Next
suspended-tickets2 of 2 served & verified
GET
/api/v2/suspended_tickets

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 & verified
Next
GET
/api/v2/suspended_tickets/{id}

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)

served & verified
Next
workspaces1 of 2 served & verified
GET
/api/v2/workspaces

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.

served & verified
Long tail
GET
/api/v2/workspaces/{workspace_id}

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.

deferred
Long tail
attachments1 of 1 served & verified
GET
/api/v2/attachments/{attachment_id}

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

served & verified
Next
bookmarks1 of 1 served & verified
GET
/api/v2/bookmarks

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.

served & verified
Long tail

03 / What's simulated

One data set, rendered in Zendesk's dialect.

What another provider has to agree with, and the test that makes it

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.

04 / Known deviations

7 rows are served but do not validate.

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.

05 / Pinned snapshots

Frozen universes, on their own hostnames.

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.

PinHostUniverse generationZendesk API versionRepository files
zendesk-v2-g10zendesk-v2-g10.snap.sandboxapis.devgeneration 10v2served
zendesk-v2-g11zendesk-v2-g11.snap.sandboxapis.devgeneration 11v2served
zendesk-v2-g8zendesk-v2-g8.snap.sandboxapis.devgeneration 8v2served
zendesk-v2-g9zendesk-v2-g9.snap.sandboxapis.devgeneration 9v2served

Need 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.

Request coverage