Developers

TL;DR

Every article here is available four ways: as HTML, as Markdown at a predictable URL, as JSON over a public API, and through an MCP server. None of those need credentials. One endpoint is paid: the full corpus in a single call, settled with x402.

What you can actually do

What you cannot do, so you do not waste a call

Markdown mirrors

Append /index.md to any page URL, or ask for Markdown with an Accept header on the page URL itself.

curl -s https://emin.de/posts/fazua-ride-50-speed-unlock-mac/index.md

# or negotiate on the HTML URL
curl -s -H 'Accept: text/markdown' https://emin.de/posts/fazua-ride-50-speed-unlock-mac

Responses carry Vary: Accept, so a cache cannot serve the HTML representation to a client that asked for Markdown.

JSON API

Typed schemas for every operation are in openapi.json. Errors use RFC 9457 problem details.

# every article, with metadata
curl -s https://emin.de/api/articles

# one article, including its full Markdown body
curl -s https://emin.de/api/articles/fazua-ride-50-speed-unlock-mac

# an unknown slug returns application/problem+json, status 404
curl -s -i https://emin.de/api/articles/no-such-article

MCP server

Streamable HTTP at /mcp, read-only, no credentials. The server card at /.well-known/mcp/server-card.json lists the transport and the tools, and the tool list there matches what the server actually implements: list_articles, get_article_markdown, search_articles, get_site_summary, list_topics.

# initialize, then list tools
curl -s -X POST https://emin.de/mcp \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'

curl -s -X POST https://emin.de/mcp \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

Paid bulk access with x402

GET /api/v1/corpus returns every article's complete Markdown in one response. An unpaid request returns a real HTTP 402 with a machine-readable challenge stating the amount, scheme, network and recipient. The exact values in the challenge match what openapi.json declares.

# see the challenge
curl -s -i https://emin.de/api/v1/corpus

This endpoint exists because crawling is the wrong shape for bulk ingestion, not as a paywall: every article is free to read individually, as HTML, as Markdown and over the JSON API. You are paying for one call instead of many, and you are not required to.

Rate limits and deprecation

API paths carry IETF RateLimit and RateLimit-Policy headers, and an exceeded limit returns 429 with Retry-After. The limits in those headers are the limits actually enforced.

If an endpoint is ever retired it will first return the Deprecation header (RFC 9745) and a Sunset header (RFC 8594) with the removal date, and be marked deprecated: true in the OpenAPI document. Nothing is removed without that sequence.

Terms

Article text is licensed CC BY 4.0: quote it, translate it, train on it, with attribution to emin.de. The site's own code is MIT and the full source is on GitHub, including the implementation of every endpoint on this page.

Authentication notes: auth.md. Discovery map: llms.txt.