Product that suits modern B2B Tech companies

Book Demo
B
Book demo call-to-action illustration
BACK
B

What data the CharlieHR API exposes

Technical Guides
October 23, 2026
Summarise the blog with AI
Open in ChatGPT
Ask questions about this page
Open in Claude
Ask questions about this page

Last verified: 2026-10-23

Key takeaways

  • The CharlieHR v1 API is read-mostly and broad: team members, salaries, bank accounts, leave requests, allowances and adjustments, offices, teams and working patterns.
  • Salary records carry an effective date, and CharlieHR pushes salary one way to Xero, so a future-dated raise can be in the API weeks before payroll sees it.
  • Days taken has no endpoint. Your product computes it from approved requests and adjustments, and sick leave has two defensible totals.
  • There are no webhooks and no documented rate limit, so change detection is polling.
  • One static key, generated by a Super Admin, reads every resource. There are no scopes.
  • Documents, reviews, polls, checklists and the handbook have no endpoint and leave only through the full account export.

The CharlieHR API covers more of the account than most builders expect. Salary, bank details, managers and allowance history all have endpoints. What the API leaves to you is judgment: which salary is current, which leave total is right, and how you find out that anything changed.

This page covers what the API returns, those three judgment calls, and what access looks like, for anyone scoping a read integration with CharlieHR. API facts come from CharlieHR's v1 reference at charliehr.com/api_docs; facts about Xero, reports and export come from its help center.

What the CharlieHR API returns

The API is JSON over HTTPS at https://charliehr.com/api/v1. Every endpoint is a GET except creating notes and note types.

ResourceEndpointsWhat it holds
Team members/team_members, /team_members/:idName, emails, phone, address, date of birth, gender, NI number, payroll ID, job title, employment status, leaving date, office, teams, manager, notes
Salaries/salaries, /team_members/:id/salariesJob title, pay rate, pay period, pay frequency, currency, effective date, employment type
Bank accounts/bank_accounts, /bank_accounts/:team_member_idAccount number, sort code, bank name; IBAN, SWIFT and holder name if international payment fields are enabled
Leave/leave_requests, /team_members/:id/leave_requests, /leave_allowances, /team_members/:team_member_id/allowance_adjustments, /leave_types, /team_members/:id/non_holiday_leave_allowancesBookings, current allowances, adjustments across all leave periods, leave categories
Company calendar/company_holidays, /restricted_datesCompany-wide days off and blocked dates
Structure/company, /offices, /teams/:id, /working_locationsThe company record, offices, teams with their members, work locations
Working patterns/team_members/:team_member_id/working_weeks, /team_members/:team_member_id/working_locationEach person's working week and location

List endpoints paginate with page and per_page, capped at 25, and return a meta block with totals and the next page. Every request authenticates with the same header:

Request
curl "https://charliehr.com/api/v1/salaries?page=1&per_page=25" \
  -H "Authorization: Token token=CLIENT_ID:CLIENT_SECRET"
Response
{
  "success": true,
  "meta": {
    "total_results": 1,
    "results_per_page": 25,
    "current_page": 1,
    "total_pages": 1,
    "prev_url": null,
    "next_url": null
  },
  "data": [
    {
      "id": "salary_XXX",
      "team_member": "team_member_XXX",
      "job_title": "Software Developer",
      "pay_rate": 30000,
      "pay_period": "Monthly",
      "pay_frequency": "Year",
      "pay_currency": "GBP",
      "effective_date": "2020-01-01",
      "employment_type": "Permanent"
    }
  ]
}

That sample is CharlieHR's own. It pairs a pay_rate of 30000 with pay_frequency "Year" and pay_period "Monthly", so check against a real customer which field carries the rate's unit before you compute anything from it.

Structure comes from the team member record. Each one carries an office, a list of teams and a manager, which is enough to place every person and rebuild reporting lines. The org chart in CharlieHR's dashboard exports only as a PDF, so build from these fields instead.

Picture a benefits platform onboarding a 40-person UK customer. It needs each employee's identity and team, their salary for salary-linked life cover, their leave, and a credential from the customer. Every one of those comes from the API. The next three sections are about what the platform still has to decide.

Judgment call 1: which salary is current

/salaries returns every salary record, including ones that haven't taken effect. A raise entered today for next month is already there, with next month's effective_date. Pick the latest record whose effective date has passed, or your cover calculation runs on a figure the employee isn't earning yet.

Payroll can disagree with CharlieHR in the meantime. CharlieHR's help center treats it as the source of truth for personal information and salaries, and pushes them one way to Xero, matching records on a Payroll ID set to the Xero Employee Number. For a future-dated salary, the sequence is:

  1. Enter: record the new salary in CharlieHR with the future date.
  2. Compare: CharlieHR checks it against Xero.
  3. List: if the figures differ, the change is listed for a Super Admin.
  4. Push: the Super Admin reviews it and pushes it to Xero.

Salaries cannot be changed in Xero after that month's pay run for that team member. Take a raise entered on 20 March, effective 1 April. It is in /salaries on 20 March. It reaches Xero only when a Super Admin pushes it, and if that misses the April pay run, payroll and CharlieHR disagree for a month. Store the effective date and the source with every salary you read.

Judgment call 2: which leave total to show

Leave comes in pieces. Requests are individual bookings, filterable by start_date and end_date. Allowances are each person's current entitlement. Allowance adjustments are the manual changes behind it, across every leave period and including carryover, with who made each one and when.

"Days taken" is not among them. CharlieHR's Time Off Overview report shows allowances, days approved this year, days taken, manual adjustments and imported days, as of today only. Your product computes days taken from approved requests, and should test that figure against a real customer's report before showing it, because imported days appear in the report and may never appear as requests.

Sick leave adds a second choice. The report totals it per holiday year and on a rolling 12-month basis, so "days taken" has two defensible answers. Pick one and label it.

Judgment call 3: how you learn something changed

Neither CharlieHR's help center nor its API reference documents webhooks or a rate limit. Change detection is polling: re-read the resources you care about on a schedule and compare. At 25 records a page, a full read of a large customer is many requests, so ask CharlieHR about limits before you schedule it across your whole customer base.

The API also returns current state only. Reports in CharlieHR can filter by a date range, but an endpoint won't tell you who sat in which team last March. If your product needs history, take your own snapshots from the first sync.

Access: one key reads everything

Only a customer's Super Admin can generate API credentials, under Company, Integrations, API Access, Your API Keys. Generating a key gives a Client ID and a Client Secret.

The secret is shown only once, then masked. Pasting the masked value into an integration returns an error, and the help center gives no way to view it again. Tell the admin to copy it before leaving the page, because the failure looks like a bad integration when it is really a bad paste.

The pair goes into every request as Authorization: Token token=client_id:client_secret. There is no token exchange, no expiry and no scopes. A key that reads office names also reads bank details, which your customer's security review will want stated.

What the API doesn't carry

DataHow it leaves CharlieHRWho triggers itFormat
Handbook, documents, reviews, polls, checklists, key dates, report exportsFull account exportA Super AdminXML: a company.xml file plus folders, deleted after a week
Org chartDashboard, under PeopleExported from the People pagePDF

The export also includes salaries and all leave requests, so it suits a one-time migration. It has no schedule and disappears after a week, which makes it a poor feed. Files and APIs fail in different ways, and this export is both stale on arrival and short-lived.

Reading CharlieHR through a unified API

CharlieHR's help center says custom product integrations go through partnered unified API providers, and that yours may not be available as a standard option. A unified API maps each source into shared models, so the questions are how much of CharlieHR it maps and what happens to the rest. Check four things: whether coverage is published per model, whether the raw upstream payload is kept, whether unmapped fields can be added, and whether you get change events.

Bindbee connects to CharlieHR through its API and publishes per-integration coverage in its Model Availability Matrix, marked Available, Beta or not available. CharlieHR's row covers compensation, bank details, groups, time off and time off balances. Records can come back with the full upstream payload as raw_data, Custom Fields map any upstream field through JMESPath, and Passthrough calls CharlieHR's own API with the connector's credentials. The three are compared here.

Bindbee syncs a Production connector every 24 hours by default, adjustable per connection on request, and sends webhooks on connector link, sync, failure and relink, and when a sync creates or updates records. That replaces judgment call 3 with an event after each sync. It suits a nightly refresh; a screen that must reflect a change within minutes still needs its own approach. Bindbee holds SOC 2 Type II and ISO 27001 and is HIPAA and GDPR compliant, with reports on its Trust Center.

Judgment calls 1 and 2 stay with you either way, because they are product decisions. If you'd rather make them on top of an integration already maintained alongside 110+ HRIS, payroll, ATS and benefits systems, see Bindbee's CharlieHR integration.

FAQ

What is Charlie HR?

CharlieHR is HR software that holds team-member records, salaries, time off, company structure and HR documents. Charlie HR and CharlieHR are the same product.

Does the CharlieHR API return salary?

Yes. GET /salaries returns every salary record for the company, and GET /team_members/:id/salaries returns one person's. Each record includes pay rate, currency, pay period, pay frequency and an effective date.

How do you authenticate to the CharlieHR API?

A Super Admin generates a Client ID and Client Secret under Company, Integrations, API Access. Every request then sends Authorization: Token token=client_id:client_secret. There is no token exchange and no scopes.

Does CharlieHR have webhooks?

Neither CharlieHR's help center nor its API reference documents webhooks. To detect changes, poll the endpoints you need, or use a provider that sends events after each sync.

Kunal Tyagi
CTO
Bindbee
VIEW AUTHOR
BLOG_

Related blogs