Rate Limits
NPILayer enforces two independent controls per API key: a monthly quota that resets each calendar month, and a rolling burst limit that 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 calendar month. Usage resets at the start of each month (UTC). When the quota is exhausted, all further requests return 429 monthly_quota_exceeded until the next reset.
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 response includes a Retry-After header indicating how many seconds to wait before retrying.
HTTP/1.1 429 Too Many Requests
Retry-After: 12
{
"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.
Rate-limit response headers
Authenticated responses include headers so your client can track usage without polling:
| Header | Description |
|---|---|
X-RateLimit-Limit |
Your monthly request quota for the current billing period. |
X-RateLimit-Remaining |
Requests remaining in the current billing period. |
X-RateLimit-Reset |
Unix timestamp when the monthly quota next resets. |
Retry-After |
Seconds to wait before retrying (429 burst responses only). |
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;
}