bamboohr-rate-limits

Implement BambooHR rate limiting, backoff, and request optimization. Use when handling 429/503 rate limit errors, implementing retry logic, or optimizing API request throughput for BambooHR. Trigger with phrases like "bamboohr rate limit", "bamboohr throttling", "bamboohr 429", "bamboohr 503", "bamboohr retry", "bamboohr backoff".

1,868 stars

Best use case

bamboohr-rate-limits is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Implement BambooHR rate limiting, backoff, and request optimization. Use when handling 429/503 rate limit errors, implementing retry logic, or optimizing API request throughput for BambooHR. Trigger with phrases like "bamboohr rate limit", "bamboohr throttling", "bamboohr 429", "bamboohr 503", "bamboohr retry", "bamboohr backoff".

Teams using bamboohr-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

$curl -o ~/.claude/skills/bamboohr-rate-limits/SKILL.md --create-dirs "https://raw.githubusercontent.com/jeremylongshore/claude-code-plugins-plus-skills/main/plugins/saas-packs/bamboohr-pack/skills/bamboohr-rate-limits/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/bamboohr-rate-limits/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How bamboohr-rate-limits Compares

Feature / Agentbamboohr-rate-limitsStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Implement BambooHR rate limiting, backoff, and request optimization. Use when handling 429/503 rate limit errors, implementing retry logic, or optimizing API request throughput for BambooHR. Trigger with phrases like "bamboohr rate limit", "bamboohr throttling", "bamboohr 429", "bamboohr 503", "bamboohr retry", "bamboohr backoff".

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

SKILL.md Source

# BambooHR Rate Limits

## Overview

BambooHR does not publish exact rate limits, but the API returns `503 Service Unavailable` with a `Retry-After` header when you exceed them. This skill covers detection, backoff, request optimization, and queue-based throttling.

## Prerequisites

- BambooHR API client configured
- Understanding of async/await patterns

## Instructions

### Step 1: Understand BambooHR Rate Limiting Behavior

BambooHR rate limiting details:

| Signal | Value | Description |
|--------|-------|-------------|
| HTTP Status | `503` | Primary rate limit signal |
| `Retry-After` header | seconds (e.g., `30`) | How long to wait before retrying |
| `X-BambooHR-Error-Message` | varies | May contain rate limit detail |
| HTTP Status `429` | rare | Some endpoints return 429 for employee count limits |

**Key insight:** BambooHR uses `503` (not `429`) for rate limiting. Failed authentication attempts also count toward rate limits, so ensure your API key is valid before making many requests.

### Step 2: Implement Retry-After Aware Backoff

```typescript
import { BambooHRApiError } from './client';

interface RetryConfig {
  maxRetries: number;
  baseDelayMs: number;
  maxDelayMs: number;
}

const DEFAULT_RETRY: RetryConfig = {
  maxRetries: 5,
  baseDelayMs: 1000,
  maxDelayMs: 60_000,
};

async function withBambooHRRetry<T>(
  operation: () => Promise<T>,
  config = DEFAULT_RETRY,
): Promise<T> {
  for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
    try {
      return await operation();
    } catch (err) {
      if (attempt === config.maxRetries) throw err;
      if (!(err instanceof BambooHRApiError)) throw err;
      if (!err.retryable) throw err; // Only retry 429, 503, 500, 502

      // Honor BambooHR's Retry-After header
      let delay: number;
      if (err.meta.retryAfter) {
        delay = parseInt(err.meta.retryAfter, 10) * 1000;
      } else {
        // Exponential backoff with jitter
        const exponential = config.baseDelayMs * Math.pow(2, attempt);
        const jitter = Math.random() * config.baseDelayMs;
        delay = Math.min(exponential + jitter, config.maxDelayMs);
      }

      console.warn(
        `BambooHR rate limited (attempt ${attempt + 1}/${config.maxRetries}). ` +
        `Waiting ${(delay / 1000).toFixed(1)}s...`
      );
      await new Promise(r => setTimeout(r, delay));
    }
  }
  throw new Error('unreachable');
}
```

### Step 3: Queue-Based Rate Limiting

```typescript
import PQueue from 'p-queue';

// BambooHR unofficial guidance: stay under ~10 requests/second
const bamboohrQueue = new PQueue({
  concurrency: 3,         // Max 3 concurrent requests
  interval: 1000,         // Per 1-second window
  intervalCap: 8,         // Max 8 requests per second
});

async function rateLimitedRequest<T>(operation: () => Promise<T>): Promise<T> {
  return bamboohrQueue.add(() => withBambooHRRetry(operation));
}

// Usage — all requests go through the queue
const employees = await rateLimitedRequest(() => client.getDirectory());
const report = await rateLimitedRequest(() => client.customReport(['firstName', 'lastName']));

// Bulk operations automatically throttled
const employeeDetails = await Promise.all(
  employeeIds.map(id =>
    rateLimitedRequest(() => client.getEmployee(id, ['firstName', 'lastName', 'jobTitle']))
  ),
);
```

### Step 4: Reduce Request Volume

**Use custom reports instead of individual GETs:**

```typescript
// BAD: N+1 requests (one per employee)
const employees = await client.getDirectory();
for (const emp of employees.employees) {
  const detail = await client.getEmployee(emp.id, ['salary', 'department']);
  // 500 employees = 501 requests
}

// GOOD: 1 request using custom report
const report = await client.customReport([
  'firstName', 'lastName', 'department', 'jobTitle', 'hireDate',
]);
// 1 request, all employee data
```

**Use incremental sync:**

```typescript
// BAD: Full directory pull every time
const allEmployees = await client.getDirectory();

// GOOD: Only changed employees since last sync
const changed = await client.request<any>(
  'GET', `/employees/changed/?since=${lastSyncTimestamp}`,
);
// Only fetch details for employees that actually changed
```

**Use table changed endpoint:**

```typescript
// GET /employees/changed/tables/{tableName}?since=...
const changedJobs = await client.request<any>(
  'GET', `/employees/changed/tables/jobInfo?since=${lastSyncTimestamp}`,
);
```

### Step 5: Monitor Rate Limit Usage

```typescript
class BambooHRRateLimitMonitor {
  private requestLog: { timestamp: number; status: number }[] = [];
  private rateLimitHits = 0;

  recordRequest(status: number) {
    this.requestLog.push({ timestamp: Date.now(), status });

    // Only keep last 5 minutes
    const cutoff = Date.now() - 5 * 60 * 1000;
    this.requestLog = this.requestLog.filter(r => r.timestamp > cutoff);

    if (status === 503 || status === 429) {
      this.rateLimitHits++;
    }
  }

  getStats() {
    const recent = this.requestLog;
    return {
      requestsLast5Min: recent.length,
      requestsPerSecond: (recent.length / 300).toFixed(2),
      rateLimitHits: this.rateLimitHits,
      errorRate: recent.filter(r => r.status >= 400).length / Math.max(recent.length, 1),
    };
  }

  shouldBackOff(): boolean {
    const stats = this.getStats();
    return stats.errorRate > 0.1 || parseFloat(stats.requestsPerSecond) > 8;
  }
}
```

## Output

- Retry logic honoring `Retry-After` header
- Queue-based throttling preventing rate limit hits
- Request volume reduction via custom reports and incremental sync
- Rate limit monitoring with stats

## Error Handling

| Signal | Detection | Action |
|--------|-----------|--------|
| `503` + `Retry-After: N` | Check response status + header | Wait N seconds, then retry |
| `503` without `Retry-After` | Status only | Exponential backoff from 1s |
| `429` (employee limit) | Status code | Contact BambooHR to increase limit |
| Many consecutive 503s | Monitor hit count | Pause all requests for 60s |

## Enterprise Considerations

- **Multi-tenant rate limits**: Each company domain has independent rate limits
- **Batch jobs**: Run large syncs during off-peak hours (nights/weekends)
- **Contact BambooHR**: For enterprise-volume needs, request rate limit increases through support
- **Webhook alternatives**: Use webhooks for real-time changes instead of polling (see `bamboohr-webhooks-events`)

## Resources

- [BambooHR API Technical Overview](https://documentation.bamboohr.com/docs/api-details)
- [p-queue Documentation](https://github.com/sindresorhus/p-queue)

## Next Steps

For security configuration, see `bamboohr-security-basics`.

Related Skills

workhuman-rate-limits

1868
from jeremylongshore/claude-code-plugins-plus-skills

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

1868
from jeremylongshore/claude-code-plugins-plus-skills

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

1868
from jeremylongshore/claude-code-plugins-plus-skills

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

1868
from jeremylongshore/claude-code-plugins-plus-skills

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

1868
from jeremylongshore/claude-code-plugins-plus-skills

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

1868
from jeremylongshore/claude-code-plugins-plus-skills

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

1868
from jeremylongshore/claude-code-plugins-plus-skills

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

1868
from jeremylongshore/claude-code-plugins-plus-skills

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

1868
from jeremylongshore/claude-code-plugins-plus-skills

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

1868
from jeremylongshore/claude-code-plugins-plus-skills

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

1868
from jeremylongshore/claude-code-plugins-plus-skills

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

1868
from jeremylongshore/claude-code-plugins-plus-skills

WebContainer resource limits: memory, CPU, file system size, process count. Use when working with WebContainers or StackBlitz SDK. Trigger: "webcontainer limits".