Skip to main content

API

·700 words·4 mins·

Every published page on this site has a machine-readable twin alongside its HTML, so an agent, script, or LLM never has to scrape a rendered page to read it. Everything below is an anonymous GET: no key, no signup, no request body, and Access-Control-Allow-Origin: * on every response so browser-based agents can read them too.

If you would rather not learn any of these URLs, ask for Markdown by name and any page will answer in it:

curl -s https://michalak.world/about/ -H "Accept: text/markdown"

Content negotiation
#

Send Accept: text/markdown and a page returns its Markdown instead of its HTML, at the page’s own URL. Nothing needs to be appended and nothing needs to be discovered first — if you have a link to a page, you can read it as Markdown. Browsers ask for text/html ahead of anything else, so they still get the rendered page.

The response is text/markdown; charset=utf-8, carries Vary: Accept so caches keep the two representations apart, and includes two headers worth reading:

HeaderMeaning
x-markdown-tokensEstimated tokens in the response, for sizing a context window or picking a chunk size.
Content-LocationThe URL of the Markdown itself, if you want to cache or cite it directly.

This is served from the same file you would get by appending index.md, so the two routes are interchangeable — use whichever fits your client. Pages that have no Markdown twin, such as the numbered pages of a paginated list, fall back to HTML rather than erroring.

Endpoints
#

EndpointReturns
/index.jsonEvery page in one JSON array: title, description, summary, full body text, tags, and dates.
/{page}/index.mdThat page’s source Markdown, headings and code fences intact. Append index.md to any page URL, or ask the page itself for text/markdown.
/llms.txtA curated map of the site in the llmstxt.org shape: expertise, key pages, every article with a description.
/llms-full.txtThe full text of every page concatenated into one response.
/api/openapi.jsonOpenAPI 3.1 description of everything in this table.
/api/status.jsonWhich build the CDN is currently serving.
/.well-known/api-catalogThe RFC 9727 catalog listing these APIs.

/sitemap.xml and /index.xml are published in the usual places as well.

Start here
#

Read the catalog to find the APIs, then the OpenAPI document to find their shapes:

curl -s https://michalak.world/.well-known/api-catalog | jq '.linkset[].anchor'
curl -s https://michalak.world/api/openapi.json | jq '.paths | keys'

Ingest the whole site in one request, or take a single page as Markdown:

curl -s https://michalak.world/index.json | jq '.[] | {title, permalink, tags}'
curl -s https://michalak.world/about/index.md

The permalink field of each index entry is the path to append index.md to — or to request with Accept: text/markdown, which returns the same document. Either way a two-step crawl is straightforward: read the index, pick the pages worth reading in full, fetch their Markdown.

What to expect
#

Responses are static files served from Cloudflare’s edge. They change only when the site is rebuilt, so caching them for a few minutes costs nothing in freshness — /api/status.json names the build you are being served if you need to tell a live deployment from a stale copy.

There is no versioned URL prefix. The OpenAPI document carries a version, and the response shapes described there will not change incompatibly without it changing too; new fields may appear at any time, so parse defensively and ignore what you do not recognize.

Nothing here is rate limited beyond ordinary CDN protection. AI crawlers are welcome: /robots.txt allows the training, search, and user-initiated fetchers by name. Reuse is subject to the terms of use, and attribution with a link back is appreciated.

Discovery
#

The catalog is advertised three ways, so an agent can find it without guessing. The well-known URI is one. A HEAD of the site root is another: it returns Link headers for api-catalog, service-desc, service-doc, and describedby without downloading a byte of HTML. And every page carries <link rel="api-catalog"> in its <head>, for an agent that landed mid-site rather than at the front door.

Inside the catalog, each entry anchors one endpoint and carries the same three links: service-desc to the OpenAPI document, service-doc to this page, and status.

Questions, or something you want exposed that is not here? Get in touch.

Michael Michalak
Author
Michael Michalak
Experienced Drupal consultant and Fractional CTO with over 13 years of expertise in backend development, optimization, and securing Drupal applications, specializing in custom module development, migrations, and enterprise integrations across various industries.