HTTP API design handbook

· 4m read

WORK IN PROGRESS.
WILL TAKE 3 MONTHS TO COMPLETE
TARGET COMPLETION DATE - Dec 2026

I've been trying to write this handbook for a year now. Today (2026-09-18) I finally decided to start publishing it. Based on my rough notes so far, this is going to be a rather large article.

This note exists for:

This note is for you if you're - writing a web framework, building an API gateway, developing an API, consuming an API.

Over the years, I've learnt to judge the quality of an org's engineering through:

  1. Clarity of API endpoints
  2. Accuracy of HTTP response codes
  3. Details in Response Headers

This note is supposed to help in these 3 areas.

Rate limiting

When rate limit is exceeded, return a HTTP 429 - Too many requests.

And to inform consumers about the rate limit status, 3 headers are are used:

  1. RateLimit-Policy
  2. RateLimit
  3. Retry-After

Do not impose rate limits without clearly informing consumers about what quotas have been imposed, and how much of it has been used.

Headers to use

RateLimit-Policy

Tells the rate limit policies that are being applied.

EXAMPLE

Suppose there are 2 policies: - daily policy allows 10,000 requests per day - burst policy allows 100 requests per minute

The value of RateLimit-Policy will be:

RateLimit-Policy: "burst";q=100;t=60, "daily";q=10000;t=86400;pk=oBJER4zNn2XZERtPXTBh3YzRNp707L6u

Identifiers and their meanings:

RateLimit

This is my favourite header!

Tells the current quota remaining in each policy.

Suppose the default rate limit policy that allows 100 requests in a 60 second window. It will have a header value:

RateLimit: "default";r=100;t=30

Identifiers and their meanings:

RateLimit can return the limits of multiple policies at once. Separate each policy by comma, and order the policies by time-window length in ascending order.

EXAMPLE

Consider 2 policies - daily policy allows 10,000 requests per day - burst policy allows 100 requests per minute - The usage is measured against an API key

Suppose 10 requests have been used up in a minute. The returned header will have value:

RateLimit: "burst";r=90;t=60, "daily";r=9990;t=86400;pk=oBJER4zNn2XZERtPXTBh3YzRNp707L6u

These 2 headers are enough, and I recommend using these 2 only.

Retry-After

Tells how long the client needs to wait before retrying the API request. Its value is in seconds.

There are 2 ways of reporting this value:

(1) Delta-seconds

Retry-After: 60

(2) HTTP-date

Gives a date in format Day, DD Mon YYYY HH:MM:SS GMT.

Retry-After: Sat, 18 Sep 2026 01:00:00 GMT

Note on headers

To report usage, you'll often find existing using 3 headers RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset. That too is fine, but the 2 header combo defined above is simply superior. (RateLimit-Limit & RateLimit-Remaining got combined into a single header - RateLimit)

Rate limiting algorithms to use - WORK IN PROGRESS

This is a very well known problem area, and infra components like redis, language-specific libraries etc have the building blocks required to implement each of them.

A list of algos for controlling API requests within a time window are:

  1. Token bucket - good algo to default to
  2. Fixed window counter - very stupid algo, inexpensive to implement at scale, will lead to 'bursty' usage
  3. Sliding window log - very expensive (cache wise) to implement
  4. Sliding window counter - inexpensive (I personally like this one the most)
  5. Leaky bucket - leads to very smooth processing, perfect for pull based architectures

There's also a concurrency limiting algo.

Conveying scheduled downtime

Suppose the API is currently down for planned maintenance. In this case:

  1. Return HTTP 503 - Service Unavailable
  2. Set response header Retry-After

Retry-After header tells how long the client needs to wait before retrying the API request. Its value is in seconds.

Can return value in 2 formats:

(1) HTTP-date (recommended, easier to use) (uses format Day, DD Mon YYYY HH:MM:SS GMT)

Retry-After: Sat, 18 Sep 2026 01:00:00 GMT

(2) Delta-seconds - tells time to wait in seconds

Retry-After: 3600

This is extremely useful for scrapers, because this clearly tells them when to resume operation, thus removing the need for polling the API to discover when it comes back.

Resources:

Colophon 861 words · ~3 pages · 4m read · #api #api-design
First written 2026-10-18 as a markdown note in Obsidian. Built into this page by a Python script on 2026-10-07.

Blog

Articles

created category title length
api HTTP API design handbook
API design guidelines
#api #api-design
3 pages
4 mins
data engineering The Spark Field Manual
An engineer-focused field manual on Spark internals for new data engineers and seasoned experts who need a refresher.
#spark #bigdata
23 pages
37 mins
python Unicode string normalization schemes in Python
Universally applicable string comparison in python. For string comparisons, and for de-duplication in datasets.
#python
5 pages
7 mins
resources Bookmarks
A centralized collection of papers, talks, lectures around computer science, engineering, and the overall industry
#resources
5 pages
7 mins
resources PVLDB - links only
A convenient centralized list of all PVLDB papers till date
#resources #research
162 pages
4 hrs 25 mins
resources PVLDB - links with abstracts (large document)
A convenient centralized list of all PVLDB papers till date, and their abstract
#resources #research
3377 pages
92 hrs 14 mins
work Lecture - You and your research by Dr. Richard Hamming
The lecture by Richard Hamming
#advice
49 pages
1 hr 18 mins
7 rows · last processed on 2026-10-07