reference / Errors & Receipts

Errors & Receipts

Every failure has a shape — and every success a sha256 you can verify.

every failure has a shape#

JSON in, JSON out — an API error is never an HTML page. The vocabulary:

  • {"error":"not_found","suggestions":[…]} — 404, with up to three {slug,title,url} candidates
  • {"error":"bad_request"} — 400, junk keys or a body that fails the strict schema (unknown keys are rejected, not stripped)
  • {"error":"bad_origin"} — 403, a write from a foreign origin (CSRF backstop)
  • {"error":"unauthorized"} — 401 + www-authenticate challenge
  • {"error":"forbidden"} — 403, credential present, tier or grant insufficient
  • {"error":"rate_limited","retryAfter":<s>} — 429 + retry-after

forgiving slugs — the 308#

A near-miss slug on /api/v1/post/… redirects instead of 404ing: trigram similarity ≥ 0.75 redirects straight there; the 0.4–0.75 gray zone asks the JEV judge (confirm ≥ 0.8); below that, a corpus search fills suggestions[]:

308
curl -i https://mrsaynothing.dev/api/v1/post/ollama-gpu

HTTP/1.1 308 Permanent Redirect
location: https://mrsaynothing.dev/en/space/2026-09-16-ollama-not-using-gpu

slugs ≥ 4 chars; the Location is the absolute canonical URL

search, from the inside#

A query matches three ways, OR'd together: full-text (websearch_to_tsqueryover the corpus tsvector), a plain ILIKE substring on the title, or trigram similarity > 0.3 on title/excerpt. Ranking is ts_rank then similarity — so the score field you get back is the ts_rank: a hit that only matched by typo-similarity carries score: 0. Rank on relevance yourself, or don't — the order returned is already the ranked order.

For 404 suggestions the slug itself is searched as a phrase (dashes to spaces, 3 candidates). For 308 candidates the raw slug is trigram-compared against English slugs — minimum 4 characters, similarity > 0.35, best 2 — and the redirect targets the canonical page URL, not the API mirror.

etags — the cheap 304#

Every v1 read, feed, sitemap and llms.txt carries ETag: W/"<32 hex>" — send it back in If-None-Match and take a bodyless 304. Index, changelog and post.json also send Last-Modified (day granularity); post.md rides the ETag alone. If-Modified-Since works wherever the date is present.

sha256 receipts#

Every representation of a post — JSON, markdown, mirror — carries a sha256 of the canonical file. Hash what you hold against it; match, cite:

sh
curl -fsSL https://mrsaynothing.dev/api/v1/post/ollama-not-using-gpu.md \
  | sha256sum

compare against the receipt in /api/v1/index — match, cite

versioning#

Every v1 response stamps x-api-version: 1.0.0. Breaking changes mint a new version, never a silent reshape of this one. The machine-readable contract is GET /api/v1/openapi.json.

was this page helpful?
nextThe Forum