Payroll that runs on the data you already have.
Attendance, leave, OT, holidays — already in ItzSEO. So payroll reads from those instead of asking HR to retype them into Tally, QuickBooks, or a spreadsheet. Monthly drafts, audited lifecycle, PDF payslips employees actually see.
Define once. Finalize monthly. Audit always.
No per-month re-entry. The structure persists; only attendance + leaves drive the monthly delta.
Salary structures
One per employee. Define basic, gross, and components — EARNINGS (HRA, special allowance, conveyance, custom) + DEDUCTIONS (PF, ESI, PT, TDS, custom). Version-history kept on every edit so you can answer 'why did Anindita's net pay change in July'.
14-calculator registry
FIXED, PER_DAY, PERCENT_OF_BASIC, PERCENT_OF_GROSS, BASIC_PRORATED, OT_HOURLY, plus India: IN_PF_EMPLOYEE/EMPLOYER, IN_ESI_EMPLOYEE/EMPLOYER, IN_PT_MAHARASHTRA/KARNATAKA/WEST_BENGAL, IN_TDS (Budget 2025). Component order enforced — gross-dependent calcs can't precede core earnings.
Monthly lifecycle
DRAFT → FINALIZED → AMENDED. DRAFTs auto-recalculate when source attendance or leave changes. FINALIZED locks the row + sends the employee an email + makes the PDF available. AMENDED writes an immutable audit row with HR's reason.
Manual entry + override
Mid-month joiners with no attendance yet? Create a manual-entry payslip with hand-typed values. Bonus or court-ordered garnishment? Direct-override after finalize, with required HR reason captured in the audit log. Both paths gated to HR + workspace owner.
Bulk finalize
Finalize the whole roster at once with a single click + confirm. Per-row failures surface inline, succeeded rows commit. No alert() interruptions — HR sees a color-coded result strip and re-runs as needed.
Modification history
Every recalc, override, amend, status change writes a PayslipModification row with before/after snapshot + actor + reason + trigger. Surfaces in the per-payslip detail panel. Concurrent recalc protection via lastRecalcAt CAS — no silent overwrites.
/me/payroll — clean, simple, downloadable.
DRAFTs are hidden until HR finalizes. No half-baked numbers leak.
Payslip list
Reverse chronological. Status pill (Final / Amended). Net pay + gross + period. Click a row → full breakdown of working days, present days, leave, OT, every earning + deduction line.
One-click PDF
@react-pdf/renderer single-page A4 with employer letterhead + employee name + period + line-item table + net pay box + finalized/amended dates. Logo failure-safe — broken logo URL falls back to text header without breaking the download.
Auto-emailed on finalize
Resend-delivered email lands when HR clicks Finalize. Amendment fires a second email with the reason. Both gated by /settings/notifications toggles employees control themselves.
Two crons keep drafts honest.
You shouldn't have to remember to draft payroll on the 1st. Or recalculate when an attendance event changes mid-month.
Monthly draft
/api/cron/payroll-monthly-draft fires on the 1st at 00:30 IST. Creates DRAFT payslips for every employee with an active salary structure, sourcing attendance + leave + OT from the prior month. Idempotent — safe to re-run.
Recalc safety net
/api/cron/payroll-recalc-pending fires every 4 hours. Catches DRAFTs where the source data changed but the inline recalc hook didn't fire (silent error, migration script, engineVersion bump). Optimistic concurrency guard on lastRecalcAt prevents stale overwrites.
PF, ESI, PT, TDS — all live.
Statutory math implemented to current spec. We audit ourselves when the law changes (we just rewrote TDS for Budget 2025).
PF (Provident Fund)
12% of basic, employee + employer halves as separate components. Wage-ceiling option available. Voluntary PF supported via custom components.
ESI (Employees' State Insurance)
0.75% employee + 3.25% employer (post-2019 rates). Per-workspace eligibility per ESI Act §10 — HR controls who's in the scheme, not a static gross-threshold gate.
Professional Tax
Maharashtra (₹0 up to ₹10k, ₹200 above, ₹300 in Feb), Karnataka, West Bengal slabs all shipped. Slab table reflects 2023 Maharashtra revision (no ₹175 mid-band).
TDS (Budget 2025)
₹75k standard deduction, ₹60k 87A rebate up to ₹12L taxable, 7-band ladder (4L/8L/12L/16L/20L/24L). New regime default. Old regime not bundled — HR uses a custom calc if needed.
Safety rails baked in.
CSV formula-injection defense — every cell starting with = + - @ or tab/CR is prefixed with ' to disarm Excel/Sheets formula triggers. Stops the "HR opens CSV → laptop pwned" class.
Money bounds + invariants — every minor-unit field bounded to ±₹1 crore. Net pay must equal gross minus deductions. Line items capped at 30. Payslip numbers charset-whitelisted.
payslipNumber uniqueness — @@unique([workspaceId, payslipNumber]) plus a P2002-retry helper means concurrent finalizes can't produce duplicate numbers.
Override blocked on DRAFT — calc engine owns DRAFTs. HR can only direct-override after finalize, so amendments can't be silently overwritten by the next recalc.
Holiday isPaid:false respected — unpaid holidays don't over-pay employees. Half-day leaves emit a 0.5 ABSENT row for the unworked half so workingDays totals correctly.
Payroll questions.
Does this replace my accountant?
What if our country isn't India?
What if HR makes a mistake?
Can employees see drafts?
What happens when attendance changes mid-month?
How does the modification history work?
Are payslips legal documents?
Is payroll included in the Agency tier?
Stop running payroll in spreadsheets.
14-day trial. Drafts on the 1st, payslips by the 5th, employees emailed automatically.