From bamboohr-pack
Diagnoses BambooHR REST API errors like 401, 403, 400, 429 via X-BambooHR-Error-Message header. Provides causes, curl auth tests, and fixes for invalid keys, permissions, payloads.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin bamboohr-packThis skill is limited to using the following tools:
Diagnostic reference for BambooHR REST API errors. BambooHR returns error details in the `X-BambooHR-Error-Message` response header for most 400-level and some 500-level errors.
Provides TypeScript and Python patterns for production BambooHR REST API clients with type safety, retries, auth, and error handling. For integrations and reusable wrappers.
Provides solutions for RemoFirst API errors including 401 unauthorized, 429 rate limits, and 422 validation in Python for global HR, EOR, payroll integrations.
Guides Next.js Cache Components and Partial Prerendering (PPR): 'use cache' directives, cacheLife(), cacheTag(), revalidateTag() for caching, invalidation, static/dynamic optimization. Auto-activates on cacheComponents: true.
Share bugs, ideas, or general feedback.
Diagnostic reference for BambooHR REST API errors. BambooHR returns error details in the X-BambooHR-Error-Message response header for most 400-level and some 500-level errors.
Always check X-BambooHR-Error-Message first — it contains BambooHR's specific error detail, which is more useful than generic HTTP status text.
const res = await fetch(`${BASE}/employees/999/`, {
headers: { Authorization: AUTH, Accept: 'application/json' },
});
if (!res.ok) {
const errorDetail = res.headers.get('X-BambooHR-Error-Message');
console.error(`HTTP ${res.status}: ${errorDetail || res.statusText}`);
}
X-BambooHR-Error-Message: Invalid API key
Cause: API key is missing, expired, revoked, or malformed in the Basic Auth header.
Solution:
# Verify key is set
echo "Key length: ${#BAMBOOHR_API_KEY}"
# Test auth directly
curl -s -o /dev/null -w "%{http_code}" \
-u "${BAMBOOHR_API_KEY}:x" \
"https://api.bamboohr.com/api/gateway.php/${BAMBOOHR_COMPANY_DOMAIN}/v1/employees/directory"
Common mistakes:
:x password part in Basic Auth encodingX-BambooHR-Error-Message: You do not have access to this resource
Cause: The API key's user account lacks permissions for the requested endpoint or employee.
Solution:
X-BambooHR-Error-Message: Invalid field: "jobTitl"
Cause: Misspelled field name, invalid date format, or malformed JSON body.
Solution:
# Verify field names against BambooHR's field list
curl -s -u "${BAMBOOHR_API_KEY}:x" \
"https://api.bamboohr.com/api/gateway.php/${BAMBOOHR_COMPANY_DOMAIN}/v1/employees/0/?fields=firstName,lastName" \
-H "Accept: application/json"
Common field name mistakes:
title (wrong) vs jobTitle (correct)email (wrong) vs workEmail (correct)name (wrong) vs firstName + lastName (correct)YYYY-MM-DD, not MM/DD/YYYYX-BambooHR-Error-Message: Employee not found
Cause: Employee ID does not exist, wrong company domain, or malformed URL path.
Solution:
# Verify company domain
echo "Domain: $BAMBOOHR_COMPANY_DOMAIN"
# Verify the base URL structure
# Correct: /api/gateway.php/{domain}/v1/employees/{id}/
# Wrong: /api/v1/employees/{id}/
# Wrong: /api/gateway.php/{domain}/employees/{id}/ (missing /v1/)
HTTP 503 with Retry-After: 30
Cause: Too many requests in a short period. BambooHR does not publish exact rate limits but returns 503 with a Retry-After header.
Solution:
async function handleRateLimit(res: Response): Promise<void> {
if (res.status === 503 || res.status === 429) {
const retryAfter = parseInt(res.headers.get('Retry-After') || '30', 10);
console.warn(`Rate limited. Waiting ${retryAfter}s...`);
await new Promise(r => setTimeout(r, retryAfter * 1000));
}
}
Prevention:
/employees/changed/?since=... for incremental sync instead of full pullsCause: BambooHR internal error. Usually transient.
Solution:
bamboohr-rate-limits)Cause: Missing Accept: application/json header — BambooHR defaults to XML.
# Wrong — returns XML
curl -u "${BAMBOOHR_API_KEY}:x" \
"${BASE}/employees/directory"
# Correct — returns JSON
curl -u "${BAMBOOHR_API_KEY}:x" \
-H "Accept: application/json" \
"${BASE}/employees/directory"
#!/bin/bash
echo "=== BambooHR Diagnostic ==="
echo "Company: ${BAMBOOHR_COMPANY_DOMAIN}"
echo "Key set: ${BAMBOOHR_API_KEY:+YES}"
echo "Key length: ${#BAMBOOHR_API_KEY}"
BASE="https://api.bamboohr.com/api/gateway.php/${BAMBOOHR_COMPANY_DOMAIN}/v1"
echo -n "Auth test: "
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -u "${BAMBOOHR_API_KEY}:x" \
-H "Accept: application/json" "${BASE}/employees/directory")
echo "$STATUS"
echo -n "Status page: "
curl -s https://status.bamboohr.com | head -c 100
echo ""
if [ "$STATUS" -eq 200 ]; then
echo "Connection OK"
elif [ "$STATUS" -eq 401 ]; then
echo "FIX: Regenerate API key in BambooHR dashboard"
elif [ "$STATUS" -eq 403 ]; then
echo "FIX: Upgrade API key user's access level"
elif [ "$STATUS" -eq 404 ]; then
echo "FIX: Check BAMBOOHR_COMPANY_DOMAIN value"
else
echo "FIX: Check status page and retry"
fi
X-BambooHR-Error-Message header| Status | Header | Root Cause | Fix |
|---|---|---|---|
| 400 | Invalid field | Typo in field name | Check field list docs |
| 401 | Invalid API key | Bad credentials | Regenerate API key |
| 403 | No access | Insufficient permissions | Upgrade user access level |
| 404 | Not found | Wrong ID or domain | Verify URL components |
| 429/503 | Retry-After | Rate limited | Backoff and retry |
| 500/502 | — | Server error | Retry; check status page |
For comprehensive debugging, see bamboohr-debug-bundle.