Rate Limits
NPILayer enforces two independent limits: a monthly quota that resets every month and is shared by all the keys on your account, and a rolling burst limit that applies to each API key and protects against runaway scripts and traffic spikes.
Plans and limits
| Plan | Monthly requests | Burst limit |
|---|---|---|
| Free | 1,000 | 30 req / minute |
| Developer | 25,000 | 60 req / minute |
| Pro | 250,000 | 300 req / minute |
| Scale | 1,000,000 | 1,000 req / minute |
Need more capacity? Contact us for custom volume pricing.
Monthly quota
Each plan includes a fixed number of accepted API requests per month. Free accounts reset on the 1st of each month (UTC). Paid accounts reset on the same day of the month that the subscription started (UTC), whether billed monthly or annually. When the quota is exhausted, all further requests return 429 monthly_quota_exceeded until the next reset. Unused requests do not roll over.
Usage is tracked at the account level across all API keys. Creating additional keys does not multiply your allowance.
{
"error": {
"code": "monthly_quota_exceeded",
"message": "Your monthly API request quota has been reached.",
"limit": 25000,
"used": 25000,
"reset_at": "2026-10-01T00:00:00Z"
}
}
Burst limit
The burst limit controls how many requests you can make in a rolling one-minute window. It exists to protect service availability — it is not intended to restrict how quickly you consume your monthly allowance.
When the burst limit is exceeded, the API returns 429 with a Retry-After header. The header currently always says 10 (seconds). Because the window is rolling, you may need to wait longer if you keep sending requests, so back off and retry, and increase the delay if you get another 429.
HTTP/1.1 429 Too Many Requests
Retry-After: 10
{
"error": {
"code": "burst_rate_limit_exceeded",
"message": "Too many requests. Please slow down and retry after the indicated delay."
}
}
What counts toward the quota
Only requests that are accepted for processing count toward your monthly quota. The following do not count:
- Requests rejected for missing or invalid authentication
- Requests rejected by the burst rate limiter
- Requests that fail due to server errors (5xx)
Client errors such as 400, 404, and 422 do count — the request reached the API and consumed a slot.
Response headers and tracking usage
The only rate-limit header is Retry-After, sent on 429 burst-limit responses. The API does not send usage headers such as X-RateLimit-Remaining.
To see how much of your monthly quota you have used and when it resets, use your dashboard. When the monthly quota is used up, the 429 response tells you the limit, the amount used, and reset_at.
Handling 429 responses
Use the code field to distinguish between the two rate-limit types and handle them appropriately:
import time, requests
def get_provider(npi, api_key):
r = requests.get(
f'https://api.npilayer.com/v1/providers/{npi}',
headers={'Authorization': f'Bearer {api_key}'}
)
if r.status_code == 429:
error = r.json()['error']
if error['code'] == 'burst_rate_limit_exceeded':
retry_after = int(r.headers.get('Retry-After', 5))
time.sleep(retry_after)
return get_provider(npi, api_key) # retry once
elif error['code'] == 'monthly_quota_exceeded':
raise Exception('Monthly quota exhausted. Resets at ' + error['reset_at'])
r.raise_for_status()
return r.json()['data']
async function getProvider(npi, apiKey) {
const r = await fetch(`https://api.npilayer.com/v1/providers/${npi}`, {
headers: { 'Authorization': `Bearer ${apiKey}` }
});
if (r.status === 429) {
const { error } = await r.json();
if (error.code === 'burst_rate_limit_exceeded') {
const wait = parseInt(r.headers.get('Retry-After') || '5', 10);
await new Promise(res => setTimeout(res, wait * 1000));
return getProvider(npi, apiKey); // retry once
}
throw new Error(`Monthly quota exhausted. Resets at ${error.reset_at}`);
}
const { data } = await r.json();
return data;
}