Most HR-tech companies sell a “unified suite” — one product, one database, one UI. When customers ask why we run two apps connected by webhooks instead, the honest answer is that the two halves of the problem have very different shapes, and trying to merge them produces the all-in-one tools that everyone complains about: too generic for HR, too coarse for payroll, too painful to migrate from when either side needs to change.

This post is the architectural argument for the split. It’s also the reason we ship things faster than monolithic competitors and why our compliance posture is cleaner.

The two shapes

Leave management is a workflow product. The hard problems are user experience, approval chains, calendar visualisations, integrations with chat tools, mobile access. The data model is small. The calculations are simple.

Payroll is a calculation engine. The hard problems are tax brackets, statutory contributions, jurisdiction-specific rules, audit trails, bank file formats. The data model is enormous. The user-facing surface is narrow — admins run payroll once a month and read payslips.

Trying to fit both into one application means one of two things happens: either the leave UX gets compromised by the data weight of payroll, or the payroll engine gets compromised by the workflow flexibility of leave. Neither is acceptable for a product where both halves matter.

So we run two apps:

  • LeaveBalanceApp owns employee records, leave workflows, approval chains, the chat integrations, expenses, salary amendment requests, the year-end declaration, and bank account self-service.
  • PayrollApp owns the tax engine, statutory contributions, payslip generation, bank file output, and the year-end tax certificate generation.

The webhook fabric between them is what makes them feel like one product to the user.

What the webhook fabric does

Every event that needs to flow from one side to the other is a typed, signed, retryable webhook:

Event sourceEvent typeConsumer
LeaveBalanceAppemployee.joinedPayrollApp creates employee shell
LeaveBalanceAppemployee.exitedPayrollApp triggers final settlement
LeaveBalanceAppleave_request.approved (unpaid)PayrollApp records LOP for next run
LeaveBalanceAppleave_request.cancelledPayrollApp reverses LOP entry
LeaveBalanceAppexpense.approvedPayrollApp queues reimbursement for next run
LeaveBalanceAppsalary_amendment.approvedPayrollApp updates basic + applies effective date
LeaveBalanceAppleave_encashment.committedPayrollApp adds to taxable salary, fires TDS hook
PayrollApppayslip.generatedLeaveBalanceApp surfaces in employee dashboard

Each event carries its own state, signed with HMAC, idempotent on the consumer side, and retryable for up to 24 hours on failure. If PayrollApp is down for an hour, no events are lost — they replay automatically when it comes back.

Can't keep up with employee's
leave emails? Track your employee's leave with Leave Balance
cross icon

Why this is better than a monolith

Independent deploy cadence. PayrollApp can ship a tax-engine change without redeploying the entire HR product. LeaveBalanceApp can ship a UI overhaul without touching payroll math. Both happen daily without coordinating release windows.

Smaller blast radius. A bug in shift management doesn’t bring down payroll. A bug in tax calculation doesn’t break leave approvals. Each app owns its operational concerns.

Cleaner compliance boundary. PayrollApp holds Nepal-specific tax data. It doesn’t need to handle UK, AU, NZ, or US payroll. The leave product handles all jurisdictions for the workflow side, and routes payroll handoffs to whichever payroll system is wired up — PayrollApp for Nepal-bundled customers, Xero/KeyPay/Gusto for others.

Optional bundling. Customers in the UK don’t pay for the Nepal payroll engine they don’t use. Customers in Nepal get both apps under one bundle. The split lets pricing match value.

Migration safety. Customers can migrate the leave product without disrupting payroll, and vice versa. Adding a new payroll integration (next is KeyPay for AU/NZ) is purely an additive change.

Why this is better than a “best of breed” stack

The other extreme — separate vendors for HR, leave, expenses, and payroll, glued by Zapier — has the opposite problem. Every integration is a separate contract, a separate account, a separate failure mode.

Our split is intentional and integrated:

  • Two apps, not ten. The full surface is HR + leave + expenses + bank accounts + shift self-service + payroll calculation. That’s two products’ worth of scope, not ten.
  • Webhook fabric is bidirectional and signed. Not a Zapier glue layer.
  • One set of credentials. PayrollApp authenticates via OAuth2 against LeaveBalanceApp’s identity provider. Single sign-on, single audit log.
  • One billing line. Customers on the bundle pay one Stripe subscription that covers both apps.

The user experience is “one product”; the architecture is “two apps, designed to work together from day one.”

What this looks like for customers

For an HR admin in Nepal:

  • They sign in to LeaveBalanceApp at app.leavebalance.com/{tenant}.
  • They configure leave policies, employee records, approval chains.
  • They run payroll by clicking through to PayrollApp at payroll.leavebalance.com/{tenant} — same identity, single sign-on.
  • Webhooks keep both sides in sync; they never touch the integration layer.

For an HR admin in the UK or Australia:

  • They sign in to LeaveBalanceApp.
  • They configure their leave product fully.
  • They wire up Xero, KeyPay, or another payroll system via the integrations panel.
  • Webhooks deliver leave and expense data to that payroll system.
  • They never see PayrollApp because they don’t need it.

The split is invisible to both groups. Each gets the right tool for their stack, with the same source of truth on the leave side.

Can't keep up with employee's
leave emails? Track your employee's leave with Leave Balance
cross icon

The bigger point

The architecture choices behind a SaaS product are usually invisible to customers, but they show up in pricing, in deploy cadence, in how cleanly migrations work, and in whether the tool can grow with new jurisdictions. Two apps connected by webhooks is a deliberately old-fashioned answer in an industry obsessed with monolithic platforms — and we think it’s the right one.

If you’re evaluating an HR + payroll vendor and they tell you “it’s all one product,” ask what happens when you need to change payroll providers, switch jurisdictions, or migrate one half of the tool. Then ask the same of a vendor that ships modular apps with a webhook fabric. The answers tend to differ in interesting ways.