Payroll
Pay everyone who was in your game for more than five hours this week 100 Robux: written once as a rule, drafted automatically into a payout run, approved by a second person once it is large enough, released with an authenticator code, and written to the audit log at every step.
What it does
Two records live in Rostack and nowhere else: what somebody actually did in your game, and the Robux that left your group. Payroll joins them. You write a rule set once, it scores every person on your staff roster over a pay period, and the result becomes a draft payout run.
Payroll decides amounts. It never decides that money moves. There is no path through this feature that approves, releases or pays anything, and the run it produces is indistinguishable from one typed in by hand.
Before you start
| You need | Why |
|---|---|
| Activity tracking connected | Minutes rules score zero until a game server has reported. The preview says so in as many words rather than quietly paying nobody. |
| The Payroll module added | It is off in a new workspace. Adding it needs workspace.manage, and you can only add a module you could already open. |
| The Payouts module | On by default. It is where the run payroll builds is submitted, approved and released. |
| A verified email and an authenticator app | Every payroll request checks both, because payroll decides an amount and an amount is the first half of a payment. Releasing a run additionally needs a fresh code from that app. |
| Sessions, for the session rules | Only completed sessions count. A cancelled or still-scheduled one is not work somebody did. |
Reading payroll takes payouts.view. Editing the rules and building a run take payouts.run, which is checked again inside the payroll code against your staff record rather than only at the door. Approving and releasing take payouts.approve, which is a different permission on purpose: that split is the whole point of the approval step.
The rules
A rule set is a policy: a pay period, up to twenty rules, and a floor and a cap. Five kinds of rule exist, and no others.
| Rule | What it pays | Settings |
|---|---|---|
activity_minutes | A fixed amount, once, to anybody who reached a number of minutes in the period. | minMinutes, amount, countAfk |
activity_rate | An hourly rate. Nothing at all below the floor; minutes above the ceiling are unpaid. The result is floored to whole Robux, never rounded up. | amountPerHour, minMinutes, maxMinutes (0 means no ceiling), countAfk |
session_hosted | A fixed amount for every completed session they hosted, and optionally for those they co-hosted. | amount, includeCoHosted |
session_attended | A fixed amount for every completed session they attended, or only for those they passed. | amount, passedOnly |
rank_flat | A flat amount for holding one of the listed ranks, optionally conditional on having shown up at all. | amount, ranks, minMinutes (0 pays regardless of presence) |
countAfk chooses which measurement the rule reads: total minutes in a server, or the active part with idle time taken out. It is off by default, because idle is not work.
Around the rules sit the rule set's own settings. The pay period is 1 to 92 days and is a trailing window ending today, so this week means the last seven days rather than the days since Monday: a community spread across time zones has no shared Monday. Suspended staff are left out unless payWhileSuspended is deliberately turned on. Every rule floors to whole Robux before anything is summed, so a rounding decision is never made at the end where you cannot see which rule produced the fraction.
The floor raises, it never creates
One more deliberate refusal: a threshold rule never fires on zero minutes, even when its threshold is set to zero. "Worked at least nothing" is not a measurement, and a policy that pays the whole roster for never appearing is a misconfiguration every time.
The preview
The preview is the product. For every person it shows the measurements that were taken, each rule that fired, the arithmetic that rule performed in words, and the floor or cap that moved the result. An administrator reads that table before a single Robux moves, and the person who was paid reads the same numbers afterwards on their payslip.
one line of a preview
xFirmastic rank 50, Moderator
measured 412 minutes, 388 active, 24 AFK, across 5 days
3 game servers joined, 3 sessions hosted, 6 attended
Worked a full week
388 minutes active, at or above the 300 minutes threshold 100
Per session hosted
3 sessions hosted at 50 Robux each 150
subtotal 250
paid 250People no rule paid are not hidden. They appear in a second list carrying the reason: suspended and this rule set does not pay suspended staff, or no rule paid them for this period. Somebody expecting payment and not appearing at all is a support ticket; appearing with a stated reason is an answer.
The preview also states, in advance, everything that would make the build refuse or drop lines: a total above the per-run cap, a monthly cap this run would cross, lines above the per-recipient cap that will be recorded as skipped rather than paid, minutes rules scoring zero because no game server has ever reported, a roster larger than the five hundred staff records one preview considers, and whether the total is high enough to need a second approver.
Nothing about a preview is written, so the editor can recompute it on every change. Numbers produced from rules the editor is still holding are marked as unsaved, and they can never become a run: building always re-reads the stored rule set.
From preview to run
Building creates a normal payout run in draft through exactly the same routine that a hand-built run uses, plus one payslip per recipient. It inherits the whole guardrail stack unchanged: Roblox's 14-day group membership rule, the per-recipient, per-run and monthly caps, an idempotency key on every line, and the second-approval flag. Recipients Roblox will not accept are recorded on the run as skipped lines with the reason attached, not quietly dropped.
the path a payroll run walks
payroll preview
│ build (nothing has moved yet)
▼
payout run: draft
│ submit
▼
pending_approval
│ approve (a second person, once the run is large enough)
▼
approved
│ release (a fresh authenticator code)
▼
executing ──▶ settled | partially_settled | failedAbove the workspace's second-approval threshold, the approver may not be the person who prepared the run. Two identities are compared, the Roblox user and the account, and both have to differ, so one person holding two accounts is still one person. Releasing demands a fresh code from your authenticator on top of that, because drafting and approving are reversible and releasing is not.
A timer is not a second approver
Every step leaves an entry in the audit log with an actor, a reason and a trace id: the rule set being created, updated or deleted, the run being built with its total and period, and each state the run moves through afterwards.
Payslips
A payslip is the answer to "why was I paid this?". It names the rule set and the pay period, lists every rule that fired with its arithmetic and its amount, shows the evidence those rules were scored from, and states the subtotal and whether the floor or the cap moved it.
The arithmetic is copied onto the payslip rather than pointed at, so editing or deleting the policy tomorrow cannot change what somebody was told they were paid for today. The money is read live instead: the run's state and the recipient's own line inside it, because approved becomes paid hours later and a payslip still saying draft is the exact document a dispute turns on. A line that failed says failed rather than showing an amount nobody received.
Anyone can see their own
payouts.view.