HTTP API design handbook

API design guidelines

By Niraj Zade  |  2026 Oct 18  |  4m read  |  852 words  |  3 pages
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:

  • Teaching newcomers or my junior teammates the components things that go into an API's design
  • Helping me remember stuff
  • Being a standards guide for feeding LLMs (before they starts auditing existing APIs or creating new ones).

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, set 3 headers:

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

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

Headers to set

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:

  • q - quota of the policy
  • qu - unit that the quota is measured in (values could be - requests, content-bytes, concurrent-requests)
  • w - time window of the quota
  • pk - (optional) - partition key used to scope usage (could be API key, account, ip address etc)

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:

  • r - API hits remaining in policy (+ve integer). 0 means all the API hits of the quota have been used up.
  • t - time window window length in seconds, in which the quota can be used
  • pk - (optional) - partition key used to scope usage (could be API key, account, ip address etc)

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 your 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 your API.

Resources:









Thoughts & opinions

Articles

I learn through writing, so I write a lot. Most of these are ever evolving pieces.


API
Data Engineering
Python
Resources
Work