Start a payroll cycle for a client
Who does this: Payroll Executive · Payroll Lead · Platform Admin When: At the start of the client's payroll month, or to recover a cycle the scheduler missed Result: A new cycle row, status
REQUESTED, and the month's request sent by email to each of the client's payroll senders.
Cycles can start themselves: payroll.cycle-initiate runs hourly and opens each client's month at their local 09:00 on the day-of-month set on the client record, retrying every hour for 48 hours if the first attempt can't proceed. You need this runbook when:
- The schedule day is in the future and you want to start now (e.g. an early month-end close)
- The scheduler missed the slot because the client was misconfigured at the time
- You're processing a one-off correction cycle for a specific month
- You're doing the client's first-ever cycle and want to step them through it
If the client's cycle already exists for the month you want, don't start another — the unique constraint on (client, cycle month) will refuse a duplicate. Open the existing one instead.
Before you start
- [ ] The client exists and has at least one active contact who can submit (
canSubmit = true). - [ ] The client has an auth policy configured (typically magic link).
- [ ] The client has document rules for the change types they expect (joiner / change / leaver bundles).
- [ ] The client has an active export template of kind
UPLOAD. - [ ] You know which cycle month you're processing, in
YYYY-MMformat.
If any of these are missing, the cycle initiator will refuse with a specific error. Open the client record, fill the gap, then come back here.
TIP
The Setup health panel on the client detail page goes green only when all four are configured. If anything is red there, fix it first.
Steps
- Open Clients in the staff dashboard sidebar.
- Find your client. Use the search box if your portfolio is long; the list is filterable by name, code, and product.
- Click into the client to open the client detail page.
- On the top right, click Start cycle.
- In the dialog:
- Cycle month: the month you're processing (e.g. for May 2026 payroll, enter
2026-05). - Reason (optional): a short note for the audit log — useful when you're starting a cycle off-schedule. Examples: "Early start — client cutoff moved up by 3 days" or "Recovery — scheduler missed because contact was inactive yesterday."
- Cycle month: the month you're processing (e.g. for May 2026 payroll, enter
- Click Start cycle.
The dialog closes with a confirmation toast. The cycle list now shows a new row for the month, status Requested.
How to know it worked
Three places to verify, in order of confidence:
- The cycle status badge flips from no row →
REQUESTEDimmediately. - What the client was told —
GET /ops/cycles/:cycleId/client-noticeslists the month's request with the words each payroll sender was sent. (Inside the platform, an outbox event is created in the same transaction that opens the cycle; the worker jobpayroll.cycle-opened-notifysends it once.) If it could not go to someone, the month carries a staff task saying why. - The audit log (cycle detail → Audit tab) shows three events:
cycle.created,cycle.requestedandoutbox.enqueued, all attributed to you. A cycle the scheduler opened carries the same three, attributed toworker:payroll.cycle-initiate.
If any one of these doesn't appear within a minute, see Why isn't my cycle showing?.
What the client sees
Opening a month sends the month's request to each payroll sender (contacts who can submit). The client answers by replying; when the company has a live payroll link, the request also ends with it (MAIL-4, 26 Oct 2026).
- By email to anyone with an email address, on that person's own thread for the month (subject "Payroll Input – {Month YYYY} – {company}", the firm's own subject since 26 Oct 2026; months started before keep their old thread), started from the firm-wide payroll mailbox chosen in Settings › Integrations.
- By their own chat only for a person with no email address (WhatsApp only within 24 hours of their last message).
- A person with an email is not moved to chat when no payroll mailbox is set up. Nothing is sent to them and the month gets a staff task saying so.
- A month opened by a document the client sent: its sender is answered where they sent it ("Thanks for your document: we've started your {Month YYYY} payroll."), and the other payroll senders get the request by email.
The request says what this client needs to send this month, from what the platform already knows:
- "Your {Month YYYY} payroll is now open.", then "Please send:" and the firm's own list, the headings of its "Payroll Input" email: new employees; resignations (last working day, unused leave, additions or deductions, the letter); leave taken; claims and reimbursements with receipts; allowances; interns; sales incentives and commissions; increments and bonuses; other deductions; NS days; overtime. A company that sends an attendance sheet every month has "the attendance sheet, as every month" first;
- on a company's real first month only, a starting point first: last month's payroll report from the previous provider, or the employee list (an employee list already on file is thanked for, not asked for again);
- what is already known about the month — leavers and their last day (with a note that a foreign employee's final pay waits for IRAS tax clearance, form IR21), changes already with us;
- changes still waiting for a document ("Still needed: …");
- when the inputs are due and when salaries go out: "Please send them by 18 October so salaries go out on 28 October." The day is the company's Inputs due by on Settings → Payroll (the 18th until set). A month opened after that day says "as soon as you can" instead. Settings → Payroll warns when the due day is not after the day the month opens (and onboarding shows the same warning against the 18th), naming what goes wrong: no date in any month's request, and every change on the payroll link after the cutoff from the day the month opens (stage review S1-02; the two defaults, 20th and 18th, wait for the PM's answer);
- "Just reply to this email with the files." (on chat: "Just send them here.");
- when the company has a live payroll link: "You can also send everything on your payroll page: {link}".
Emails greet the person by name ("Hi {name},") and end with the firm's sign-off, set by an admin on Settings → General ("Payroll team" until set); chat copies are short lines with no greeting. The word "cycle" is not used in anything the client reads.
A month the scheduler opened is an automatic message: it sends only while automatic messages are on (both the platform's MSG_AUTO_REPLY_ENABLED, on unless set to false, and the company's switch on Settings → Payroll, on by default). With either off the month still opens and staff get a task saying the request was not sent. A month you open by hand always sends.
If the client hasn't sent anything, reminders follow on day 3, 5 and 7 from 10:00 in the company's own time — see Reminders (P-12).
NOTE
Contacts marked Can approve but not Can submit are not part of this step. They receive the approval request later in the month.
Common situations
| If you see… | It means… | What to do |
|---|---|---|
| Start cycle button is disabled | Client has missing config (red on the Setup health panel) | Open client detail, fix what's red |
| Dialog rejects with "Cycle for {month} already exists" | A cycle row exists for that client + month | Open the existing cycle from the cycle list |
| Toast: "No active submitter contact" | Every contact with canSubmit=true has been deactivated, or none exists | Open client → Contacts and add or reactivate one |
| Toast: "No active UPLOAD template" | Client has never uploaded an Infotech import template, or the active one has been deactivated | Open client → Templates and activate one |
| Cycle is created but Outbox shows no rows after a minute | Outbox dispatcher is stuck | See Outbox stuck runbook |
| The month carries "{Last month} is not finished yet, so {this month}'s employee list … may still change" (blocking, Payroll Lead) | Last month was not finalised when this month opened, so this month's list came from the last finalised month (PAY-3) | Nothing, usually: when last month is finalised, this month's list catches up by itself (joiners, leavers, raises, on rows nobody changed) and the item clears. A Payroll Lead can release it with a reason (Resolve) to sign off earlier. A row someone changed this month, or a list the client sent this month, is left as it is; the month's history records the difference. |
| The month opened with no employees, though it is not the company's first month | No earlier month was finalised when it opened (a new client's second month opened by hand), so there was nothing to copy | Nothing, usually: when the month before is finalised, its list is filled in here by itself (stage review S1-01), unless the client has sent its own employee list for this month. The open toast and the Payroll Leads' alert say so. |
| A warning "{name} joined in {last month} but is not on this month's employee list" | Last month's joiner was sent to Infotech without an employee code, and Infotech's report gave no single match by name (or none was imported), so they could not be carried (S1-05) | Add them with the employee code Infotech gave them, then clear the warning |
| Toast: "{Month} has not started yet …" | A month after the current one (in the company's own time) cannot be opened (S1-04) | Open it on or after its first day; the scheduler opens it on its schedule day |
| Payroll Lead alerts reach the Admins, saying the firm has no active Payroll Lead | Nobody active has the Payroll Lead role, so the alerts meant for the Leads go to the Admins and Platform Admins instead (S1-09) | Make someone a Payroll Lead on Team |
Cancelling a month opened by mistake (current, 28 Oct 2026)
More actions → Opened by mistake? Cancel this cycle… on the month's page, with a reason. Cancelling stops the run, its reviews, reminders and deadlines, withdraws any approval request, and tells the client only if you tick the box.
- Not after the export. Once any export has gone to Infotech the month cannot be cancelled, whatever its status now (a figure that moved after the export sends the month back to Client review, but its file still stands). The button is hidden and the server refuses: correct the figure and regenerate the export; once finalized, a Payroll Lead reopens the payroll until the payslip step; if Infotech must not run the month at all, tell Infotech directly and note it on the month.
- Reopening revives only what the cancel waived. The cancel records which statutory clocks it waived; Reopen cycle puts those back to watching and no other. The IR21 clock is never revived by itself: the month's leavers are checked again, so a clock waived earlier because nobody owed it stays waived, and one a leaver still owes is watched again.
- A client's reply never reopens a cancelled month. A document for a cancelled month still starts the Open cycle review for staff, but the client is not asked "shall we start your payroll?" for it, and a client's "yes" that reaches the review anyway is refused. The review card says the month was cancelled and why; a staff member's approval reopens it (recorded as theirs), a rejection leaves it cancelled with the document kept as evidence.
Related runbooks
- Verify an email was sent
- Why isn't my cycle showing?
- When does each scheduled action fire? — for understanding the auto-initiation schedule
- Validation rules reference — the eight blocking rules a submission has to pass
- Payroll cycle status machine — the 16-state lifecycle this cycle now lives in