Skip to content
routebase
API Governance10 chapters

Chapter 06 of 10

Consistent Headers Across Every API

Headers are the first place consistency decays. The four families worth standardising, why a policy beats a rule here, and what a policy in a contract does not do.

Naming conventions get argued about in reviews. Headers get forgotten, because they sit one level below the thing anybody is looking at.

That makes them the most reliable early indicator of whether your consistency is a mechanism or an intention.

Why headers decay first

A response header is attached per response, and a medium API has a few hundred responses.

Nobody adds a correlation header to all of them by hand correctly. The first twenty get it, the next batch gets it under a different name, and the ones added during a release week get nothing. None of that is visible in a design review, because reviews look at operations and bodies rather than at the header list of the third error response.

The result is an API where tracing works on some calls, and a consumer who cannot tell which.

The four families worth standardising

Most header conventions reduce to four groups, and everything else is local to one API.

Correlation. One identifier that travels with a request across every service it touches. This is the header your on-call engineer needs at three in the morning, and it is worth more than the other three combined.

Rate limit state. How much budget a caller has left and when it resets. Carrying it only on the rejection is the common mistake, because a client that learns its position only when refused cannot slow down before that. Note that the widely used X-RateLimit-* spelling is a convention rather than a published standard, so pick one spelling and apply it everywhere. The rate limit chapter of the design guide covers what the values should mean.

Caching and concurrency. Validators such as ETag and Last-Modified, along with the cache directives that say whether a response may be stored. These are defined in RFC 9110 and RFC 9111, so the decision is where to apply them rather than what to call them.

Deprecation signals. Whatever you use to tell a caller that this version is going away, applied consistently rather than mentioned in a changelog. Deprecation and sunset covers the process behind the signal.

A policy beats a rule here

For most conventions a check is the right mechanism. Headers are the case where it is not.

A rule reports that this response is missing the correlation header. Somebody then adds it to that response, and to the next one, and to the three hundred after that, and the count goes back up the following week. The rule is correct and the work it creates is endless.

A policy inverts that. You declare that every response in a status class carries this set of headers, and the responses get them. The consistency is a consequence of the declaration rather than a task somebody works through, and new endpoints inherit it without anyone remembering.

This is the same argument as the previous chapter. Where you can make a class of violation impossible, do that instead of detecting it.

Scope, priority and exceptions

A policy needs three things to survive contact with a real estate of APIs.

It needs a scope narrow enough to be true. Applying rate limit headers to every response in the document is wrong, because they belong on the responses the limit governs. Status classes are the natural unit, so a policy for successful responses and a policy for rejections say different things.

It needs a precedence when two policies overlap, since they will. An explicit order is better than a surprise, and the surprise is what teaches people to distrust the mechanism.

It needs exceptions with reasons. One response that legitimately should not carry an inherited header is normal, and an exception recorded on that response is a documented decision. Turning the policy off for the whole specification because of one response is how you lose the other three hundred.

What a policy in a contract does not do

This is worth saying plainly, because the word enforcement invites the wrong expectation.

A header policy describes what your API documents. It makes every matching response in the specification carry the header, which means your reference documentation, your generated clients and your mocks all agree about it. It does not reach into the running service and make it send the header.

Closing that gap is a different mechanism, which is checking a live environment against the contract and reporting where they differ. Contract drift covers it, and a header your specification promises and your service omits is exactly the kind of thing it finds.

In Routebase

Header policies are built from header components, and both cascade from the organisation down.

The organisation-level API Header Policies page, with a Header Components card listing Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset with their types and required flags, and a Header Policies card below it holding an enabled Rate limit headers policy and a disabled Retry guidance on 429 policy with drag handles.
Policies are defined once for the organisation and inherited by every project and specification, and the drag handle sets which one wins where two overlap.

A header component is a reusable definition of one header, carrying its name, type, required flag and description. A set of common headers covering correlation, rate limits, caching and retries can be added in one step. A policy bundles components and applies them to every response whose status code matches its scopes, which are the individual codes or whole classes.

Policies exist at the organisation, the project and the specification, and the most specific level wins. They are priority ordered by dragging, and a policy can be disabled while you stage it. An impact analysis shows how many endpoints and responses a policy touches, along with any overlap with another policy, before you save it.

A single response can exclude an inherited header with a reason recorded on the exclusion, and the policy stays intact everywhere else. Managing organisation-level policies needs the governance permission, while an exclusion needs ordinary specification write access. The Header Policies guide covers scopes, priority and exclusions.

Frequently asked questions

Which HTTP headers should every API response carry?

Four families cover almost all of it. A correlation identifier lets one request be traced across services, and rate limit state tells a client where it stands. The other two are caching and concurrency validators such as ETag, and deprecation signals on anything that is going away. Beyond those, a header belongs to one API rather than to a standard.

How do you keep response headers consistent across APIs?

Apply them rather than check them. A rule reports that one response is missing the correlation header, and somebody then has to add it by hand to that response and every other one like it. A policy that attaches a set of headers to every response in a status class does the work instead, so the consistency is a consequence rather than a chore.

Should every response include rate limit headers?

Every response the limit actually applies to, which is usually every authenticated one rather than only the rejections. A client that learns its remaining budget only when it is refused cannot slow down in advance, so the headers are worth carrying on success as well. The 429 response then adds retry guidance on top.

Last reviewed by The Routebase Team.

Ready to ship on it?

Routebase is live. Design your API once — docs, mocks, tests, and monitoring all follow from the same source.

14-day Pro trial — no credit card required.