Skip to content
All articles
Engineering8 July 2026·8 min read

Directory sync is reconciliation, not import

Treat a directory as a feed of changes and you will drift within a month. Treat it as a state to converge on and the problem gets smaller.

Paycux engineering

The first version of every directory integration is an import. Fetch the users, create the ones you do not have, done. It works, it demos well, and it starts drifting almost immediately.

Drift is not dramatic. A rename that never arrives. Someone who left the company but still has a row in your database. A group membership that was removed on their side and stayed on yours. Individually they are small. Collectively they are the reason a customer stops trusting the integration.

Events are a hint, not a source of truth

SCIM gives you change notifications, and it is tempting to treat them as a reliable log. They are not. Deliveries can be duplicated, reordered, or dropped by an intermediary having a bad afternoon. If your state is the result of replaying every event exactly once in order, your state is wrong the first time any of those things happens.

The better model is convergence. Events tell you something probably changed; your job is to make your view match theirs, which means knowing how to answer that question without the events at all.

Events tell you something probably changed. They do not tell you what things are now.

What that looks like in practice

Keep the provider's identifier, not just the email — people change their email and remain the same person. Store a snapshot of what you last saw, so a periodic full sync can diff rather than re-emit. Make every handler idempotent, keyed on the event id, because at-least-once delivery means duplicates are routine rather than exceptional.

And decide, explicitly, what deprovisioning means in your product. Deleting a user is rarely right — their work has to go somewhere. Most products want deactivation: access revoked immediately, data intact, restorable if the person comes back in three months.

  • Key on the provider identifier, never on the email address
  • Diff against a snapshot before emitting changes downstream
  • Make handlers idempotent on event id
  • Separate 'lost access' from 'deleted', and say so in your UI

The part that is genuinely hard

Group semantics. Some providers send full membership on every change, some send deltas, some send a group with a hundred members as a hundred separate events over several minutes. If access is derived from groups, a customer can watch their team lose permissions and get them back while a sync runs.

The fix is to make membership changes take effect on a settled state rather than on each event as it lands. It is unglamorous, and it is the difference between an integration people trust and one they check.

Everything here, already built

Sign-in, enterprise SSO, directory provisioning, roles and an audit trail behind one API. Start with the quickstart and have a working sign-in this afternoon.

Start selling to enterprise customers

Create an account, point sign-in at Paycux, and get back to the part of the product that is actually yours.