On this page · 12 sections
- What changed, and on what date
- The size problem, measured
- The .md convention is gone site-wide
- Roles versus permission groups
- Who this affects, and how to tell if that is you
- What to do instead
- India-specific considerations
- What is still unknown
- Comparison: the three doc-fetch routes on developers.cloudflare.com
- FAQ
- How eCorpIT can help
- References
Summary. On 21 August 2026 Cloudflare began returning a documentation_url field inside API 403 responses, and told developers that "Agents can use the documentation_url field to immediately fetch the endpoint's documentation from the 403 error response." Measured against the live site on 23 August 2026, the URL in Cloudflare's own worked example resolves to a 2,012,713-byte HTML document. The .md suffix that used to expose a clean markdown copy of any Cloudflare docs page now returns HTTP 404 across the whole of developers.cloudflare.com. The replacement route, /index.md, does return text/markdown on product pages, but on every /api/** endpoint page it returns content-type: text/html and a payload byte-identical to the HTML page. Two further endpoints measured the same way came back at 1,891,470 and 2,020,583 bytes. And the block the page does surface is headed "Accepted Permissions (at least one required)" and lists API token permission groups, not the account roles the announcement points readers at.
The feature is real and useful for a human sitting in a terminal. The agent workflow it advertises is the part that does not hold up yet.
What changed, and on what date
Cloudflare published "Enriched 403 responses for the Cloudflare API" to its developer changelog with a pubDate of Friday, 21 August 2026, at the path /changelog/post/2026-08-20-contextual-403s/. The change adds a documentation_url field to each entry in the errors array of a 403 Forbidden response. Cloudflare's example body is:
{
"success": false,
"errors": [
{
"code": 10000,
"message": "Forbidden",
"documentation_url": "https://developers.cloudflare.com/api/resources/workers/subresources/beta/subresources/workers/methods/list"
}
],
"messages": [],
"result": null
}
Cloudflare gives three reasons for the change. The first is troubleshooting speed: "The linked API docs surface the roles required for each endpoint, making it easier to self-serve access issues." The second is coverage: "Contextual 403 responses are now available across nearly all Cloudflare product APIs." The third is the agent case quoted above. The changelog does not publish a list of which product APIs sit inside "nearly all" and which do not, so there is no way to test coverage other than by hitting endpoints and reading what comes back.
Error code 10000 is the generic Cloudflare authentication error, which is exactly why the extra field matters. A bare {"code": 10000, "message": "Forbidden"} tells an operator nothing about which of roughly 150 account-scoped roles or several hundred token permission groups was missing.
The size problem, measured
The URL in Cloudflare's own example is the "List Workers" endpoint page. Fetched on 23 August 2026 with a browser user agent, it behaves like this:
| Request | HTTP status | Bytes returned | Content-Type |
|---|---|---|---|
.../methods/list (bare, follows a 301) |
200 | 2,012,713 | text/html |
.../methods/list.md |
404 | 9 | text/plain |
.../methods/list/index.md |
200 | 2,012,713 | text/html |
/api/resources/r2/subresources/buckets/methods/list/index.md |
200 | 1,891,470 | text/html |
/api/resources/zones/methods/list/index.md |
200 | 2,020,583 | text/html |
Stripping script and style tags from the List Workers page leaves 107,720 characters of visible text. The overwhelming majority of that is the global API navigation tree, which is rendered into every endpoint page: the extracted text opens with hundreds of unrelated entries such as "Abuse Reports", "Submit an abuse report", "List Accounts", "Create an account", "List Roles", "Role Details" and "List Permission Groups" before it reaches anything about Workers. The endpoint's own content sits inside a <main> element well below all of that.
For a person with a browser this is invisible. The sidebar is chrome and the eye goes to the middle of the page. For an HTTP client that fetches a URL and passes the body to a model, it is roughly 2 MB of markup to retrieve and parse in order to reach a three-line permissions list. That is the gap between "immediately fetch the endpoint's documentation" and what the endpoint actually returns.
The .md convention is gone site-wide
The more consequential finding is not specific to the 403 change. Until recently, appending .md to any developers.cloudflare.com docs URL returned a clean markdown rendering of that page, and a lot of tooling was built on that convention. As of 23 August 2026 it returns 404 everywhere we tested:
| Page | / (HTML) |
.md |
/index.md |
/index.md Content-Type |
|---|---|---|---|---|
/fundamentals/manage-members/roles/ |
200, 134,158 B | 404 | 200, 73,300 B | text/markdown |
/fundamentals/api/reference/permissions/ |
200, 253,265 B | 404 | 200, 199,493 B | text/markdown |
/cloudflare-one/traffic-policies/http-policies/package-registry-security/ |
200, 306,347 B | 404 | 200, 17,477 B | text/markdown |
/r2/reference/data-location/ |
200, 137,548 B | 404 | 200, 8,038 B | text/markdown |
/api/resources/zones/methods/list/ |
200, 2,020,583 B | 404 | 200, 2,020,583 B | text/html |
Two things follow. On product documentation the migration is a clear improvement: the R2 data-location page drops from 137,548 bytes of HTML to 8,038 bytes of markdown, and the Gateway package registry page from 306,347 to 17,477. That is a 94 percent reduction on the second one. Under /api/**, the same route exists, returns 200, and gives you HTML anyway.
The 404 body itself is worth noting for anyone writing retry logic. On product paths the .md 404 returns the full styled docs 404 page — 83,293 bytes for the two /fundamentals/ URLs, 232,267 bytes for the Gateway page, 69,330 bytes for the R2 page. Under /api/** the .md 404 returns 9 bytes of text/plain reading Not Found. A client that only checks for a non-empty body, rather than the status code, will treat a 232 KB HTML 404 as a successful documentation fetch. This is the same class of failure we documented when Amazon S3 403 errors began naming the denying policy ARN: the new field is genuinely helpful, and the exclusions are where the automation breaks.
Roles versus permission groups
The changelog says the linked docs "surface the roles required for each endpoint," and one of its three "For more info" links is Cloudflare's Roles page at /fundamentals/manage-members/roles/. The List Workers endpoint page does carry a permissions block. It reads:
Accepted Permissions (at least one required) Workers Tail Read Workers Scripts Write Workers Scripts Read
Those three strings are API token permission groups. They come from the API token permissions reference at /fundamentals/api/reference/permissions/, a page last updated 17 June 2026 that segments its contents into User permissions, Account permissions and Zone permissions. They are not roles.
Roles are a different system. The Roles page lists account-scoped roles assigned to human members of an account — "Administrator", "Super Administrator - All Privileges", "Administrator Read Only", "Analytics", "Cloudflare R2 Admin", "Cloudflare Zero Trust", "Cache Purge", "Firewall", "Log Share" and so on, each described in prose. Grepping the markdown copy of that page for "endpoint", "documentation_url" and "permission group" returns zero matches. The Roles page never maps a role to an API endpoint, and it does not tell you which permission groups a given role carries.
So the self-service loop the changelog describes only closes for one of the two ways a Cloudflare 403 happens. If your API token is missing a permission group, the endpoint page names the exact groups that would work. If a member's account role is too narrow, the endpoint page names token permission groups that are not the thing you need to change, and the roles document it sends you to cannot answer the question. Naming both systems "permissions" in casual writing is what makes this easy to miss. Cloudflare's own consent surface has the same split, which we unpacked in Cloudflare optional OAuth scopes.
Who this affects, and how to tell if that is you
You are affected if any of the following is true.
You run an agent or a script that reads Cloudflare API error bodies and follows links in them. The new field will resolve, return 200, and hand back roughly 2 MB. Check whether your fetch layer has a response size cap, because a silent truncation at 256 KB or 1 MB will cut the page long before the <main> element.
You built tooling on the .md suffix. Anything doing curl "$URL.md" against Cloudflare docs is now getting a 404 body rather than markdown, and if it does not check the status code it is feeding a 404 page into a prompt. Cloudflare's own pages now advertise the replacement in a header line reading Last updated Aug 14, 2026|Copy as Markdown|View as Markdown|Agent setup, where "View as Markdown" points at the /index.md URL.
You are diagnosing a 403 for a human member rather than a token. Read the permissions block on the endpoint page as a statement about tokens, then go to the account member's role separately.
What to do instead
For agents, skip the documentation_url as a fetch target and use the index files Cloudflare publishes for exactly this purpose. https://developers.cloudflare.com/api/llms.txt returns HTTP 200, text/plain, 93,427 bytes. The site-wide https://developers.cloudflare.com/llms.txt is 15,906 bytes, and per-product indexes exist too — https://developers.cloudflare.com/cloudflare-one/llms.txt is 140,897 bytes. Cloudflare embeds a pointer to these directly in its markdown pages, in a blockquote that reads "Fetch the complete documentation index at" followed by the product's llms.txt URL. Cloudflare also now ships an Agent setup section at /agent-setup/, with per-agent guides for Claude Code, Codex and Cursor.
For product documentation, switch every .md call to /index.md and assert on content-type: text/markdown rather than on status code alone. That single assertion catches both failure modes described here: the 404 pages that return HTML bodies, and the /api/** routes that return 200 with HTML.
For 403 handling specifically, keep the documentation_url in your logs. It is a precise, stable identifier for which endpoint was denied, and that is genuinely new information. Treat it as a key, not as a document to download. The same discipline applies across an enterprise AI agent production stack, where every outbound fetch is a cost and a failure mode. Teams already scoping down what their agents can reach, the pattern we covered in Claude Managed Agents domain filters, should note that adding developers.cloudflare.com to an allowlist so an agent can follow these links has a real token cost attached.
The wider point holds beyond Cloudflare. An error message written for a machine has to be tested against a machine. The real cost here is not the missing markdown route; it is that nobody fetched the URL the feature emits and looked at what came back.
India-specific considerations
Indian teams running Cloudflare from a Gurugram or Bengaluru office feel the size issue more than the permissions one. Agent runs billed per input token turn a 2 MB fetch into a recurring line item. At the common rule of thumb of roughly four characters per token, the 2,012,713-byte List Workers page is on the order of 500,000 input tokens if a client passes the raw body to a model, and around 27,000 even after stripping to the 107,720 characters of visible text. Multiply either figure by a CI job that retries on every 403 and the arithmetic stops being trivial.
The roles-versus-permissions distinction also matters for anyone documenting access control under the Digital Personal Data Protection Act 2023. If your access-control register records "the Cloudflare docs say this endpoint needs Workers Scripts Read", that statement describes a token permission group, and it does not describe which staff members can reach the data. Those are separate entries in a register and an auditor will read them as separate controls. We cover the broader mapping problem in the DPDP Act engineering playbook.
What is still unknown
Three things are not answerable from the public record as of 23 August 2026. Cloudflare has not published which product APIs are excluded from "nearly all". It has not said whether the /api/** /index.md behaviour is a deliberate choice or an incomplete migration, and the byte-identical response makes an incomplete migration the more likely reading. And there is no published mapping from account roles to token permission groups, which is the document that would actually close the self-service loop the changelog describes.
Comparison: the three doc-fetch routes on developers.cloudflare.com
| Route | Product pages (/r2/, /cloudflare-one/, /fundamentals/) |
API reference pages (/api/**) |
Safe for an agent? |
|---|---|---|---|
| Bare URL | 200, HTML, 134 KB–306 KB measured | 200, HTML, 1.89 MB–2.02 MB measured | No, size and markup overhead |
.md suffix |
404, HTML 404 page, 69 KB–232 KB | 404, text/plain, 9 bytes |
No, retired August 2026 |
/index.md |
200, text/markdown, 8 KB–199 KB |
200, text/html, identical to bare URL |
Only on product pages |
llms.txt index |
200, text/plain, 15,906 B site-wide |
200, text/plain, 93,427 B for /api/ |
Yes, this is the intended path |
FAQ
How eCorpIT can help
We build and operate AI agents that call third-party APIs in production, where an unbounded fetch or an unchecked status code turns into a cost line or a silent failure. Our teams instrument the fetch layer, set response size caps, assert on content types rather than status codes, and keep a tested map of which documentation routes actually return machine-readable output. eCorpIT is CMMI Level 5 and ISO 27001:2022 certified, and we design access-control documentation aligned with DPDP requirements. Talk to our agent engineering team about auditing what your agents fetch and what it costs you.
References
Last updated: 23 August 2026. All HTTP status codes, byte counts and content types in this article were measured against the live Cloudflare documentation site on 23 August 2026.