Planned Changes to the API
2026.02.17 – Best Practice: Always Send Credentials With API Requests
Effective February 28, 2026
In November 2025, we announced plans to remove the WWW-Authenticate: Basic realm="..." header from all API 401 responses. After further evaluation, we've taken a more targeted approach to avoid disrupting existing integrations.
Background
When an API request is made without credentials, BambooHR returns a 401 response with a WWW-Authenticate: Basic realm="..." header. Some HTTP clients use this as a signal to retry the request with credentials — a pattern known as HTTP authentication negotiation.
While this pattern is part of the HTTP specification, it has two drawbacks:
- It causes unexpected browser login prompts when a BambooHR session expires and the browser receives the challenge header.
- It doubles the number of HTTP round trips for every API call, adding latency and consuming rate limit budget on requests that will always fail.
What's changing on February 28, 2026
- Browser-based requests to BambooHR will no longer receive the
WWW-Authenticate: Basic realm="..."header on 401 responses. This eliminates the unexpected credential prompt in the browser. - Non-browser API clients will continue to receive the header for backward compatibility.
Integrations that already send the Authorization header on every request are not affected.
Recommended action
We strongly recommend configuring your integration to include credentials on every API request from the start rather than relying on the challenge-response cycle. This is an industry best practice and provides meaningful benefits:
- Faster responses — Eliminates the extra round trip of receiving a 401 and retrying.
- Improved reliability — Requests succeed on the first attempt.
- Reduced rate limit usage — Failed unauthenticated requests count toward rate limits. Authenticating upfront preserves your request budget for productive calls.
- Future compatibility — The
WWW-Authenticate: Basic realmheader will not be included in future API versions.
Examples: Sending credentials with every request
BambooHR's API uses Basic Auth with your API key as the username and any string (e.g., x) as the password. Below are examples for common HTTP clients. Replace YOUR_API_KEY and your-subdomain with your own values.
PowerShell
$apiKey = "YOUR_API_KEY"
$encodedAuth = [Convert]::ToBase64String(
[System.Text.Encoding]::UTF8.GetBytes("${apiKey}:x")
)
$headers = @{ "Authorization" = "Basic $encodedAuth" }
$uri = "https://your-subdomain.bamboohr.com/api/v1/employees/directory"
$response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headersC# (RestSharp)
var client = new RestClient("https://your-subdomain.bamboohr.com/api/v1");
var request = new RestRequest("employees/directory", Method.Get);
request.AddHeader("Authorization",
"Basic " + Convert.ToBase64String(
Encoding.UTF8.GetBytes("YOUR_API_KEY:x")));
var response = await client.ExecuteAsync(request);Node.js (axios)
const axios = require('axios');
const response = await axios.get(
'https://your-subdomain.bamboohr.com/api/v1/employees/directory',
{ auth: { username: 'YOUR_API_KEY', password: 'x' } }
);PHP (Guzzle)
$client = new \GuzzleHttp\Client();
$response = $client->get(
'https://your-subdomain.bamboohr.com/api/v1/employees/directory',
['auth' => ['YOUR_API_KEY', 'x']]
);Python (requests)
import requests
response = requests.get(
'https://your-subdomain.bamboohr.com/api/v1/employees/directory',
auth=('YOUR_API_KEY', 'x')
)Looking ahead
For improved security and granular access control, we recommend migrating to OAuth 2.0. See Getting Started With The API for details.
If you have questions about how this affects your integration, please contact our support team.
2025.11.26 – Upcoming Improvement to Webhook Error Details
We’re enhancing webhook error information to make troubleshooting easier. Soon, webhook error logs will include more detailed and actionable fields, and a new API endpoint will allow developers to retrieve webhook errors programmatically. We expect these improvements to be available in early 2026.
2025.11.07 – Deprecating HTTP Authentication Negotiation (removing WWW-Authenticate: Basic realm on 401)
WWW-Authenticate: Basic realm on 401)We are deprecating support for HTTP authentication negotiation in our public APIs. Today, some clients (e.g., PowerShell scripts) send an unauthenticated request, receive a 401 with a Basic realm challenge, and then retry with credentials. To provide a consistent and reliable authentication experience across all integrations, we’re removing the Basic realm challenge—which can cause confusing browser credential prompts when sessions expire—by eliminating the WWW-Authenticate: Basic realm="..." header from 401 responses.
What’s changing
- The
WWW-Authenticate: Basic realm="..."header will no longer be returned on 401 responses. - Clients must send credentials with the initial request (or use OAuth 2.0 tokens).
- Integrations that already send the
Authorizationheader up front are not affected.
Action required
- If your script or integration relies on a 401 challenge/negotiation flow, update it to include the
Authorizationheader in the initial request (Basic with your BambooHR API key), or use OAuth 2.0 access tokens.
BambooHR’s API uses Basic Auth with the API key as the username and any string as the password.
Timeline
- Announcement: November 7, 2025
- Removal enforced after: February 28, 2026
- After enforcement: requests that depended on negotiation may receive 401 errors without an automatic retry.
PowerShell example (send credentials with the first request)
Replace
your-subdomain,YOUR_API_KEY, and the sample endpoint with your own. In Basic Auth for BambooHR, use the API key as the username and any string for the password.
# 1) Provide your BambooHR API key as the username; use any string as the password
$apiKey = "YOUR_API_KEY"
$password = "x" | ConvertTo-SecureString -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($apiKey, $password)
# 2) Build the Basic Authorization header manually (send on the FIRST request)
$authString = "$($cred.UserName):$($cred.GetNetworkCredential().Password)"
$encodedAuth = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($authString))
$headers = @{ "Authorization" = "Basic $encodedAuth" }
# 3) Call the API (example endpoint shown)
$uri = "https://your-subdomain.bamboohr.com/api/v1/employees/directory"
try {
# Use Invoke-RestMethod or Invoke-WebRequest; do NOT rely on negotiation or default creds
$response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers
Write-Host "Request successful."
$response | ConvertTo-Json -Depth 6
}
catch {
Write-Host "Request failed. Error: $($_.Exception.Message)"
}More Information
- For more information about authentication, see Getting Started With The API.
Updated about 15 hours ago
