How do I identify and match employees from the HRIS API?

Edited

When integrating with an HRIS connector, you'll often need to match an Apideck employee record back to the underlying system - for example, to look the same person up against the vendor's native API, or to reconcile against records you've already stored on your side. This article explains which identifier field to use.

Start with the id field

For every supported HRIS connector, the id returned on /hris/employees is the native employee identifier from the underlying vendor's API. There's no separate identifier hidden behind the scenes, and you don't need raw=true or a custom field mapping to access it.

For example, in a BambooHR response:

{ "id": "99", "firstName": "Michael", ... }

The "99" is the same ID BambooHR uses internally - the value you'd get from GET /v1/employees/99 directly against BambooHR.

Lucca HR works the same way: their numeric user ID (e.g. 416) is returned as the unified id (as a string, "416").

You can safely store this value and use it as the link between Apideck and the underlying system.

When to use employee_number

Some vendors expose two distinct identifiers per employee:

  • A database ID (the vendor's internal primary key), and

  • A separate HR-facing employee number (the value shown in the vendor's UI, on payslips, or in CSV exports).

For these connectors, the database ID is returned as id, and the HR-facing number is returned separately as employee_number.

Use employee_number when your system stores the HR-facing number rather than the database ID. Connectors where this distinction matters include BambooHR, Lucca HR, AlexisHR, BreatheHR, Cascade HR, CIPHR, Factorial, Folks HR, Gusto, HiBob, HR Works, Humaans, Keka, Loket, Namely, NetSuite, Nmbrs, Okta, Paychex, People HR, Sage HR, Workday, and Zoho People, among others.

For connectors where the vendor exposes only one identifier, employee_number may be empty - in that case, id is the only value you need.

When to use downstream_id

downstream_id is reserved for connectors where the vendor exposes a second native identifier beyond what fits in id and employee_number. Today, this applies to a small number of HRIS connectors:

  • Fourth - downstream_id returns the PayrollNumber.

  • Acerta - downstream_id returns the employeeId, while id carries the agreementId.

  • Remote - downstream_id mirrors the value of id, so you can match on either.

For all other HRIS connectors, downstream_id is empty. An empty downstream_id does not mean the native vendor ID is hidden - it means the vendor has only one stable identifier per employee, and that identifier is already in id.

Which field should I match on?

A quick decision guide:

If your system stores…

Match on

The identifier the vendor uses internally (e.g. BambooHR's 99, Lucca's 416, NetSuite's internalId)

id

The HR-facing employee number (e.g. BambooHR's employeeNumber, Sage HR's employee_number)

employee_number

A secondary native identifier (Fourth PayrollNumber, Acerta employeeId)

downstream_id

An email or display name

emails[].email, display_name, etc.

Frequently asked questions

Why does the id value look different from what I see in my HRIS dashboard? Most HRIS dashboards display the human-readable employee number, not the database primary key. The database primary key is what we surface as id. The number you see in the dashboard is usually surfaced separately as employee_number - try matching on that instead.

Do I need raw=true to retrieve the native ID? No. raw=true returns the unmodified vendor payload alongside the unified response, but it isn't required to access the native ID. For HRIS employees, id already carries the native vendor identifier.

Why is downstream_id empty for my connector? Because the vendor only exposes one stable identifier per employee, and we already return it as id. downstream_id is only populated when the vendor has a second distinct identifier worth surfacing.


If anything still doesn't line up with what you're seeing in a response, please reach out - we're happy to take a closer look at the specific connector and resource you're working with.

Was this article helpful?

Sorry about that! Care to tell us more?

Thanks for the feedback!

There was an issue submitting your feedback
Please check your connection and try again.