Skip to content

Request an integration

Tell us which system you want to connect. We review every request weekly and publish a step-by-step guide or build the connection.

Nmbrs payroll export

Bring approved TimeTracking hours, allowances, expenses and leave into Nmbrs as hours and variable wage components, via file import or the Nmbrs API.

Last updated: · Markdown version

1. Summary

What syncs Approved hours per hour type, allowances, approved expenses, approved leave
Direction TimeTracking → Nmbrs
Mechanism CSV export (custom mapping) imported in Nmbrs, or a script that pushes rows to the Nmbrs API
Trigger Per payroll period, after the weekly close

Status: Recipe — works today with an export file or your own script. No native Nmbrs connector.

2. Mechanism

A. File import. A Nmbrs-shaped export mapping renders one line per employee per hour code (or wage component) per period. You import it in Nmbrs for the run. Assumption — Nmbrs supports importing hours and variable wage components per employee per period from Excel/CSV, keyed on employee number and a code; verify the exact template with your Nmbrs consultant.

B. API push. A script commits the TimeTracking export and writes the lines through the Nmbrs API. Assumption — Nmbrs exposes employee hour components and variable wage components per period in its API (classic SOAP services and a newer REST API); verify endpoint names, period semantics and authentication with your Nmbrs consultant.

Nmbrs distinguishes hour codes (uren) from wage components (looncomponenten, amounts). Map hours-type lines (componentType: "hours") to hour codes and money lines (expenses, allowances) to wage components. Because one mapping produces one file, use two mappings if Nmbrs needs two imports, or one mapping with both a quantity and an amount column.

3. Prerequisites

  • TimeTracking admin; API key with write scope.
  • employee_number in TimeTracking = Nmbrs employee number.
  • Nmbrs hour codes and wage component codes for each TimeTracking hour type, expense kind and leave type.
  • Nmbrs company id and payroll period convention (week, 4 weeks, month). Pass the matching startsOn/endsOn.
  • For option B: Nmbrs API credentials.

4. Entity mapping

Nmbrs object / field TimeTracking Notes / external ID
Company TimeTracking org const: column if needed.
Employee number employee_number → employeeNumber Only stable key today.
Hour code (uursoort) hourType (normal, overtime_125, ort_*, holiday, leave_*) via map Lines with componentType: "hours".
Hours value minutes → hours_decimal Decimal separator per template.
Wage component code expense_<kind>, allowance_<code> via map Lines with componentType: "allowance".
Wage component value amountCents → cents_decimal
Period / year Export range Not in PayLine; constant or chosen on import.
Cost centre / department clientName / placementRef Optional.

External IDs: upsert people, clients and placements idempotently with PUT /{people|clients|placements}/by-external/{source}/{ref} (or POST /…/batch with externalSource + externalRef per row, up to 500 rows). The response includes external_source, external_ref and created: true|false. Use for example source nmbrs with the Nmbrs employee id as ref.

5. Step-by-step setup

export TT=https://app.timetracking.tech/api/v1
export KEY=tt_live_…        # write scope
  1. Verify employee numbers: tt people list (column with the employee number) or curl -s "$TT/people" -H "Authorization: Bearer $KEY".

  2. Create the mapping yourself (admin, dashboard): open the export mappings screen (/export/mappings, linked from Export), copy preset-generic or preset-sdworx, edit columns, code tables and validation, and optionally set it as the org default. Saved mappings are validated; max 50 per org. The mapping id is the UUID in its URL (/export/mappings/<uuid>): pass it as mappingId to POST /exports and tt export --mapping. Example JSON for the editor (assumed layout — verify with your Nmbrs consultant):

{
  "id": "nmbrs-uren",
  "name": "Nmbrs — uren en looncomponenten",
  "format": "csv",
  "delimiter": ";",
  "includeHeader": true,
  "encoding": "utf-8",
  "lineEnding": "crlf",
  "groupBy": ["employeeNumber", "hourType"],
  "columns": [
    { "header": "EmployeeNumber", "source": "employeeNumber" },
    { "header": "Code", "source": "hourType", "transform": { "kind": "map", "table": "codes" } },
    { "header": "Hours", "source": "minutes", "transform": { "kind": "hours_decimal", "decimals": 2, "decimalSeparator": "," } },
    { "header": "Amount", "source": "amountCents", "transform": { "kind": "cents_decimal", "decimalSeparator": "," } },
    { "header": "Type", "source": "componentType", "transform": { "kind": "upper" } }
  ],
  "tables": {
    "codes": {
      "normal": "U100", "overtime_125": "U125", "overtime_150": "U150",
      "ort_evening": "U210", "ort_night": "U220", "ort_saturday": "U230", "ort_sunday": "U240", "holiday": "U250",
      "leave_vacation": "U300", "leave_sick": "U310",
      "expense_km": "L410", "expense_public_transport": "L420", "expense_parking": "L430", "expense_meal": "L440"
    }
  },
  "validation": [
    { "column": "EmployeeNumber", "required": true },
    { "column": "Code", "required": true }
  ]
}

Codes U100… are placeholders. Type renders HOURS or ALLOWANCE, so one file can be split by type before import if Nmbrs needs two imports.

  1. Preview, then commit (irreversible) and import:
curl -s -X POST "$TT/exports" -H "Authorization: Bearer $KEY" -H "content-type: application/json" \
  -d '{"mappingId":"nmbrs-uren","startsOn":"2026-11-02","endsOn":"2026-11-29","mode":"preview"}' \
  | jq '.data | {ok, issues, warnings, pendingCount, rows: (.rows|length)}'

tt export --from 2026-11-02 --to 2026-11-29 --mapping nmbrs-uren --commit -o nmbrs-p11.csv
  1. Import nmbrs-p11.csv in Nmbrs for the matching period. For option B, parse data.content from the commit response (or download it later with GET /exports/runs/{runId}/file) and post each line to the Nmbrs API (see the Loket guide for a TypeScript parsing sketch: Loket.nl).

  2. After Nmbrs processed the run, an admin locks the period in the dashboard.

6. Sync schedule and triggering events

  • Per Nmbrs payroll period. For 4-weekly payroll pass the 28-day range; for monthly the calendar month.
  • export.completed and period.locked webhooks signal progress (an admin creates them in the dashboard, or via the API with an admin user token or an admin-scope key). On export.completed, download the file with GET /exports/runs/{runId}/file. See Webhook events.
  • Committed files stay retrievable: GET /exports/runs (paginated {items, next_cursor}), GET /exports/runs/{id} (metadata, mapping_snapshot, pay_lines, warnings) and GET /exports/runs/{id}/file (the exact committed file, text/csv). A read-only key is enough.

7. Corrections, conflicts and locked periods

  • Unapproved and conflicted days stay out of the file (pendingCount).
  • Exported and locked days are immutable (423). Book corrections in an open period.
  • If an Nmbrs import is rejected after commit, fix it on the Nmbrs side using the saved file. Do not record the hours again in TimeTracking.

8. Testing checklist

  • All codes mapped; preview issues: [].
  • Hours vs amounts land in the correct Nmbrs component type.
  • Test import into a Nmbrs test run; totals per employee equal the TimeTracking overview.
  • Leave hours are not counted twice if leave is also registered in Nmbrs.

9. Troubleshooting

HTTP / code Message Fix
401 unauthenticated Invalid or revoked API key New key.
403 forbidden API key is read-only write key for exports.
404 not_found Export mapping not found Check the mapping id.
409 conflict This period was just exported; refresh before exporting again Avoid double commit.
422 invalid Export has N validation issue(s) Preview and fix missing numbers/codes.
422 invalid Nothing approved to export in this period Approve days first.
423 locked This day is exported or locked; book a correction in an open period Correct in an open period.
429 rate_limited Rate limit … exceeded Retry after 60 s.

10. Limits and known gaps

  • Mappings are edited by admins in the dashboard only; there is no mapping API.

  • One mapping = one file; hours and wage components share it unless you use two mappings.

  • groupBy keeps the first line's date.

  • Leave double-counting risk if leave is managed in both systems: pick one source.

  • Encoding: a mapping with encoding: "windows-1252" is delivered as Windows-1252 (Latin-1) only by GET /exports/runs/{id}/file (content-type: text/csv; charset=windows-1252, no BOM). Characters outside Latin-1 (€, curly quotes, em dash) become ?. The preview/commit JSON content and the dashboard download stay UTF-8.

Planned (not in API v1.1) — export-mapping CRUD via the API.

11. Build it with Claude

Help me connect TimeTracking to Nmbrs.
1. Using the TimeTracking MCP tools, list people and flag any without an employee number.
2. Run export_preview with mappingId "preset-generic" for 2026-11-02..2026-11-29 and list every distinct hour_type.
3. Draft a Nmbrs ExportMapping JSON (schema: docs/developers/data-out/export-mappings.md) with a codes table that
   has one TODO code per hour_type; split hours vs amounts using componentType.
4. Do not commit any export. Mark every Nmbrs-specific field as "verify with Nmbrs consultant".