BLS API without a key: the daily cap returns HTTP 200
Checked 2026-09-08 · Statistical agencies: BLS, Census, BEA, FRED and EIA
The BLS Public Data API refuses an over-quota request with HTTP 200 and an empty Results object, so any client that branches on the status code sees success and then crashes on the missing series list. There is no Retry-After and no rate-limit header to warn you first. Unregistered callers get roughly two dozen requests a day counted against their IP address, not the 500 the registered-key documentation quotes, and v1 and v2 share one counter. The cap is not the only thing this API does quietly: several ordinary-looking requests come back 200 with part of what you asked for removed and nothing but a message string to say so, and one of them hands you ten years of data that are not the ten you asked for. Which requests, what each one drops and what to test instead of the status code are in the table.
What we saw
The over-quota response carries HTTP 200 with no Retry-After and no rate-limit headers. Source (response headers, 2026-09-08).
HTTP/2 200 x-content-type-options: nosniff cache-control: max-age=0, no-cache, no-store strict-transport-security: max-age=31536000 ; includeSubDomains ; preload
Results is an empty object on refusal, not the usual {"series": [...]}, so Results['series'] raises KeyError. Source (response body, 2026-09-08).
{"status":"REQUEST_NOT_PROCESSED","responseTime":0,"message":["Request could not be serviced, as the daily threshold for total number of requests allocated to the user with registration key has been reached."],"Results":{}}The error text has a double space where the key would be printed, because no key was sent. Nothing in the request identifies the caller, so the counter is on the source address. Source (message[0], 2026-09-08).
allocated to the user with registration key has been reached.
v1 and v2 draw on the same counter: once v2 is refused, v1 is refused with the identical body. Source (response body, 2026-09-08).
{"status":"REQUEST_NOT_PROCESSED","responseTime":0,"message":["Request could not be serviced, as the daily threshold for total number of requests allocated to the user with registration key has been reached."],"Results":{}} HTTP 200A POST to the batch endpoint is refused the same way, so switching from GET to a batched POST does not buy any headroom once the cap is hit. Source (POST body {"seriesid":["LNS14000000"]}, 2026-09-08).
{"status":"REQUEST_NOT_PROCESSED","responseTime":0,"message":["Request could not be serviced, as the daily threshold for total number of requests allocated to the user with registration key has been reached."],"Results":{}} HTTP 200Limits
- The exact unregistered cap was not isolated. Twenty-six assorted requests from this address were served over about forty minutes and the twenty-seventh was refused; some of those were POSTs carrying several series, so whether the counter counts requests or series is untested. Plan for a couple of dozen, not for a documented number.
- Not retested after midnight, so the reset interval is assumed, not measured.
- Behaviour with a registered key was not tested - no key was available. Every row above is unregistered behaviour, and the disabled-feature messages are specifically what a keyless caller sees.
- The ten-year clip was observed on one monthly series. Whether quarterly or annual series clip the same way was not checked.
Open question
The year-range clip returns ten years, and not the ten a caller asking for a longer range would expect. Is that deliberate, or does the clip just truncate the range it built?