2026-08 · Named API operations
An API today is read by two very different readers: a code generator that turns it into an SDK, and an assistant that has to decide whether to call it at all. Both were missing something fundamental.
Every operation has a name
The OpenAPI description gave each of the 75
operations a purpose, its parameters and its response shapes — but not its name.
The field for that is operationId, and it was missing throughout.
Without it a generator has to make a name up, usually from the HTTP method and
the path. POST /v1/codes becomes postV1Codes, and GET /v1/codes/{id}/scans
turns into something like getV1CodesIdScans. Such names are readable, but they
are tied to the path: change the path and you rename a method that lives in
somebody else’s code.
Now the name is in the specification:
"/v1/codes": {
"get": { "operationId": "listCodes" },
"post": { "operationId": "createCode" }
}
The shape is the same in all 75 places: list…, get…, create…, update…,
replace…, delete… — and where the action follows none of those patterns, the
verb of the thing itself, such as validateDpp or registerGs1Identifier. The
verb follows the domain, not the HTTP method: archiveWorkspace is a DELETE,
importDpps a POST.
Function-calling tool catalogues use the same name. An assistant that reads the
specification now sees createCode instead of postV1Codes — and the name stays
the same even if the path changes one day.
Guidance instead of an inventory
https://qr3.app/llms.txt is the file an assistant reads before it reads
anything else from qr3.app. Until now it listed what exists — never when
it fits. The new ## When to use qr3.app section names six jobs instead of six
features: a printed code whose destination still has to change later; a DPP
obligation under the EU regulation; resolving a GS1 identifier; bulk creation;
measurement without personal data; an agent that should act rather than only
read.
It comes with a sentence that draws the line — what qr3.app is not the right tool for. Without that the section would be advertising, not guidance.
The same information now sits in the handshake of the MCP server. Anyone wiring it into Claude, ChatGPT or a client of their own previously saw eleven tools and not one sentence about what they are for:
curl -s -X POST https://mcp.qr3.app/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize",
"params":{"protocolVersion":"2025-06-18","capabilities":{},
"clientInfo":{"name":"probe","version":"1"}}}'
The response now carries an instructions field with that same guidance, plus a
note on which calls need an API key and which do not.
Four claims that were not true
Going through llms.txt we measured every claim in it against production. Four
did not hold up and have been removed or corrected:
- There is no Python SDK yet.
llms.txtnamed aqr3apppackage on PyPI along with apip installline. That package is not published there. Anyone who followed the line got an error — the claim is gone until the package actually ships. The SDKs for JavaScript/TypeScript, Go and PHP, as well as the CLI and the MCP server, are unaffected. - Markdown does not apply to every page. The file said every server-rendered
page answers
Accept: text/markdown. In fact the homepage and the blog do; the remaining pages are generated at build time and stay HTML. The accurate statement, including that limit, is there now. - The contact address differed in two places — in
llms.txtand in the homepage’s structured data — from the one in the legal notice. Everywhere it is now[email protected]. - One link promised a page that does not exist:
/en/security/is a redirect to the “Security” section of the homepage. The link now points where it lands.
llms.txt also links docs.qr3.app/en/skills/
now. The page existed but appeared in no sitemap and no index — present and
undiscoverable at the same time.
What you need to do
For running integrations: nothing. Paths, parameters and response shapes are
unchanged; operationId is purely additive.
One exception, stated up front: if you generate your own SDK from our OpenAPI
file, your generator will rename the methods on its next run — from postV1Codes
to createCode. That is the point of the change, but it is a rename inside your
code. If you would rather not do that now, postpone the regeneration; if you use
the official SDKs, this does not affect you.