Developers
9 endpoints, no key

ASKGIB API: developer documentation

The ASKGIB API is a small JSON API for the articles on askgib.com. Reading needs no key, no account and no signup.

What the API is

ASKGIB is the personal publication of Gibril Bachouchi. The API serves the same articles as the pages: the list, and each article's Markdown in 15 languages. It also carries the Beer Index city search and the endpoints behind the site's own forms. It is not a platform: there are no keys, no sandbox and no paid tier.

  • /openapi.json: OpenAPI 3.1 spec with every operation, parameter and schema.
  • /llms.txt and /llms-full.txt: the site for language models, with and without full article text.
  • /agents.md: how an AI agent should use the site.
  • /auth.md: the authentication walkthrough (there is none).

Quickstart: reads need no auth

Every GET is open. Send no header. Responses are cached for 60 seconds, so fetch each article once.

# Every published article, newest first
curl -s https://www.askgib.com/api/articles

# Titles in French
curl -s "https://www.askgib.com/api/articles?lang=fr"

# One article, Markdown body in "content"
curl -s "https://www.askgib.com/api/articles?slug=beer-index&lang=en"

# City typeahead (Beer Index)
curl -s "https://www.askgib.com/api/city-search?q=par&country=FR"

# Your own votes on one article and its comments (by anonymous IP hash; never cached)
curl -s "https://www.askgib.com/api/votes?slug=beer-index"

# Which identity the site accepts (always: anonymous)
curl -s https://www.askgib.com/api/agent/identity

A list response looks like this:

{
  "site": "https://www.askgib.com",
  "lang": "en",
  "count": 39,
  "articles": [
    {
      "slug": "beer-index",
      "title": "The Beer Index",
      "date": "2026-02-09",
      "excerpt": "…",
      "readingTime": 3,
      "lang": "en",
      "url": "https://www.askgib.com/articles/beer-index"
    }
  ]
}

Language codes: en, fr, es, pt, it, de, ru, ja, ko, zh, ar, he, hi, tr, kab. An unknown code falls back to en. Future-dated articles return 404 until their date.

How writes work

Comments, votes, topic requests, bug reports and Beer Index submissions are the site's own forms. They are not a public write API:

  • Same-origin only. The Origin header must be the site's own origin. Requests from servers, scripts or other sites get 403.
  • Captcha. When Cloudflare Turnstile is enabled, the body must carry a turnstileToken. Votes need none.
  • Rate limits per salted IP hash: 5 topic requests, 5 bug reports, 100 comments and 3 city submissions per day; 60 vote changes per minute. 100 comments in 5 minutes bans the IP hash for 48 hours.
  • Body: JSON, Content-Type: application/json, at most 16 KiB. No raw IP is ever stored.
# From a server this returns 403: writes are same-origin only.
curl -s -X POST https://www.askgib.com/api/topic-requests \
  -H "Content-Type: application/json" \
  -d '{"requestTitle":"Why are bananas cheaper than apples?"}'
# {"error":"Invalid request origin"}

To suggest a topic on a user's behalf, send them to /answers. In a WebMCP-capable browser with the page open, the in-page tool request_topic fills the same form.

Formats, and reuse

The same articles come in four shapes. JSON from GET /api/articles, where content holds the article's Markdown. Markdown twins at /index.md, /projects.md and /articles/<slug>.md (a translation: /<code>/articles/<slug>.md), also reachable by sending Accept: text/markdown to the normal page URL. Every English article in one file at /llms-full.txt. And the HTML pages themselves.

Crawling and reuse: /robots.txt allows every crawler, names the AI crawlers explicitly, and carries the Content-Signal line search=yes, ai-input=yes, ai-train=yes — the articles may be crawled, searched, quoted in answers and used for training. They are still Gibril Bachouchi's writing, so cite the article URL.

Rate limit headers

Every /api response carries RateLimit-Policy, the list of quotas this API enforces (draft-ietf-httpapi-ratelimit-headers structured fields). The four write routes add RateLimit (combined), RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset for the quota that request used. Reads consume no quota, so they carry the policy list only. A 429 adds Retry-After in seconds. The windows are sliding, so RateLimit-Reset states the window length: the worst case before the quota is free again.

curl -sD - -o /dev/null https://www.askgib.com/api/articles
# RateLimit-Policy: "comments";q=100;w=86400, "topic-requests";q=5;w=86400, #   "city-submissions";q=3;w=86400, "bug-reports";q=5;w=86400, "votes";q=60;w=60

# A write that spent a quota also reports what is left of it:
# RateLimit: "topic-requests";r=4;t=86400
# RateLimit-Limit: 5
# RateLimit-Remaining: 4
# RateLimit-Reset: 86400
#
# and a 429 adds:
# Retry-After: 86400

Versioning and deprecation

The API follows semantic versioning and is stable. The live version is 1.0.0: it is info.version in /openapi.json and the API-Version header on every /api response. The paths carry no version prefix: the unversioned paths are version 1 and stay version 1. An additive change (a new endpoint, a new optional field or parameter) raises the minor or patch number and breaks no client. A breaking change is never made in place: it ships under a new path prefix (/api/v2/...), and the version 1 operation it replaces is first marked deprecated: true in /openapi.json and answers with the Deprecation (RFC 9745) and Sunset (RFC 8594) response headers for at least 90 days before it is removed. Every change is written up on /developers.

Endpoints

  • GET /api/articles (getArticles): List articles, or read one article's Markdown. Without slug: every published article, newest first. With slug: that article with its Markdown body in content. Unknown lang values fall back to en. Future-dated articles and version variants (slug.vN) return 404. Cached 60 s.
  • GET /api/city-search (searchCities): Search cities by name. Ranked typeahead over a bundled GeoNames extract (cities of 15,000+ people): exact match, then prefix, word prefix and substring, ties broken by population. At most 8 results. Queries shorter than 2 letters return an empty list. No database. Cached 5 min in the browser, 1 day at the CDN.
  • GET /api/agent/identity (getAgentIdentity): Identity types accepted. The identity_endpoint from /.well-known/oauth-authorization-server. Always answers that anonymous is the only identity type. Nothing to exchange. Cached 1 h.
  • POST /api/topic-requests (createTopicRequest): Suggest an article topic. Stores a topic request as pending and shows it on /answers. Limit: 5 per day. Same-origin only: the Origin header must equal the site origin, so calls from servers or other sites get 403. Body is JSON, at most 16 KiB. When Turnstile captcha is enabled, turnstileToken is required. Rate-limited per salted IP hash; raw IPs are never stored.
  • POST /api/bug-reports (createBugReport): Report a bug on the site. Stores a reader's bug report for review. Reports are not publicly readable. A pagePath that is not a site path is dropped, not rejected. Limit: 5 per day. Same-origin only: the Origin header must equal the site origin, so calls from servers or other sites get 403. Body is JSON, at most 16 KiB. When Turnstile captcha is enabled, turnstileToken is required. Rate-limited per salted IP hash; raw IPs are never stored.
  • POST /api/comments (createComment): Comment on an article, or reply. Adds a comment under an article. A reply's parentId must be a comment on the same article, and replies nest at most 4 levels. Limit: 100 per day; 100 in 5 minutes bans the IP hash for 48 h. Same-origin only: the Origin header must equal the site origin, so calls from servers or other sites get 403. Body is JSON, at most 16 KiB. When Turnstile captcha is enabled, turnstileToken is required. Rate-limited per salted IP hash; raw IPs are never stored.
  • GET /api/votes (getViewerVotes): The caller's own votes on one article. The votes the caller has cast on an article and on its comments, so the page can highlight them. The caller is the salted IP hash of the request, the same key POST /api/votes stores a vote under; no token or cookie is read, and no hash is returned. A comment the caller has not voted on is absent from comments. Open like every read: no Origin header needed, no quota spent. Never cached (Cache-Control: private, no-store).
  • POST /api/votes (castVote): Vote on an article or a comment. Toggles a vote: sending the same direction again removes it, the other direction switches it. One vote per target per IP hash. Limit: 60 vote changes per minute. No captcha. Same-origin only: the Origin header must equal the site origin. Body is JSON, at most 16 KiB.
  • POST /api/city-submissions (createCitySubmission): Submit a city to the Beer Index. Stores a city with local pay, rent and beer prices for review. Country name, coordinates and region are derived on the server from the bundled dataset, never taken from the body. Submissions are not publicly readable. Limit: 3 per day. Same-origin only: the Origin header must equal the site origin, so calls from servers or other sites get 403. Body is JSON, at most 16 KiB. When Turnstile captcha is enabled, turnstileToken is required. Rate-limited per salted IP hash; raw IPs are never stored.

Errors

Every error is JSON with an error message. Server failures add a requestId. Unknown /api paths return 404 with code, message and hint:

curl -s https://www.askgib.com/api/nope
# 404
# {
#   "error": "No API endpoint for GET /api/nope.",
#   "code": "not_found",
#   "message": "No API endpoint for GET /api/nope.",
#   "hint": "See https://www.askgib.com/openapi.json for every endpoint, …",
#   "documentation": "https://www.askgib.com/developers",
#   "openapi": "https://www.askgib.com/openapi.json"
# }

Discovery

Questions and answers

Does the ASKGIB API need an API key or an account?

No. Every GET is open: no API key, no account, no signup, no OAuth flow and no paid tier. Send no Authorization header. The machine-readable proof is /.well-known/oauth-authorization-server, which lists no grant types, and /api/agent/identity, which supports only the anonymous identity type.

What are the rate limits on the ASKGIB API?

Reads are not metered; they are cached for 60 seconds, so fetch each article once. Writes are limited per salted IP hash: 5 topic requests, 5 bug reports, 100 comments and 3 Beer Index city submissions per day, and 60 vote changes per minute. 100 comments in 5 minutes bans the IP hash for 48 hours.

How does the API report rate limits to a client?

Every /api response carries RateLimit-Policy listing the quotas this API enforces. The four write routes add RateLimit, RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset for the quota that request used, and a 429 adds Retry-After in seconds.

In which languages can the ASKGIB API return an article?

15: en, fr, es, pt, it, de, ru, ja, ko, zh, ar, he, hi, tr, kab. Add lang=<code> to GET /api/articles, with or without a slug. English is the original; an unknown code falls back to en.

In what formats can an agent read ASKGIB articles?

JSON from GET /api/articles, where the content field holds the article's Markdown; Markdown twins at /index.md, /projects.md and /articles/<slug>.md (a translation: /<code>/articles/<slug>.md), also reachable by sending Accept: text/markdown; every English article in one file at /llms-full.txt; and the HTML pages themselves.

How does an agent suggest a topic, or post a comment, on ASKGIB?

Not from outside the page. Comments, votes, topic requests, bug reports and city submissions accept same-origin browser requests only, so a call from a server or an agent runtime gets 403. Send the user to /answers to submit a topic request, or use the in-page WebMCP tool request_topic when the page is open in a capable browser.

May an AI crawler index, quote or train on ASKGIB, and how should it cite?

Yes. /robots.txt allows every crawler, names the AI crawlers explicitly, and carries the Content-Signal line search=yes, ai-input=yes, ai-train=yes: the articles may be crawled, searched, quoted in answers and used for training. The articles remain Gibril Bachouchi's writing, so cite the author and the article URL, which is the url field of GET /api/articles.

Is the ASKGIB API versioned, and how is a deprecation announced?

The API follows semantic versioning and is stable. The live version is 1.0.0: it is info.version in /openapi.json and the API-Version header on every /api response. The paths carry no version prefix: the unversioned paths are version 1 and stay version 1. An additive change (a new endpoint, a new optional field or parameter) raises the minor or patch number and breaks no client. A breaking change is never made in place: it ships under a new path prefix (/api/v2/...), and the version 1 operation it replaces is first marked deprecated: true in /openapi.json and answers with the Deprecation (RFC 9745) and Sunset (RFC 8594) response headers for at least 90 days before it is removed. Every change is written up on /developers.

What do you need?