---
name: bamboohr-oauth-app
description: Obtains BambooHR API credentials — either an OAuth2 client ID and secret registered in the BambooHR Developer Portal (self-registration has been open since April 2025), or the per-customer API key plus company subdomain that most BambooHR integrations still run on. Covers redirect URIs, the 220-scope catalog, the permission inheritance that silently returns partial data, rate limits, sandbox access, and the Marketplace listing gate. Use when asked to get BambooHR OAuth credentials, register a BambooHR app, set up a BambooHR developer or test account, help a customer create or rotate a BambooHR API key, or fix a BambooHR auth error like a 404 on a list endpoint, a missing refresh token, or a redirect URI mismatch. For any other vendor's developer portal, use that vendor's skill instead.
---

# BambooHR API Credentials

**Read this before you start: BambooHR has two credential models, and the one you need may not be OAuth.**

1. **Per-user API key + company subdomain, over HTTP Basic auth.** This is what most BambooHR integrations run on
   today. It needs no relationship with BambooHR at all: each customer generates a key inside their own account and
   hands it to you with their subdomain. It is still fully documented and most endpoints accept it.
2. **OAuth2 authorization code, with a client ID and secret from the BambooHR Developer Portal.** Historically this
   was partner-gated — you had to contact BambooHR. **Since 2025-04-15 developers can self-register** at
   `https://developers.bamboohr.com`, register an organization, create an application, pick scopes, and get a client
   ID and secret without a partnership. What remains gated is *production* standing: the Developer Terms let BambooHR
   require review and approval before granting production access, and a **Marketplace listing plus a sandbox account
   still require the Marketplace Partner Program** (which has a 100-customer bar and a security-audit requirement).

So: you can almost certainly get OAuth credentials by yourself. You cannot get a sandbox, a listing, or a guarantee of
production standing by yourself. Decide which of those you actually need before doing anything (§1).

Three things about this platform are expensive to get wrong, whichever model you pick. **Every host is per-customer** —
authorize, token and API all live on `https://{companyDomain}.bamboohr.com`, so your connect flow must collect the
subdomain *before* it can even build an authorize URL. **The credential inherits the permissions of the user behind
it**, so a key or token from a limited user returns `200` with partial data rather than an error — the single most
misdiagnosed BambooHR problem (§8). And **BambooHR answers some list endpoints with `404` when credentials are bad**,
so "not found" is routinely an auth failure wearing a disguise (§10).

## Inputs to collect before you start

Ask in one batch. Never invent.

| Input | Notes |
| --- | --- |
| **Which credential model** | OAuth app, per-customer API keys, or both (§1) |
| **New app or edit to an existing one** | A new client ID re-authorizes every existing OAuth connection (§1) |
| **Developer Portal account owner** | Email and organization name; who accepts the Developer Terms (§2) |
| **App name, description, logo** | Shown to the customer's user during authorization (§3) |
| **Redirect URIs** | Every callback host you serve, exact strings (§4) |
| **Scope set** | Which objects the connector reads and writes (§5) |
| **Test BambooHR account** | Which account to develop against; the Terms cap you at two (§2) |
| **Customer subdomain(s)** | Needed for any real authorize or API call (§7) |
| **Are you pursuing a Marketplace listing?** | Business decision — do not assume either way (§9) |

## Quick Start

1. Pick the credential model, and confirm whether a **new** OAuth app is really needed (§1).
2. Self-register at the Developer Portal and create/claim a test BambooHR account (§2).
3. Register the application: organization → app → scopes → redirect URIs (§3).
4. Add **every** redirect URI, exactly (§4).
5. Select scopes from BambooHR's published catalog — include `openid` and `offline_access` (§5).
6. Check what the connector on your side actually expects before you commit to a scope set (§6).
7. Capture client ID and secret; for the API-key path, walk the customer through key creation instead (§7).
8. Work out which **user** the credential belongs to — this decides what data you get (§8).
9. Check rate limits, production review and the listing gate (§9), then verify end to end (§10) and hand off (§11).

## Platform state (verified 2026-09-20 — re-verify before trusting)

Dates below are BambooHR's own changelog entries. If the portal or docs do not look like this, stop and report what
you actually see rather than clicking on.

- **2025-03-31 — OAuth 2.0 became the primary documented auth method**, replacing legacy API-key generation via
  `oidcLogin`.
- **2025-04-14 — new applications can no longer use `oidcLogin`** (the OpenID Connect → `id_token` → BambooHR API key
  flow). Existing apps may keep using it with the `legacy.login` scope. If you are reading an older runbook that
  exchanges an ID token plus an "Application Key" for a user's API key, that path is closed to you.
- **2025-04-15 — Developer Portal self-registration opened.** Register your organization, create an application,
  select scopes, obtain client ID and secret. Before this you had to contact BambooHR directly.
- **2025-05-12 — `POST /api/v1/login` marked deprecated**, OAuth 2.0 recommended. No sunset date has been set, and
  BambooHR states that a deprecated label alone does not announce a cutoff.
- **2025-07-03 — API routing centralized** to `https://{companyDomain}.bamboohr.com/api/`, replacing
  `https://api.bamboohr.com/api/gateway.php/{companyDomain}/`. The old structure still works; new work uses the new one.
- **2026-02-18 — send credentials on every request.** BambooHR still returns `401` with `WWW-Authenticate: Basic
  realm="..."` when credentials are absent; clients that wait for that challenge double their round trips and burn
  rate-limit budget. That header will not be included in future API versions.
- **2026-09-16 (four days ago) — rate-limited requests now return `429` with `Retry-After`, not `503`.** The limits
  themselves did not change. `503` now means genuine unavailability. Note the collision this creates: `429` was
  already documented as "the account has reached its employee limit" (§10).
- **API keys are not deprecated.** Endpoint documentation added through 2026 keeps saying "supports both Basic Auth
  and OAuth 2.0". Treat Basic auth as a first-class path, not a legacy one.
- **The scope catalog is published.** The OpenAPI security scheme behind the API reference carries **220 named
  scopes** (counted 2026-09-20), with `/authorize.php` and `/token.php` as relative authorize and token URLs — they
  are relative because the host is the customer's.

## 1. Decide: which model, and reuse or register new

**Choose the credential model first.**

- **API key + subdomain** — no BambooHR relationship, no review, no app. The customer does the work; you do onboarding
  UX. The costs are all operational: keys are tied to a human user and die when that user is disabled (§8).
- **OAuth2** — better security story, granular scopes, refresh tokens, and the model BambooHR steers new integrations
  toward. Costs: a Developer Portal app, a redirect-URI registration, scope selection, and exposure to the production
  review clause in the Developer Terms.
- **Both** is common and usually right for a multi-tenant connector: OAuth for new customers, API keys for those who
  will not run an OAuth flow.

**Then decide reuse vs new.** A new OAuth app means a **new client ID**, and every existing OAuth connection is bound
to the old one — every customer would re-authorize. Reuse the existing app for: adding a redirect URI, adding a scope,
rotating a compromised secret, or diagnosing a failure. Register a new app only when the user explicitly wants one (a
replacement for a compromised app, a separate product, a deliberate migration off `oidcLogin`). Say which path you are
taking before you touch the portal.

## 2. Accounts: Developer Portal and something to test against

**Developer Portal** — `https://developers.bamboohr.com/login`. Free account, self-registration open since 2025-04-15.
Use of the portal is subject to the BambooHR Developer Terms of Service, which the account owner accepts.

**Something to develop against.** BambooHR's own getting-started list includes "create a test BambooHR account to
develop against". The Developer Terms constrain this sharply, and these are the constraints most likely to trip up
automated testing:

- **No more than two test accounts.**
- **Fake or dummy data only** — no customer integration data in a test account.
- **Test accounts must be used manually.** No scripts or bots to generate or drive them.

A free-trial account (`https://www.bamboohr.com/signup/`) is the usual way to get one. A *sandbox* in BambooHR's sense
is different: it is provisioned once you are accepted into the Marketplace Partner Program (§9).

**Human-only steps.** Email verification, MFA, accepting the Developer Terms, signing the Marketplace Agreement,
submitting a W-9/W-8 — hand these back rather than looping on them.

**If this session has no browser automation** (the usual case for a CLI or cloud run), do not pretend to click. Give
the user an exact ordered click path with the literal values to paste — the redirect URIs from §4 and the scope list
from §5 — and continue once they report back with the client ID.

## 3. Register the application

In the Developer Portal: register your **organization**, then create an **application**, **select the scopes** it
needs, and **register its redirect URIs**. That sequence is BambooHR's own description of self-registration; the exact
field labels are behind a portal login and are not published, so **report what the form actually shows** rather than
asserting the shape of it. If the portal asks for something this skill does not mention — an environment toggle, a
review submission, a company-verification step — write it down and add it here afterwards.

The portal is also where redirect URIs are managed after creation, per BambooHR's Marketplace requirements.

## 4. Redirect URIs

Register **every** callback host your platform serves. For Unified.to these are one per data center; confirm the
current list with the platform owner rather than assuming:

```
https://api.unified.to/oauth/code          # us (default)
https://api-eu.unified.to/oauth/code       # eu
https://api-au.unified.to/oauth/code       # au
https://api-dev.unified.to/oauth/code      # dev
```

Notes that cost a cycle each:

- **Exact match.** BambooHR's docs are explicit: "even small differences (such as an extra slash or capitalization
  change) can cause authentication errors." The same string must appear in the authorize request *and* the token
  exchange, where `redirect_uri` is a required parameter for both `authorization_code` and `refresh_token` grants.
- **The redirect URI is yours and constant; the authorize host is the customer's.** The authorize host
  `https://{companyDomain}.bamboohr.com/authorize.php` changes per customer, the callback does not. One serves every
  tenant; carry the tenant in `state`, which is exactly how BambooHR's own partner OIDC guidance says to do it.
- **Whether the portal accepts several redirect URIs per app is not documented publicly.** BambooHR's partner guidance
  talks about whitelisting URIs (plural) and routing tenants via `state`, but confirm in the portal. If an app accepts
  only one, that is a finding to report — a separate app per data center, or a single shared callback host, is an
  architecture decision, not something to improvise.

## 5. Scopes

Scopes are **space-delimited**, which in the authorize URL means `+`-joined:

```
https://{companyDomain}.bamboohr.com/authorize.php?request=authorize&state=<state>&response_type=code
    &scope=openid+offline_access+employee+employee:job&client_id=<client id>&redirect_uri=<registered URI>
```

Two are structural rather than data-bearing:

| Scope | Why |
| --- | --- |
| `openid` | "Allows the application to authenticate with BambooHR" |
| `offline_access` | **The refresh token is only returned if `offline_access` was in the original authorize request.** Add it later and every already-authorized customer is still without a refresh token. |

The rest are data scopes, `.write` suffixed for mutation. A sample of the ones an HRIS/ATS connector reaches for, with
BambooHR's own descriptions:

| Scope | Covers |
| --- | --- |
| `employee` / `employee.write` | All non-sensitive employee information |
| `employee:job`, `employee:compensation`, `employee:contact`, `employee:name`, `employee:custom_fields`, … | Per-field-group employee access, each with a `.write` twin |
| `sensitive_employee:address`, `sensitive_employee:protected_info`, `sensitive_employee:creditcards` | Sensitive employee data, separated deliberately |
| `time_off` / `time_off.write`, `time_off:requests`, `time_off:policies`, `time_off:categories` | Time off |
| `time_tracking` (+ `:timesheets`, `:configurations`, `:employees`, `:kiosks`, `:time_clocks`, …) | Hours worked and time-tracking administration |
| `scheduling:shifts`, `scheduling:schedules` | Shifts within schedules |
| `hiring:applications`, `hiring:job_openings`, `hiring:offers`, `hiring:talent_pools` | ATS |
| `company:info`, `company:details`, `company_file` | Company data and files |
| `report`, `benefit`, `holidays`, `training`, `goal`, `user`, `webhooks` | Reports, benefits, holidays, training, goals, users, webhooks |

Three traps here:

- **There is no single scopes page in the guides.** The catalog lives in the OpenAPI security scheme behind the API
  reference (220 scopes on 2026-09-20) and in the portal's scope picker; individual endpoint pages and changelog
  entries name the scope each operation needs. Read the endpoint you actually call.
- **Naming is not uniform across families.** The catalog uses `employee:job`, while BambooHR's own List Employees
  announcement names `employees.read`, `employees:name.read` and `employees:job.read`. Do not extrapolate a scope
  string from a sibling — look it up on the endpoint page, and test it.
- **`email` is documented for SSO, not for the API.** BambooHR's OpenID Connect SSO guide uses `openid email
  company_id`, but `email` and `company_id` are **not** in the API scope catalog. If your authorize request carries
  `email`, verify it is accepted rather than assuming it is harmless.

Ask for what the connector calls and no more. Scopes cap what a token may request; they never exceed what the
authorizing user may do (§8).

## 6. What Unified.to's BambooHR connector expects

**As of 2026-09-20, Unified.to's BambooHR connector supports both credential models.** Treat this as a dated
observation and **confirm it with the connector's owner before registering anything** — connector configuration
changes more often than a vendor portal does.

- **Both auth types are configured**: a token/Basic-auth connection built from an **API key plus the company
  subdomain** (the key is sent as the Basic username with a throwaway password), and an **OAuth2 authorization-code**
  connection.
- **The subdomain is collected from the customer as a first-class credential**, alongside the key or the OAuth
  credentials, because every host is per-company. The OAuth configuration is explicitly marked as needing that
  subdomain, and also as needing a **developer/application key** in addition to client ID and secret — worth
  clarifying with the owner, since the developer-key requirement belongs to the retired `oidcLogin` flow (§Platform
  state) rather than to current OAuth2.
- **Hosts** are `https://{subdomain}.bamboohr.com/api` for the API, `https://{subdomain}.bamboohr.com/authorize.php`
  for authorization and `https://{subdomain}.bamboohr.com/token.php` for the token exchange — the per-company form,
  not the retired `api.bamboohr.com/api/gateway.php/...` gateway.
- **Every authorization requests `openid`, `email` and `offline_access`**, plus per-object scopes: the `hiring:*`
  family for ATS objects, `company_file` for documents, the `employee:*` and `sensitive_employee:*` families plus
  `report` for employees, `time_off` and `user` for time off, `time_tracking` and `scheduling:shifts` for attendance
  and shifts, `company:info` for locations, and `benefit` for benefits. Note `email` against the §5 warning, and note
  that at least one time-tracking scope was recorded as inferred by analogy rather than read off BambooHR's catalog.
- **BambooHR's sandbox is recorded as not self-serve**, gated on acceptance into the Marketplace Partner Program.
- **The connector translates certain `404`s into auth errors**, because BambooHR returns `404` rather than `401` on
  several list endpoints when credentials are invalid. That is a real platform behaviour, not a local workaround (§10).

## 7. Capture the credentials

### OAuth app

From the Developer Portal application: **client ID** and **client secret**. Assume the secret is shown once and
capture it immediately; if the portal lets you re-read it, note that here. Record alongside it:

- Authorize URL: `https://{companyDomain}.bamboohr.com/authorize.php?request=authorize`
- Token URL: `https://{companyDomain}.bamboohr.com/token.php?request=token`
- The exact scope string you registered, and the exact redirect URIs

The token response looks like this — `expires_in` is **3600 seconds**, and `refresh_token` appears only if
`offline_access` was requested:

```
{ "access_token": "...", "expires_in": 3600, "token_type": "Bearer", "scope": "<space separated>",
  "refresh_token": "...", "id_token": "...", "companyDomain": "<your company domain>" }
```

Refreshing posts `grant_type=refresh_token` with `client_id`, `client_secret`, `refresh_token` **and `redirect_uri`**
to the same token URL. BambooHR's documentation shows both exchanges as a JSON-looking body without naming a content
type; if the exchange is rejected without a useful message, try the other encoding before assuming the credentials are
wrong (§10).

Rotating the secret invalidates the old one: existing access tokens live out their hour, but every exchange and
refresh fails until the new secret is deployed. Never rotate without explicit go-ahead and a cutover plan.

### Per-customer API key

This is the path the customer walks, so give them the steps rather than doing it for them:

1. Sign in to BambooHR and open the **user context menu** from their name. BambooHR's docs say lower-left; some UI
   versions put it upper-right. Admins also reach key management at **Settings → Account → API Keys**.
2. Choose **API Keys**. The option only appears if the user has sufficient permission.
3. Create a key and **name it** — naming is required, and an unnamed pile of 160-bit hex strings is unmanageable.
4. **Copy it immediately.** Since 2018, keys are encrypted after creation and cannot be retrieved again; a lost key
   must be replaced.
5. Send you the key **and the company subdomain** — the text before `.bamboohr.com` in their login URL.

The key is used as the HTTP Basic **username**, with any string as the password:

```
curl -i -u "{API Key}:x" "https://{companyDomain}.bamboohr.com/api/v1/employees/directory"
```

Account Owners and Admins can see every key connected to their account — creator, name, created and last-used date —
and can **disable** keys (reversibly, in bulk) or delete them. Disabling is the safe first move during an incident;
deletion is permanent.

## 8. Permissions: what the credential can actually see

**This is the section that prevents the classic misdiagnosis.**

BambooHR authenticates and permissions every API request "as if a real user were using the software". The permissions
of the user behind the credential determine which employees and which fields the request may read or edit. Scopes sit
*on top of* that: a scope can narrow access, never widen it.

The failure mode is quiet. A key created by a department manager returns `200 OK` with the employees that manager can
see — a subset — and omits field groups they cannot view. Nothing errors. The integration looks like it is syncing;
it is syncing a fraction of the company, and the gap surfaces weeks later as "your sync is missing people".

What to do about it:

- Have the customer create the key (or authorize the OAuth flow) as a **user whose access level covers everything the
  integration must read**, ideally a dedicated service user rather than a person who will change roles or leave.
- Say plainly that a key **dies when its user is disabled or deleted**, and that admins can disable or delete any key
  in the account. Offboarding an employee is a common cause of a connection that "suddenly stopped".
- Know the documented carve-outs. Since 2025-03-10, only **admin** users can retrieve user email addresses from
  `/v1/meta/users/`. Permissioned webhooks are likewise tied to the access level of the user who created them.
- When data looks partial, **compare against what that user sees in the BambooHR UI** before touching code. If the UI
  shows the same subset, the integration is correct and the permission grant is the bug.

## 9. Rate limits, production review, sandbox and the Marketplace

**Rate limits.** BambooHR publishes no numeric limits and reserves the right in the Developer Terms to impose or
adjust them at its discretion. What is documented:

- Requests deemed too frequent are throttled. Since **2026-09-16** that is `429` with a **`Retry-After`** header;
  before then it was `503`. Honour `Retry-After`.
- Repeated use of an **unknown API key** disables API access for a period, returning `403` while the block lasts. The
  user can still log in to the website, which makes this easy to misread as a permissions problem.
- Requests sent without credentials cost an extra round trip and consume budget — send credentials preemptively.

**Production review.** The Developer Terms state BambooHR may require new integrations, or material changes to
existing ones, to be submitted for review and approval **before granting or restoring production access**, and may
approve or reject at its sole discretion. Self-registration gets you credentials; it does not exempt you from this.

**Sandbox and Marketplace listing** are the same gate. The Marketplace Partner Program requires, per BambooHR's
published requirements: executing the Marketplace Agreement, a W-9 (or W-8), a **third-party security audit** (SOC 2
Type 1 or 2, ISO 27001, FedRAMP or HITRUST) or a security questionnaire, a Developer Portal account, and listing
assets (documentation, logo, 4–6 product images, a help guide, a demo URL). The public application page also asks for
**at least 100 total customers**, participation in Crossbeam, and a support-response commitment. **A sandbox account
is provided once you are accepted.**

Everything in that paragraph is a business decision — eligibility, security attestations, agreements, customer-count
claims. Do not answer any of it on the user's behalf; hand it back (§Stop and ask).

## 10. Verify end-to-end

Authorizing against your own test account proves less than it looks. Test the customer path:

1. Start from the **subdomain prompt** — confirm your connect flow collects it before building the authorize URL, and
   that a wrong subdomain fails visibly rather than silently.
2. Run a full authorize → callback → token exchange against a real company domain.
3. Confirm the response carries a **`refresh_token`** (it will not, without `offline_access`), then force a refresh
   and confirm the refreshed token still works.
4. Make one **read call per scope family** you registered, and compare the result against what the authorizing user
   sees in the BambooHR UI (§8).
5. For the API-key path, run the same read calls with `-u "{API Key}:x"` and the customer's subdomain.

| Symptom | Cause |
| --- | --- |
| `404` on a list endpoint that should have data | Very often bad or insufficient credentials — BambooHR returns `404` here instead of `401` (§6). Check the credential before hunting for the resource. |
| `401 Unauthorized` | No credentials sent. Send them preemptively rather than waiting for the `WWW-Authenticate` challenge. |
| `403 Forbidden` on some endpoints, `200` on others | The user's access level, not the scope set (§8). |
| `403` on everything, website login still fine | API access temporarily disabled after repeated use of an unknown API key (§9). Wait it out; fix the key. |
| `429` **with** `Retry-After` | Rate limited (since 2026-09-16). Back off for the stated interval. |
| `429` **without** `Retry-After` | Account employee limit reached — a completely different problem. Check the header before retrying. |
| `503` | Genuine unavailability. Since 2026-09-16 it no longer means rate limiting. |
| Token response has no `refresh_token` | `offline_access` was missing from the **original** authorize request. Re-authorize; a later scope change does not retrofit it. |
| Redirect/`redirect_uri` error | Not an exact match with the registered URI — trailing slash, case, scheme — or omitted from the token exchange (§4). |
| Authorize page 404s or shows the wrong company | Wrong `companyDomain` in the host. |
| Token exchange rejected with no useful message | Try the other body encoding before assuming the secret is wrong (§7). |
| Sync returns a subset of employees or missing fields | Permission inheritance (§8), not a mapping bug. |
| Connection worked for months, then stopped for one customer | Their key's user was disabled, or an admin deleted/disabled the key (§7, §8). |

## 11. Hand off — never commit the key or the secret

- **Do not** write a client secret or a customer API key into source control, a test, a fixture, a committed `.env`,
  a ticket, a PR body, or a chat channel. Values go to the user, for the secret store or console.
- **Do not paste a live key into a support email.** BambooHR's API support page asks for the call you made and your
  key/token details; send the endpoint, parameters and timestamps, and redact the credential.
- If a code change is needed (a new callback host, a scope, subdomain handling), keep it credential-free and say what
  the human must set out of band.
- Close with: which credential model; app name and Developer Portal organization; client ID; where the secret was
  delivered; the authorize/token URL shapes including the `{companyDomain}` placeholder; the exact scope string; the
  redirect URIs registered; which user the test credential belongs to and what access level it has; and anything left
  for the user to do.

## Stop and ask

Hand back to a human rather than guessing when: the work requires a sandbox, a Marketplace listing, or anything from
the partner application (security attestations, customer counts, agreements, W-9, Crossbeam) — these are business and
legal decisions; BambooHR asks you to submit the integration for production review; the Developer Portal allows only
one redirect URI per app and your platform needs four; a customer must create the credential under a higher access
level or a dedicated service user; a scope you need is absent from the published catalog (including `email`) and
behaviour must be tested rather than assumed; the connector's own expectations (§6) do not match what the portal
offers; or the portal and docs do not match the **Platform state** section above.

## References

Verified 2026-09-20 — every URL below returned HTTP 200.

- Getting Started With The API (OAuth flow, API keys, Basic auth) — https://documentation.bamboohr.com/docs/getting-started
- Technical Overview (status codes, throttling, `X-BambooHR-Error-Message`) — https://documentation.bamboohr.com/docs/api-details
- Historical Changes to the API (OAuth 2.0, `oidcLogin`, self-registration, routing) — https://documentation.bamboohr.com/docs/past-changes-to-the-api
- Planned Changes to the API (503 → 429, effective 2026-09-16) — https://documentation.bamboohr.com/docs/planned-changes-to-the-api
- API reference — carries the OAuth2 security scheme and its scope catalog — https://documentation.bamboohr.com/reference/list-employees
- API Support — https://documentation.bamboohr.com/docs/api-support
- Permissioned Webhooks (access-level inheritance) — https://documentation.bamboohr.com/docs/permissioned-webhooks
- Single Sign-On (SSO) with OpenID Connect — https://documentation.bamboohr.com/page/single-sign-on-sso-with-openid-connect
- Using OpenID Connect to Authenticate and Retrieve an API Key (the retired `oidcLogin` path) — https://documentation.bamboohr.com/page/authenticate-integration
- BambooHR Developer Portal — https://developers.bamboohr.com/login
- Developer Terms of Service (production review, test-account limits, rate limits) — https://www.bamboohr.com/legal/developer-terms-of-service
- Marketplace Program Requirements — https://www.bamboohr.com/partner-programs/marketplace-requirements
- Marketplace Application (eligibility bar) — https://www.bamboohr.com/partner-programs/apps-marketplace-application
- Partner Programs overview — https://www.bamboohr.com/partner-programs/overview
- Admin API Keys Settings — https://www.bamboohr.com/product-updates/admin-api-keys-settings
- API Key Management Enhancements (disable vs delete, last-used) — https://www.bamboohr.com/product-updates/api-key-management-enhancements
- Create a New API Key (customer-facing help article) — https://help.bamboohr.com/s/article/587919
- API Error Code Definitions (customer-facing help article) — https://help.bamboohr.com/s/article/587843
- BambooHR free-trial signup (test account) — https://www.bamboohr.com/signup/
