Skip to main content
bamboohr-sdk-patterns Apply production-ready BambooHR API patterns for TypeScript and Python.
Use when implementing BambooHR integrations, building reusable clients,
or establishing team coding standards for BambooHR REST API.
Trigger with phrases like "bamboohr SDK patterns", "bamboohr best practices",
"bamboohr code patterns", "idiomatic bamboohr", "bamboohr client wrapper".
跳到安装 Skills Marketplace 发现并探索由社区构建的 Agent Skills
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/jeremylongshore/claude-code-plugins-plus-skills --skill bamboohr-sdk-patterns命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
下载 Zip 下载中... 同仓库更多 Skills Implement user sign-up and sign-in flows with Clerk.
Use when building authentication UI, customizing sign-in experience,
or implementing OAuth social login.
Trigger with phrases like "clerk sign-in", "clerk sign-up",
"clerk login flow", "clerk OAuth", "clerk social login".
Implement session management and middleware with Clerk.
Use when managing user sessions, configuring route protection,
or implementing token refresh and custom JWT templates.
Trigger with phrases like "clerk session", "clerk middleware",
"clerk route protection", "clerk token", "clerk JWT".
Configure enterprise SSO, role-based access control, and organization management.
Use when implementing SSO integration, configuring role-based permissions,
or setting up organization-level controls.
Trigger with phrases like "clerk SSO", "clerk RBAC",
"clerk enterprise", "clerk roles", "clerk permissions", "clerk organizations".
jeremylongshore
jeremylongshore/claude-code-plugins-plus-skills
打开 GitHub 仓库 name bamboohr-sdk-patterns description Apply production-ready BambooHR API patterns for TypeScript and Python.
Use when implementing BambooHR integrations, building reusable clients,
or establishing team coding standards for BambooHR REST API.
Trigger with phrases like "bamboohr SDK patterns", "bamboohr best practices",
"bamboohr code patterns", "idiomatic bamboohr", "bamboohr client wrapper".
allowed-tools Read, Write, Edit version 1.4.0 license MIT author Jeremy Longshore <jeremy@intentsolutions.io> tags ["saas","hr","bamboohr","patterns"] compatibility Designed for Claude Code
BambooHR SDK Patterns
Overview
Production-ready patterns for the BambooHR REST API. BambooHR has no official Node.js SDK — you call the API directly via fetch or axios. These patterns wrap the raw HTTP calls into type-safe, retry-aware, multi-tenant-ready code.
Prerequisites
Completed bamboohr-install-auth setup
Familiarity with async/await and TypeScript generics
Instructions
Step 1: Type-Safe Client with Error Handling
import 'dotenv/config' ;
export interface BambooHRConfig {
companyDomain : string ;
apiKey : string ;
timeoutMs ?: number ;
}
export interface BambooEmployee {
id : string ;
firstName : string ;
lastName : string ;
displayName : string ;
jobTitle : string ;
department : string ;
division : string ;
workEmail : string ;
location : string ;
status : string ;
hireDate : string ;
supervisor : string ;
employeeNumber : string ;
photoUrl ?: ;
}
{
: ;
: ;
: ;
( ) {
. = ;
. = ;
. = config. ?? ;
}
request<T>( : , : , ?: ): <T> {
controller = ();
timer = ( controller. (), . );
{
res = ( , {
method,
: {
: . ,
: ,
...(body ? { : } : {}),
},
: body ? . (body) : ,
: controller. ,
});
(!res. ) {
errMsg = res. . ( ) || res. ;
(res. , errMsg, path, {
: res. . ( ),
});
}
text = res. ();
text ? . (text) : ({} T);
} {
(timer);
}
}
( ) {
. < < , >>( , );
}
( ) {
. <{ : []; : [] }>( , );
}
( ) {
. <{ : { : } }>( , , data);
}
( ) {
. < >( , , data);
}
( ) {
. <{ : ; : < , >[] }>(
, ,
{ : , fields, filters },
);
}
( ) {
params = ({ start, end, ...(status && { status }) });
. < []>( , );
}
( ) {
. < []>( , );
}
( ) {
. < >( , , data);
}
}
{
( ) {
( );
. = ;
}
(): {
. === || . === || . >= ;
}
}
string
export
class
BambooHRClient
private
base
string
private
auth
string
private
timeout
number
constructor
config : BambooHRConfig
this
base
`https://api.bamboohr.com/api/gateway.php/${config.companyDomain} /v1`
this
auth
`Basic ${Buffer.from (`${config.apiKey} :x` ).toString('base64' )} `
this
timeout
timeoutMs
30_000
async
method
string
path
string
body
unknown
Promise
const
new
AbortController
const
setTimeout
() =>
abort
this
timeout
try
const
await
fetch
`${this .base} ${path} `
headers
Authorization
this
auth
Accept
'application/json'
'Content-Type'
'application/json'
body
JSON
stringify
undefined
signal
signal
if
ok
const
headers
get
'X-BambooHR-Error-Message'
statusText
throw
new
BambooHRApiError
status
retryAfter
headers
get
'Retry-After'
const
await
text
return
JSON
parse
as
finally
clearTimeout
async
getEmployee
id : number | string , fields : string []
return
this
request
Record
string
string
'GET'
`/employees/${id} /?fields=${fields.join(',' )} `
async
getDirectory
return
this
request
fields
any
employees
BambooEmployee
'GET'
'/employees/directory'
async
addEmployee
data : { firstName: string ; lastName: string ; [k: string ]: string }
return
this
request
headers
location
string
'POST'
'/employees/'
async
updateEmployee
id : number | string , data : Record <string , string >
return
this
request
void
'POST'
`/employees/${id} /`
async
customReport
fields : string [], filters ?: Record <string , any >
return
this
request
title
string
employees
Record
string
string
'POST'
'/reports/custom?format=JSON'
title
'Custom Report'
async
getTimeOffRequests
start : string , end : string , status ?: string
const
new
URLSearchParams
return
this
request
any
'GET'
`/time_off/requests/?${params} `
async
getTableRows
employeeId : number | string , table : string
return
this
request
any
'GET'
`/employees/${employeeId} /tables/${table} `
async
addTableRow
employeeId : number | string , table : string , data : Record <string , string >
return
this
request
void
'POST'
`/employees/${employeeId} /tables/${table} `
export
class
BambooHRApiError
extends
Error
constructor
public status : number ,
message : string ,
public path : string ,
public meta : { retryAfter?: string | null } = {},
super
`BambooHR ${status} : ${message} [${path} ]`
this
name
'BambooHRApiError'
get
retryable
boolean
return
this
status
429
this
status
503
this
status
500
Step 2: Retry Wrapper with Exponential Backoff
import { BambooHRApiError } from './client' ;
export async function withRetry<T>(
operation : () => Promise <T>,
maxRetries = 3 ,
baseMs = 1000 ,
): Promise <T> {
for (let attempt = 0 ; attempt <= maxRetries; attempt++) {
try {
return await operation ();
} catch (err) {
if (attempt === maxRetries) throw err;
if (err instanceof BambooHRApiError && !err.retryable ) throw err;
const retryAfter = err instanceof BambooHRApiError ? err.meta .retryAfter : null ;
const delay = retryAfter
? parseInt (retryAfter, 10 ) * 1000
: baseMs * Math .pow (2 , attempt) + Math .random () * 500 ;
console .warn (`Retry ${attempt + 1 } /${maxRetries} in ${delay.toFixed(0 )} ms` );
await new Promise (r => setTimeout (r, delay));
}
}
throw new Error ('unreachable' );
}
Step 3: Multi-Tenant Factory
import { BambooHRClient , BambooHRConfig } from './client' ;
const tenantClients = new Map <string , BambooHRClient >();
export function getClientForTenant (tenantDomain : string , apiKey : string ): BambooHRClient {
if (!tenantClients.has (tenantDomain)) {
tenantClients.set (tenantDomain, new BambooHRClient ({ companyDomain : tenantDomain, apiKey }));
}
return tenantClients.get (tenantDomain)!;
}
export function clearTenantClients ( ) {
tenantClients.clear ();
}
Step 4: Zod Response Validation import { z } from 'zod' ;
const EmployeeSchema = z.object ({
id : z.string (),
firstName : z.string (),
lastName : z.string (),
displayName : z.string (),
jobTitle : z.string ().default ('' ),
department : z.string ().default ('' ),
workEmail : z.string ().email ().optional (),
status : z.enum (['Active' , 'Inactive' ]).default ('Active' ),
hireDate : z.string ().regex (/^\d{4}-\d{2}-\d{2}$/ ).optional (),
});
const DirectorySchema = z.object ({
employees : z.array (EmployeeSchema ),
});
const raw = await client.getDirectory ();
const validated = DirectorySchema .parse (raw);
Python Equivalent import os, requests
from dataclasses import dataclass
from typing import Optional
@dataclass
class BambooHRClient :
company_domain: str = ""
api_key: str = ""
def __post_init__ (self ):
self .company_domain = self .company_domain or os.environ["BAMBOOHR_COMPANY_DOMAIN" ]
self .api_key = self .api_key or os.environ["BAMBOOHR_API_KEY" ]
self .base = f"https://api.bamboohr.com/api/gateway.php/{self.company_domain} /v1"
self .session = requests.Session()
self .session.auth = (self .api_key, "x" )
self .session.headers.update({"Accept" : "application/json" })
def get_employee (self, emp_id: int , fields: list [str ] ) -> dict :
r = self .session.get(f"{self.base} /employees/{emp_id} /" ,
params={"fields" : "," .join(fields)})
r.raise_for_status()
return r.json()
def get_directory (self ) -> dict :
r = self .session.get(f"{self.base} /employees/directory" )
r.raise_for_status()
return r.json()
def custom_report (self, fields: list [str ] ) -> dict :
r = self .session.post(f"{self.base} /reports/custom" ,
params={"format" : "JSON" },
json={"title" : "Report" , "fields" : fields})
r.raise_for_status()
return r.json()
Output
Type-safe client with all major BambooHR endpoints
Custom error class with retryable flag and Retry-After support
Exponential backoff retry wrapper
Multi-tenant factory pattern
Zod runtime validation for API responses
Error Handling Pattern Use Case Benefit BambooHRApiErrorAll API calls Structured errors with HTTP status withRetry()429/5xx transient failures Automatic recovery Zod schemas Response validation Catch API changes early Multi-tenant factory SaaS/multi-company Isolated credentials per tenant
Resources
Next Steps Apply these patterns in bamboohr-core-workflow-a for employee management workflows.