Carerix integration
Sync Carerix employees, companies and placements into TimeTracking with external-ID upserts and batches, and report approved hours back with GET /days.
Last updated: · Markdown version
1. Summary
Status: Recipe (no native connector).
Direction: Carerix to TimeTracking for master data. Optional: TimeTracking to Carerix for approved hours.
Carerix is a staffing ATS/CRM widely used by Dutch agencies. The recipe upserts placed employees, client companies and placements into TimeTracking by their Carerix ids, and optionally writes approved hours back.
2. Mechanism
- Carerix side. Read through the Carerix API (REST/XML "CxAPI" on older instances, REST/GraphQL on newer). Typical entities:
CREmployee,CRCompany,CRVacancy,CRMatch/ placement (CRJobin some setups). Detect changes by polling on modification date, or with Carerix notifications if your contract includes them. - TimeTracking side.
PUT /{clients|people|placements}/by-external/carerix/{id}orPOST /{clients|people|placements}/batchwithexternalSource: "carerix". - Hours back.
GET /days?from&to&status=approved&updated_since=…(cursor-paginated), triggered bytimesheet.approvedor a schedule.
Assumption — verify with your Carerix admin/consultant: entity names and API flavour differ per Carerix version and licence.
3. Prerequisites
- Carerix API credentials with read access to employees, companies and placements.
- TimeTracking API key with scope
write. - For webhooks: an admin user or an
admin-scope API key. - Storage for the back-sync checkpoint (
updated_since).
4. Entity mapping
| Carerix object.field | TimeTracking field | Notes |
|---|---|---|
CREmployee id |
person external ref (/people/by-external/carerix/{id}) |
|
CREmployee payroll number |
employeeNumber |
Must equal the payroll number used in exports. |
CREmployee first / last name |
firstName / lastName |
Put Dutch prefixes in lastName ("de Vries"). |
CREmployee email, mobile, language |
email, phone, locale |
locale drives the app language (nl, pl, en, …). |
CRCompany id |
client external ref (/clients/by-external/carerix/{id}) |
|
CRCompany name |
name |
|
| Contact who signs timesheets | client contact | Dashboard only; no API for contacts. |
Placement / CRMatch id |
placement external ref; also ref |
|
| Employee id / company id of the placement | personExternalRef / clientExternalRef |
Same source carerix. |
| Placement start / end | startsOn / endsOn |
YYYY-MM-DD; omit endsOn for open-ended. |
| Function title | roleTitle |
|
| Placement ended | DELETE /placements/{id} (deactivate) or active: false |
|
TimeTracking day (GET /days item) |
Carerix hours/timesheet record | Assumption: depends on the Carerix timesheet module. Key on the day id. |
External-ID strategy. source = carerix, ref = Carerix id. Upserts are idempotent and full replaces (omitted optional fields become null). Responses include created: true|false.
5. Step-by-step setup
export TT=https://app.timetracking.tech/api/v1
export KEY=tt_live_...
curl -s -X PUT "$TT/clients/by-external/carerix/2201" -H "Authorization: Bearer $KEY" -H "content-type: application/json" \
-d '{"name":"VDL Montage","externalRef":"2201","approvalMode":"both","mailDomains":"vdl-montage.example"}'
curl -s -X PUT "$TT/people/by-external/carerix/50017" -H "Authorization: Bearer $KEY" -H "content-type: application/json" \
-d '{"employeeNumber":"1001","firstName":"Jan","lastName":"de Vries","email":"jan@example.com","locale":"nl"}'
curl -s -X PUT "$TT/placements/by-external/carerix/90311" -H "Authorization: Bearer $KEY" -H "content-type: application/json" \
-d '{"personExternalRef":"50017","clientExternalRef":"2201","ref":"CX-90311","roleTitle":"Monteur","startsOn":"2026-09-01"}'
Initial load: use POST /clients/batch, /people/batch, /placements/batch (≤500 rows each, rows {externalSource:"carerix", externalRef, …}), in that order. Check results[] for ok: false rows. The script structure is the same as the Bullhorn sync.
Hours back:
curl -s "$TT/days?from=2026-11-01&to=2026-11-30&status=approved,exported&updated_since=2026-11-20T00:00:00Z&limit=500" \
-H "Authorization: Bearer $KEY"
6. Sync schedule and triggering events
| Trigger | Action |
|---|---|
| Poll Carerix every 15 min on modification date | Upsert changed employees, companies, placements. |
| Nightly | Re-upsert everything active (idempotent). |
timesheet.approved webhook or schedule |
GET /days?updated_since=…, write to Carerix. |
placement.updated {active:false} |
Optional: reflect office deactivations. |
7. Corrections, conflicts and locked periods
- TimeTracking owns hours.
conflict.createdtells you a conflict exists; resolve it in TimeTracking. - A correction moves an approved day back to
submittedand bumps itsversion; overwrite by dayidin Carerix. - Exported/locked days return
423 locked. Corrections are new entries in an open period. - Shortening a placement before existing hours returns
409.
8. Testing checklist
- First upsert returns
created: true, the repeatcreated: false. - Batch with one bad row still writes the rest.
- Ending a placement deactivates it.
-
GET /days?updated_since=returns only changed days.
9. Troubleshooting
| Error | Fix |
|---|---|
401 invalid key |
New key from a current admin. |
403 "API key is read-only" |
Use a write key. |
422 "Person and client must exist (by id or external ref) before the placement" |
Upsert person and client first, same source. |
422 with issues |
Check issues[].path; dates YYYY-MM-DD. |
409 "N registration(s) exist after …" |
Do not shorten before existing hours. |
429 |
Wait Retry-After (60 s). |
10. Limits and known gaps
- No API for client contacts.
- The master-data CSV import (
POST /import) still matches clients by name; prefer the external-ID API for ongoing sync.
11. Build it with Claude
Build a Carerix → TimeTracking sync (TypeScript, Node 20). Ask me for the Carerix API flavour (XML CxAPI or
REST/GraphQL) and sample responses for an employee, a company and a placement before writing the mapping.
TimeTracking: https://app.timetracking.tech/api/v1, Bearer $TT_API_KEY, responses { data } / { error }.
Use PUT /clients|/people|/placements/by-external/carerix/{id} (full replace), placements with personExternalRef/clientExternalRef, POST /…/batch for bulk (≤500, per-row
results), DELETE /placements/{id} to deactivate, Idempotency-Key on writes, 429 handling. Back-sync approved
hours with GET /days?from&to&status=approved&updated_since&limit=500 following next_cursor.
Dry-run mode and tests with mocked HTTP. Never delete data.