navan-rate-limits
Implement adaptive rate-limiting for the Navan REST API with exponential backoff and request queuing. Use when building bulk data operations or encountering 429 errors from Navan. Trigger with "navan rate limits", "navan throttling", "navan 429".
Best use case
navan-rate-limits is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Implement adaptive rate-limiting for the Navan REST API with exponential backoff and request queuing. Use when building bulk data operations or encountering 429 errors from Navan. Trigger with "navan rate limits", "navan throttling", "navan 429".
Teams using navan-rate-limits should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/navan-rate-limits/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How navan-rate-limits Compares
| Feature / Agent | navan-rate-limits | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Implement adaptive rate-limiting for the Navan REST API with exponential backoff and request queuing. Use when building bulk data operations or encountering 429 errors from Navan. Trigger with "navan rate limits", "navan throttling", "navan 429".
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
Related Guides
Best AI Skills for Claude
Explore the best AI skills for Claude and Claude Code across coding, research, workflow automation, documentation, and agent operations.
ChatGPT vs Claude for Agent Skills
Compare ChatGPT and Claude for AI agent skills across coding, writing, research, and reusable workflow execution.
SKILL.md Source
# Navan Rate Limits
## Overview
Navan does not publicly document its API rate limits. Developers typically discover thresholds empirically when bulk data pulls or batch operations begin returning HTTP 429 responses. This skill implements defensive rate-limiting patterns that adapt to server responses rather than relying on fixed quotas — inspecting response headers, applying exponential backoff with jitter, and queuing requests to prevent flooding.
## Prerequisites
- Active Navan OAuth 2.0 credentials (see `navan-install-auth`)
- Node.js 18+ (examples use native fetch)
- Understanding of HTTP 429 status code and Retry-After header semantics
## Instructions
### Step 1: Build an Adaptive Retry Wrapper
```typescript
interface RetryOptions {
maxRetries: number;
baseDelayMs: number;
maxDelayMs: number;
}
async function navanFetch(
url: string,
options: RequestInit,
retry: RetryOptions = { maxRetries: 5, baseDelayMs: 1000, maxDelayMs: 30000 }
): Promise<Response> {
let lastError: Error | null = null;
for (let attempt = 0; attempt <= retry.maxRetries; attempt++) {
const response = await fetch(url, options);
// Log rate limit headers when present (undocumented but sometimes returned)
const remaining = response.headers.get('X-RateLimit-Remaining');
const limit = response.headers.get('X-RateLimit-Limit');
if (remaining !== null) {
console.log(`Rate limit: ${remaining}/${limit} remaining`);
}
if (response.status !== 429) return response;
// Extract delay from Retry-After header or calculate exponential backoff
const retryAfter = response.headers.get('Retry-After');
let delayMs: number;
if (retryAfter) {
delayMs = parseInt(retryAfter, 10) * 1000;
console.log(`429 received — Retry-After: ${retryAfter}s`);
} else {
// Exponential backoff with jitter
delayMs = Math.min(
retry.baseDelayMs * Math.pow(2, attempt) + Math.random() * 1000,
retry.maxDelayMs
);
console.log(`429 received — backoff: ${Math.round(delayMs)}ms (attempt ${attempt + 1})`);
}
await new Promise(resolve => setTimeout(resolve, delayMs));
lastError = new Error(`Rate limited after ${attempt + 1} attempts`);
}
throw lastError ?? new Error('Max retries exceeded');
}
```
### Step 2: Implement a Request Queue for Bulk Operations
```typescript
class NavanRequestQueue {
private queue: Array<() => Promise<void>> = [];
private running = 0;
private readonly concurrency: number;
private readonly delayBetweenMs: number;
constructor(concurrency = 3, delayBetweenMs = 500) {
this.concurrency = concurrency;
this.delayBetweenMs = delayBetweenMs;
}
async add<T>(fn: () => Promise<T>): Promise<T> {
while (this.running >= this.concurrency) {
await new Promise(r => setTimeout(r, 100));
}
this.running++;
try {
const result = await fn();
await new Promise(r => setTimeout(r, this.delayBetweenMs));
return result;
} finally {
this.running--;
}
}
async drain(): Promise<void> {
while (this.running > 0) {
await new Promise(r => setTimeout(r, 100));
}
}
}
```
### Step 3: Use the Queue for Batch Data Pulls
```typescript
const queue = new NavanRequestQueue(3, 500); // 3 concurrent, 500ms gap
const accessToken = process.env.NAVAN_ACCESS_TOKEN!;
async function fetchAllExpenses(startDate: string, endDate: string) {
let page = 1;
let hasMore = true;
const allExpenses: any[] = [];
while (hasMore) {
const currentPage = page;
const result = await queue.add(async () => {
const res = await navanFetch(
`https://api.navan.com/v1/expenses?page=${currentPage}&start_date=${startDate}&end_date=${endDate}`,
{ headers: { 'Authorization': `Bearer ${accessToken}` } }
);
if (!res.ok) throw new Error(`HTTP ${res.status}: ${await res.text()}`);
return res.json();
});
allExpenses.push(...result.data);
hasMore = result.has_more;
page++;
}
return allExpenses;
}
```
### Step 4: Log and Monitor Rate Limit Signals
```typescript
function logRateLimitHeaders(response: Response, endpoint: string): void {
const headers = [
'X-RateLimit-Limit',
'X-RateLimit-Remaining',
'X-RateLimit-Reset',
'Retry-After'
];
const found: Record<string, string> = {};
for (const h of headers) {
const val = response.headers.get(h);
if (val) found[h] = val;
}
if (Object.keys(found).length > 0) {
console.log(`[${endpoint}] Rate limit headers:`, found);
}
}
```
## Output
A resilient API client that handles Navan's undocumented rate limits through adaptive retry logic and controlled concurrency. The queue prevents bulk operations from triggering 429 responses, and the retry wrapper recovers gracefully when limits are hit.
## Error Handling
| Error | Code | Solution |
|-------|------|----------|
| Too Many Requests | 429 | Retry with exponential backoff; inspect Retry-After header |
| Gateway Timeout | 504 | Reduce concurrency in queue; retry after 5-10 seconds |
| Service Unavailable | 503 | Navan maintenance window; retry with longer backoff (30-60s) |
| Unauthorized | 401 | Token expired during long batch operation; refresh OAuth token and retry |
| Bad Gateway | 502 | Transient upstream error; retry once after 2 seconds |
## Examples
**Quick test for rate limit headers:**
```bash
curl -s -D - -o /dev/null \
-H "Authorization: Bearer $NAVAN_ACCESS_TOKEN" \
https://api.navan.com/v1/users?limit=1 2>&1 | grep -i 'rate\|retry'
```
**Bulk export with throttling (Python):**
```python
import time
import requests
def navan_get(url, token, max_retries=5):
for attempt in range(max_retries):
resp = requests.get(url, headers={'Authorization': f'Bearer {token}'})
if resp.status_code != 429:
return resp
delay = int(resp.headers.get('Retry-After', 2 ** attempt))
print(f'Rate limited — waiting {delay}s (attempt {attempt + 1})')
time.sleep(delay)
raise Exception('Max retries exceeded')
```
## Resources
- [Navan Help Center](https://app.navan.com/app/helpcenter) — Official documentation and support articles
- [Navan Integrations](https://navan.com/integrations) — Integration partner ecosystem
- [HTTP 429 Specification (RFC 6585)](https://datatracker.ietf.org/doc/html/rfc6585#section-4) — Standard for rate limiting responses
## Next Steps
After implementing rate limiting, see `navan-security-basics` for credential rotation and token management, or `navan-data-sync` for building paginated data export pipelines.Related Skills
workhuman-rate-limits
Workhuman rate limits for employee recognition and rewards API. Use when integrating Workhuman Social Recognition, or building recognition workflows with HRIS systems. Trigger: "workhuman rate limits".
wispr-rate-limits
Wispr Flow rate limits for voice-to-text API integration. Use when integrating Wispr Flow dictation, WebSocket streaming, or building voice-powered applications. Trigger: "wispr rate limits".
windsurf-rate-limits
Understand and manage Windsurf credit system, usage limits, and model selection. Use when running out of credits, optimizing AI usage costs, or understanding the credit-per-model pricing structure. Trigger with phrases like "windsurf credits", "windsurf rate limit", "windsurf usage", "windsurf out of credits", "windsurf model costs".
webflow-rate-limits
Handle Webflow Data API v2 rate limits — per-key limits, Retry-After headers, exponential backoff, request queuing, and bulk endpoint optimization. Use when hitting 429 errors, implementing retry logic, or optimizing API request throughput. Trigger with phrases like "webflow rate limit", "webflow throttling", "webflow 429", "webflow retry", "webflow backoff", "webflow too many requests".
vercel-rate-limits
Handle Vercel API rate limits, implement retry logic, and configure WAF rate limiting. Use when hitting 429 errors, implementing retry logic, or setting up rate limiting for your Vercel-deployed API endpoints. Trigger with phrases like "vercel rate limit", "vercel throttling", "vercel 429", "vercel retry", "vercel backoff", "vercel WAF rate limit".
veeva-rate-limits
Veeva Vault rate limits for REST API and clinical operations. Use when working with Veeva Vault document management and CRM. Trigger: "veeva rate limits".
vastai-rate-limits
Handle Vast.ai API rate limits with backoff and request optimization. Use when encountering 429 errors, implementing retry logic, or optimizing API request throughput. Trigger with phrases like "vastai rate limit", "vastai throttling", "vastai 429", "vastai retry", "vastai backoff".
twinmind-rate-limits
Implement TwinMind rate limiting, backoff, and optimization patterns. Use when handling rate limit errors, implementing retry logic, or optimizing API request throughput for TwinMind. Trigger with phrases like "twinmind rate limit", "twinmind throttling", "twinmind 429", "twinmind retry", "twinmind backoff".
together-rate-limits
Together AI rate limits for inference, fine-tuning, and model deployment. Use when working with Together AI's OpenAI-compatible API. Trigger: "together rate limits".
techsmith-rate-limits
TechSmith rate limits for Snagit COM API and Camtasia automation. Use when working with TechSmith screen capture and video editing automation. Trigger: "techsmith rate limits".
supabase-rate-limits
Manage Supabase rate limits and quotas across all plan tiers. Use when hitting 429 errors, configuring connection pooling, optimizing API throughput, or understanding tier-specific quotas for Auth, Storage, Realtime, and Edge Functions. Trigger: "supabase rate limit", "supabase 429", "supabase throttle", "supabase quota", "supabase connection pool", "supabase too many requests".
stackblitz-rate-limits
WebContainer resource limits: memory, CPU, file system size, process count. Use when working with WebContainers or StackBlitz SDK. Trigger: "webcontainer limits".