Write-back · guide
Idempotency and payroll cut-offs for benefits deduction writes
Send every deduction write with a deterministic idempotency key derived from employee and pay period, retry only inside the window your vendor honours it (five minutes on Bindbee), treat timeouts as landed, and because Bindbee's API does not expose the payroll cut-off, read the run back after a sync to confirm which period the line landed in.
By Eli Wilson · Published
Short answer: send every deduction write with an X-Idempotency-Key derived from the employee and the pay period (for example payroll-{employee_id}-{period_end}), and know how long your vendor honours it. On Bindbee, the key is honoured for five minutes, so retry only within five minutes with the same key. Treat a timeout as landed, and after the window, confirm by reading the payroll run back after a sync instead of retrying blindly. Your own ledger, not the key, is the long-term guard against duplicates. For cut-offs, the key fact is that Bindbee’s API does not expose the payroll cut-off, so plan without it. A write that arrives after a period closes can land in the next open period, so check start_date, end_date and check_date on the read-back and reconcile. Of the seven vendors compared below, four document a unified deduction write (Bindbee, Finch, Knit, Unified.to), and only Bindbee’s idempotency behaviour was verified for this piece; ask the others in writing.
The mechanics below use Bindbee’s POST /employee-payroll-runs as the worked example, because its idempotency and period semantics are documented in enough detail to show; it is how deductions are written there. Each write is a line in one pay period or one payroll run, not a standing deduction election (create employee payroll runs), so an ongoing deduction means a write every period. Write: Supported (write payroll deductions). For the end-to-end flow, see writing benefits deductions back into payroll after enrollment.
Comparison: deduction write and its safety mechanics (as of 1 Oct 2026)
Who can write a deduction, and where:
| Vendor | Unified deduction write | Payroll systems documented | Shape of the write |
|---|---|---|---|
| Bindbee | POST /employee-payroll-runs (earnings, deductions, taxes) | Write: Supported | One line per pay period or payroll run; no update endpoint |
| Merge | Not documented in Merge’s HRIS common models | Not applicable | HRIS writes documented for Employees and Time Off |
| Finch | Deductions (write) on Pro, marked “Employer Fee Required”: retirement, medical, dental, vision, HSA/FSA, commuter; pre/post-tax; company contributions | Per-system list not verified for this piece | Not verified |
| Kombo | None in Kombo’s OpenAPI | Not applicable | HRIS writes cover employees, documents, absences, skills; DATEV raw file passthrough |
| Apideck | None (no POST/PATCH on payroll, deductions or benefits in the HRIS spec) | Not applicable | Payroll is read-only |
| Knit | Create company deduction; enroll, update and unenroll employee deduction | Enroll: ADP Run, ADP WFN, Paycor, Paychex, Paylocity, PrismHR, Avionte, QuickBooks Payroll. Update: ADP Run, ADP WFN, Paycor, Paychex, Paylocity. Unenroll: those five plus QuickBooks Payroll. Company deduction: ADP Run, Workday, QuickBooks Payroll, NetSuite Payroll | Enrollment-style operations with an update endpoint |
| Unified.to | Create a deduction, Update a deduction endpoints | Of US systems checked, only Paylocity lists create/update/remove. Paychex and UKG Pro list remove only. ADP WFN, Paycor, UKG Ready: read only | Unsupported operations return 501 |
Safety mechanics:
| Vendor | Idempotency | When the write is visible to reads | Payroll cut-off exposed |
|---|---|---|---|
| Bindbee | X-Idempotency-Key header, honoured for five minutes; same key with a different body returns 409 (idempotency docs). Passthrough writes cannot carry a key | Write goes straight to the source and returns its response; readable via GET after the next sync, or sooner with an on-demand resync | No |
| Merge | Not applicable | Not applicable | Not applicable |
| Finch | Not verified | Assisted connections: changes written back within 2 business days | Not verified |
| Kombo | Not applicable | Not applicable | Not applicable |
| Apideck | Not applicable | Not applicable | Not applicable |
| Knit | Not verified | Not verified | Not verified |
| Unified.to | Not verified | Not verified (reads pass through to the source, per Unified.to) | Not verified |
“Not verified” means it was not researched for this piece; it is not a claim the feature is missing.
The two failure modes
1. Duplicates
A duplicate deduction is the worst outcome of this integration: an employee is charged twice and payroll staff have to reverse it by hand. It usually comes from retries:
- Your worker times out and retries.
- A queue redelivers a message.
- Two code paths (an enrollment event and a nightly reconciliation job) both decide the same line is missing.
What to do
The defences below are written against Bindbee’s documented behaviour. Where a vendor’s idempotency is not documented, assume none and lean harder on your ledger.
- Derive the key once per logical write and store it. Build it from stable inputs (employee, payroll code, period end) so a retry reproduces it. Generating a fresh UUID on every attempt protects nothing. Bindbee’s docs suggest a key of the form
payroll-{employee_id}-{period_end}; if you write more than one deduction per employee per period, add the payroll code. The Payroll Run Calendar’spay_period_end_dateis the natural input for{period_end}. - Know the window. Bindbee honours a key for five minutes after a successful write. Within that window the same key and body returns the saved result. After it, the same key can create a second record. Retries belong inside the window.
- Your ledger is the long-term guard. Store the ID Bindbee returns against the line in your ledger. Before any later path (a nightly reconciliation, a replayed queue message) writes, it checks the ledger. The key cannot protect paths that run hours apart.
- Treat timeouts as unknown, not failed. Bindbee’s docs say a write that times out has still reached the provider. Retry immediately with the same key. If you’re past five minutes, don’t retry: force a resync and read the run back first.
- Don’t confirm by reading straight away. A write is not readable via GET until the next sync. An immediate read that comes back empty does not mean the write failed, and if you use it as a trigger to write again you will create the duplicate you were trying to avoid. To confirm sooner, call
POST /api/embedded/v1/connectors/resyncand wait for theconnector_syncedwebhook. Use it for confirmation after a write, not on a timer.
What a write and its responses look like
curl --request POST \
--url 'https://api.bindbee.dev/api/hris/v1/employee-payroll-runs' \
--header 'Authorization: Bearer <BINDBEE_API_KEY>' \
--header 'X-Connector-Token: <CONNECTOR_TOKEN>' \
--header 'X-Idempotency-Key: payroll-{employee_id}-{period_end}-{code}' \
--header 'Content-Type: application/json' \
--data @deduction.json
How Bindbee responds to a key:
| You send | Bindbee does | Your next step |
|---|---|---|
| A new key | Processes the write and sends it to the provider | Record the returned ID |
| The same key and body, after success, within five minutes | Returns the saved response, with no second provider write | Treat any 2xx as success; a replayed response can carry a different status code |
| The same key while the first is still running | 409, “Request with this idempotency key is already in progress.” | Wait briefly, retry the same key |
| The same key with a different body | 409, “Idempotency key already exists with a different payload.” | Check the body; use a new key only for a genuinely new write |
| The same key after a failed attempt | Processes the request again | Retry is safe |
| The same key after five minutes | May treat it as a new request | Don’t; check your ledger and read back instead |
2. Missed or misplaced cut-offs
Payroll periods close. Bindbee’s docs say a late write can land in the next open period, and the cut-off is not exposed through the API. So:
- Write early. Run deduction writes as soon as an enrollment is final, well ahead of the end of the period.
- Know the calendar. The Payroll Run Calendar (
pay_period_start_date,pay_period_end_date,pay_date) and Pay Group models give you the schedule where the connector exposes them. The cut-off itself is the customer’s payroll team’s rule; collect it during onboarding. - Check where the line landed. After the next sync, read the employee payroll run and compare
start_date,end_dateandcheck_datewith the period you intended. If it landed a period late, decide with the employer whether a catch-up amount is needed. The API leaves that business rule to you.
Mechanics per connector
Before writing, call GET /employee-payroll-runs/meta/post. It returns the connector’s schema, required fields and integration_params. The bodies differ:
- Workday takes
type+id, accepts one deduction per request, and rejects a body that contains both earnings and deductions. - ADP takes a
code.
Each write also names the period it belongs to (create employee payroll runs):
- Workday and SAP SuccessFactors take
start_dateandend_date. - UKG Ready takes a specific
payroll_runid. - ADP takes a
payroll_filebatch (payroll_process_name).
A line applies to that one period or run only. It is not a recurring election, so an ongoing deduction is written every period, and stopping a deduction means not writing it for the next period.
Read the customer’s payroll codes with GET /payroll-codes (type EARNING, DEDUCTION or TAX). Use sub_type (HEALTH, RETIREMENT, GARNISHMENT and others) to classify codes without parsing names. Which code maps to which plan is the customer’s decision. Store it as configuration per employer.
Workday’s one-deduction-per-request rule matters for idempotency: a medical + dental + HSA change is three requests and needs three keys, so put the payroll code in the key.
Changing an existing deduction
There is no PATCH or PUT for deductions. Because each write targets one pay period or payroll run, a change is simply a different line in the next period you write, and stopping a deduction means not writing it next period. The one point Bindbee’s docs do not cover is a second write with the same code in the same period: whether it adds to or replaces the first is not documented, so read the run back to confirm before you rely on a same-period correction. Bindbee’s guidance for a late change is to treat it as an adjustment in the following period. Keep your own ledger per employee, code and period, and reconcile it against the read-back runs after each sync.
This is a real difference between vendors. Knit documents an update-employee-deduction endpoint (ADP Run, ADP WFN, Paycor, Paychex, Paylocity), and Unified.to documents Deduction update on Paylocity. Whether those change a standing deduction in the payroll system, and how they interact with cut-offs, was not verified for this piece; read the vendor’s docs for each system before relying on them.
A correction is a new logical write and needs a new key. A key derived only from employee and period collides on a same-period correction: the same key with a different body returns 409 (“Idempotency key already exists with a different payload”). Include a version or ledger line ID in the key.
Compensation has no unified write model at all. Where the source vendor allows it, compensation changes go through passthrough. Passthrough does not accept X-Idempotency-Key, so a retried passthrough write reaches the vendor as a second write. Deduplicate on your side before you retry.
Limits by vendor
- Bindbee: the cut-off is not exposed by the API; collect it from the customer. There is no update endpoint, so corrections are new lines and your ledger is the source of truth for intent. Writes are per period, not recurring, so your system writes every active deduction each period. The idempotency key lasts five minutes, and passthrough writes can’t carry one. Write: Supported; Paycom (API), Rippling, BambooHR, HiBob, TriNet, Personio and every SFTP connector have no deduction write, and Gusto is not listed (payroll deduction write support by payroll system). Writes are not visible until the next sync (24 hours by default) unless you trigger a resync. The rate limit is 200 requests per minute per connector token (rate limits), and Workday’s one-deduction-per-request rule multiplies requests at open enrollment.
- Merge: no unified deduction write is documented in its HRIS common models; a payroll write would need passthrough, which is not on the Launch plan.
- Finch: deduction write is on Pro and marked “Employer Fee Required”. Assisted connections take up to 2 business days to write back, which matters near a cut-off. Idempotency was not verified.
- Kombo: no deduction write.
- Apideck: no deduction or contribution write.
- Knit: deduction write is documented on a subset of payroll systems only (not Gusto, BambooHR, UKG or Rippling). Idempotency and read-after-write behaviour were not verified.
- Unified.to: deduction create/update is listed only for Paylocity among the US systems checked; unsupported operations return
501. Idempotency was not verified.
Frequently asked
- What should the idempotency key be?
- Something deterministic from employee, period and (if you write several deductions per period) payroll code, such as `payroll-{employee_id}-{period_end}-{code}`. Never a fresh random value per retry. For a correction in the same period, add a version or ledger line ID, because reusing a key with a different body returns `409`.
- My write timed out. Should I retry?
- Retry within five minutes with the same key. After that, force a resync and read back before you write again. Bindbee's docs say a timed-out write has still reached the provider.
Source limits
Documentation comparison as of 1 Oct 2026; nothing verified hands-on. Only Bindbee's idempotency behaviour was verified from its docs; idempotency, read-after-write and cut-off exposure for Finch, Knit and Unified.to were not verified, and 'not verified' is not a claim the feature is missing. Finch's per-system write list and the semantics of Knit's and Unified.to's update endpoints were not verified. Whether a second same-code write in the same period adds to or replaces the first is not documented by Bindbee.
Sources checked
Wrong or out of date? payrolldataspecs@gmail.com — corrections are free. How claims are scored: methodology.