Coveo ships a large, genuinely deep reference surface — REST API index, SDKs, an llms.txt, per-page .md source files — but two auth pages flatly disagree on whether API keys expire, the same concept resolves to different page IDs across the docs, and the machine-readable surface built for AI agents emits raw template tags and unresolved placeholders.
1. Auth docs contradict each other on whether an API key expires (critical)
Location:/en/1369.md (API key authentication) vs /en/1718.md (Manage API keys)
Problem:1369.md states flatly: "An API key is a non-expiring access token which carries a certain set of privileges in a Coveo organization." 1718.md documents the opposite in detail: keys created from templates such as View all content and Custom "will be asked to set an expiration date," keys reach a Soon to be expired status 7 days out with admin email notifications "7 days before / 2 days before / immediately after," and keys that "haven't been used for one year" are "deactivated automatically." Only a Custom key can be explicitly set to Never.
Consequence: A developer reading the auth guide reasonably builds an integration assuming the key is permanent, skips rotation/expiry handling, and then gets a production 401 when the key hits its expiration date or the one-year inactivity sweep. This is exactly the silent contradiction that humans muddle through and automated agents copy wholesale.
The fix: Correct 1369.md to "An API key may be non-expiring, but most templates require an expiration date" and link directly to the expiration/auto-deactivation section of 1718.md. State the one-year inactivity deactivation in both places.
2. The Push API resolves to two different page IDs depending on where you start (significant)
Problem: The API index lists the Push API at /en/12/. The C# SDK end-of-support notice — the page actively telling developers to migrate to the Push API — points them to "the Push API documentation" at /en/68.md, and the SDK GitHub README uses /en/68/index-content/use-the-push-api. (Note: the REST API overview's own .md source, 143.md, doesn't resolve the Push reference at all — it emits a literal placeholder, per Finding 4 — so the only two surfaces that name a concrete Push API page, and , disagree.)
Code verification
Runtime snippet checks
Run the public examples from this audit in an isolated sandbox and attach the pass, fixed, skipped, and failed counts to the report.
Consequence: Migrating developers following the deprecation notice land on /en/68; developers arriving from the API index land on /en/12, with no signal which is the canonical Push API reference. Inconsistent IDs for one API also make it impossible for an agent to deduplicate or trust internal links.
The fix: Choose one canonical Push API page ID and update every reference (apis.txt, q2dd0592.md, the SDK README) to it. Add a redirect from the stale ID rather than leaving both live.
3. The same link text resolves to different pages — "Customer Service API" and "API key" (significant)
Location:/en/llms/sections/apis.txt (API index); /en/n3ge4046.md vs /en/p3ob0090.md
Problem: Two distinct sub-issues, both of identical-label/different-target type:
The API index lists "Customer Service API" twice with identical link text but different IDs — 3321.md (under the guide heading) and 3430/ (under "Reference"). The Answer API page's reference link resolves to 3430.md#tag/Answer, indicating 3430 is the reference hub — so these are almost certainly a guide + reference pair, but the index labels them identically with no guide/reference distinction.
Separately, the anchor text "API key" resolves to two genuinely different pages depending on the starting point: the Authentication methods page (n3ge4046.md) links "API key" to 1718.md (Manage API keys), while the Answer API page (p3ob0090.md) links "API key" to 105.md (Use API key authentication with the Search API). The identical link text gives no hint they cover different things.
Consequence: A reader scanning the index sees "Customer Service API" twice and can't tell whether it's a duplicate, a versioned split, or a guide/reference pair. A developer following "API key" links across pages lands on different pages behind identical text, with no indication of which one fits their case.
The fix: Relabel the two index entries as "Customer Service API (guide)" and "Customer Service API (reference)." Make the "API key" link text disambiguate its target (e.g., "Manage API keys" vs "Use API key auth with the Search API") rather than reusing one phrase for two pages.
4. The machine-readable surface built for agents emits raw template code and malformed example URLs (significant)
Location:/en/q2ib0310.md (Deprecations source); /en/143.md (REST APIs overview source); /en/n3ge0020.md (Platform token source); /en/p3ob0090.md (Answer API source) — all advertised via llms.txt and the https://docs.coveo.com/en/{slug}.md pattern
Problem: The docs explicitly publish llms.txt, llms-full.txt, and a per-page .md source pattern for LLM/agent consumption. But those surfaces are unrendered in several ways:
The Deprecations .md emits raw Liquid ({% assign by_order = site.deprecations | where_exp… %} and [{{ notice.title }}]({{ site.baseurl }}/{{ notice.slug }}/)) instead of the notices table. (Verified disconfirmation: the human-facing HTML at /en/q2ib0310/ renders all five active notices correctly — the defect is confined to the .md/llms surface, not the rendered page.)
The REST API overview .md shows AsciiDoc cells as literal |[code] / |[guide] placeholders instead of resolved links.
The platform-token .md drops angle-bracket placeholders, leaving POST .../rest/organizations//tokens with an empty org-ID segment.
The Answer API .md shows the generate endpoint as POST https://.org.coveo.com/rest/organizations//answer/v1/configs//generate — empty host plus two empty path segments, the same defect class.
Consequence: An AI coding agent — the consumer this surface was explicitly built for — fetching q2ib0310.md gets template directives instead of deprecation dates, fetching 143.md gets [code]/[guide] instead of API links, and copy-pasting the platform-token or Answer API examples produces requests to malformed URLs with an empty host and empty org-ID/config segments.
The fix: Render Liquid, AsciiDoc tables, and angle-bracket placeholders to their final values before publishing the .md source files, or generate the .md surface from rendered HTML. Mark placeholder values explicitly (e.g., {organizationId}, {configId}) rather than dropping them.
5. The official SDK README links into docs using a legacy URL scheme (significant)
Location:https://raw.githubusercontent.com/coveooss/platform-sdk/master/README.md (SDK README) vs the current /en/{id}/ docs scheme
Problem: The official C# Platform SDK README — the canonical migration path off the now-deprecated SDK — links into the docs using a legacy URL form with extra path segments that differ from the current /en/{id}/ scheme: /en/q2dd0592/deprecations/net-c-platform-sdk, /en/68/index-content/use-the-push-api, /en/1707/cloud-v2-administrators/privilege-reference, and /en/90/cloud-v2-developers/managing-batches-of-items-in-a-push-source. The cloud-v2-developers / cloud-v2-administrators segments are an old path scheme; the rest of the docs use bare /en/{id}/.
Consequence: Developers following the official deprecation/migration README click URLs in a non-canonical scheme at exactly the moment they're being forced off the SDK; if any of these no longer resolve or redirect inconsistently, the migration path breaks. An agent indexing both the README and the docs records two incompatible URL schemes for the same pages and can't reconcile them.
The fix: Verify each legacy /en/{id}/cloud-v2-* URL still resolves, add redirects to the current /en/{id}/ form where needed, and update the README links to the canonical scheme.
6. "Event Protocol" links to three different pages on a single page (minor)
Location:/en/1769.md (Usage Analytics — Get started)
Problem: The identical prose label "Event Protocol" is hyperlinked to three different slugs within one page: o1n91230.md ("use the Event Protocol to log events"), o9je0592.md ("The Event Protocol and Coveo Relay library are generally available"), and o3r90189.md ("If you're using the Event Protocol, keep in mind that custom fields have been replaced…"). The "Coveo Relay library" is a fourth, separate slug (o9je0322.md).
Consequence: A reader (or an agent indexing the page) cannot tell which URL is the canonical "Event Protocol" reference; whichever link a developer clicks is a coin-flip, and an agent building a link graph records three distinct "Event Protocol" nodes for one feature.
The fix: Pick one canonical Event Protocol page and point all three references at it; if the three targets are genuinely different topics (overview vs migration vs reference), rename the link text so each says what it actually is.
7. Answer API documents that failures return no debugging information (minor)
Location:/en/p3ob0090.md (Answer API — open beta)
Problem: Under "Limitations," the docs state: "The /generate endpoint doesn't currently provide debugging information if the Answer API can't generate an answer," and show the failure payload as {"payloadType":"genqa.endOfStreamType","payload":"{\"answerGenerated\":false}","finishReason":"COMPLETED","errorMessage":null,"statusCode":null}. There is no error reference — no codes, no causes, no remediation — for the failure case. This is an acknowledged limitation of an open-beta endpoint, which is why it's rated minor rather than higher.
Consequence: When answer generation fails, a developer receives errorMessage: null and statusCode: null with finishReason: COMPLETED, making a failure indistinguishable from a success with no answer. There is nothing to log or alert on, and the docs offer no troubleshooting path.
The fix: Document the known failure causes (no relevant content, quota, model timeout, permissions) even while the endpoint can't yet return structured errors, and give developers a fallback detection rule (answerGenerated: false) plus guidance on what to surface to end users.
8. Feature maturity is buried in mid-page callouts (minor)
Problem: The homepage promotes Atomic broadly as a primary "DX tool," but the maturity caveat specific to the Commerce variant lives only deep in an "Important" callout in o6q90192.md: "Atomic for Commerce components are in open beta and remain under active development" and "hasn't yet gone through a formal accessibility review." Separately, the Answer API is "open beta" and requires the Knowledge Hub, which is itself "currently available as a beta to early-access customers only — contact your Customer Success Manager"; that prerequisite surfaces only as you reach the first-call path.
Consequence: A team evaluating Atomic from the homepage won't see the Commerce variant's beta status and missing accessibility review until they're deep in the building guide — a blocker for any accessibility-bound deployment. Similarly, a developer can read the entire Answer API page before learning the whole feature is gated behind an early-access beta they must request.
The fix: Surface maturity status (GA / open beta / early-access) as a visible badge at the top of each feature page, and state access prerequisites (e.g., Knowledge Hub early access, Atomic for Commerce beta) in the prerequisites section rather than only mid-page.
9. Token lifetimes are scattered across token types and never reconciled (minor)
Location:/en/n3ge0020.md, /en/123.md, and /en/56.md (referenced but not scraped)
Problem: Different token types carry different default lifetimes documented on separate pages: platform tokens default to 24h (PT24H, n3ge0020.md) and browser-session access tokens last "up to four hours" (123.md). The Authentication methods page also references search tokens (56.md), whose validity range is not reconciled here. No single page compares the token types side by side.
Consequence: A developer choosing an auth approach has to visit multiple pages and infer the differences themselves, and is more likely to pick the wrong token type or mis-set a validity period.
The fix: Add a single comparison table (token type → default lifetime → max lifetime → intended use) to the Authentication methods page and link to it from each token page.
10. Deprecation notice opens with a grammar error in the EOL date (minor)
Problem: The lead sentence of the SDK end-of-support notice reads: "It's reaching end of support in August 31, 2026." The correct preposition for a specific date is "on."
Consequence: A grammatical error in the first sentence of a dated, high-stakes deprecation notice — the exact date developers must plan a migration around — undercuts confidence in the date itself.
The fix: Change "in August 31, 2026" to "on August 31, 2026."
Problem: The implementation sequence is labeled "Step 1: Index content," "Step 2: Build a search UI," "Step 3: Tune relevance," then jumps to "Step 5: Leverage AI and ML." The analytics step ("Monitor your solution with Coveo Analytics…") and two trailing items are unlabeled, leaving a visible Step 4 gap.
Consequence: The numbered onboarding path — the first thing a new developer reads — looks broken or incomplete, undermining confidence that the sequence is the canonical implementation order.
The fix: Number the analytics step as Step 4 (and the trailing items consistently), or drop explicit numbers and present the sequence as an ordered list so it renumbers automatically.
What they do well
Deprecation notices are concrete and dated — the search/listing configuration API deprecation gives a real timeline (Oct 1 2025 → Nov 25 2025 → Aug 31 2026) and calls out breaking behavior changes like Exclude rules no longer being page-defining.
Auth guidance is appropriately cautious where it matters — browser-session tokens are clearly labeled "use only for testing," and 105.md warns never to expose a key not built from the Anonymous search template.
The site publishes an llms.txt, llms-full.txt, and per-page .md sources — the right instinct for agent consumption, even though the rendering of those files needs fixing.
Top 3 recommendations
Resolve the API-key expiration contradiction (Finding 1) immediately — it's a flat, production-breaking disagreement between two auth pages.
Fix internal-link integrity — one canonical page per concept (Push API), disambiguate identical link text (Customer Service API guide/reference, "API key"), and sweep the legacy cloud-v2-* URLs with redirects (Findings 2, 3, 5).
Render the .md/llms surface before publishing so the agent-facing files contain real tables, links, and placeholder values instead of Liquid, [code]/[guide], and empty host/org-ID/config segments (Finding 4).