useCapxulRunPayroll
Mutation hook that executes a payroll run — one payroll Payment per active roster line, for a given period.
Executes a payroll run: pays every "active" line on the organization's
roster for one period, drawing
from an org sub-account envelope. Unlike a
Transfer, payroll is real money
leaving the organization — each roster line becomes a Payment with
paymentType: "payroll".
SDK-ready
Payroll is graded SDK-ready: the roster and run primitives are published and tested, but the scheduling / streaming payroll product experience is not SDK-complete yet. See Capability status.
Import
import { useCapxulRunPayroll } from "@capxul/sdk-react";Usage
"use client";
import { useCapxulRunPayroll } from "@capxul/sdk-react";
import type { OrgId, SubAccountId } from "@capxul/sdk";
function RunPayrollButton({
orgId,
payrollEnvelopeId,
}: {
orgId: OrgId;
payrollEnvelopeId: SubAccountId;
}) {
const runPayroll = useCapxulRunPayroll(orgId);
return (
<div>
<button
type="button"
disabled={runPayroll.isPending}
onClick={() => runPayroll.mutate({ from: payrollEnvelopeId, period: "2026-07" })}
>
{runPayroll.isPending ? "Running payroll…" : "Run July payroll"}
</button>
{runPayroll.data ? <p>{runPayroll.data.length} payments created</p> : null}
{runPayroll.error ? <p>{runPayroll.error.message}</p> : null}
</div>
);
}Parameters
orgId
OrgId | undefined
The organization running payroll. Unlike a query, a mutation cannot be
disabled — firing it while orgId is still undefined rejects with a
CapxulError.
The mutation takes a PayrollRunInput:
Prop
Type
from is the org sub-account envelope the run draws from. period names the
pay period and must be a YYYY-MM string (for example "2026-07").
Re-running the same period with an unchanged roster is idempotent: instead
of paying everyone twice, the run returns the payments already created for
that period. Changing the roster (or the from envelope) makes it a new run.
Return type
import { type UseCapxulRunPayrollReturn } from "@capxul/sdk-react";
// UseMutationResult<readonly Payment[], CapxulError, PayrollRunInput>On success, data is an array of Payment — one per active roster line, each
with paymentType: "payroll" and the roster line's amount, recipient, and
timing. Lines whose status is "paused" or "ended" are skipped.
The hook returns TanStack Query's UseMutationResult. The most-used fields:
| Field | Description |
|---|---|
mutate | Fire the mutation (fire-and-forget; pair with onSuccess/onError callbacks). |
mutateAsync | Fire the mutation and get a Promise of the result. Rejects with a CapxulError on failure. |
data | The mutation result (typed per hook, shown above). undefined until the first success. |
error | A CapxulError when the last attempt failed, otherwise null. |
isPending | true while the mutation is in flight. Use it to disable submit buttons. |
reset | Clear the mutation state (data, error) back to idle. |
Mutations do not retry by default. The full field list is in the
TanStack Query useMutation reference;
see also the TanStack Query integration guide.
Cache behavior
On success this mutation invalidates the org's roster
(["capxul", "org", orgId, "payroll", "roster"]) and the org's insights
summary and history. Then, because a run creates real payments, it also
invalidates the money state for each returned Payment: the payments list,
that payment's detail, the org's treasury and org account, and the org's
address book.
Errors
Failures surface as a CapxulError on
error / thrown from mutateAsync — notable modes:
orgIdis stillundefinedwhen the mutation fires.periodis not aYYYY-MMstring.- The roster has no
"active"lines — a run needs at least one. - The run's total exceeds the signed-in member's org spending cap. The whole run is rejected; there are no partial payments.
- The mutation fires while
<CapxulProvider>is still bootstrapping.
Client method
This hook wraps client.org(orgId).payroll.run(input) — the
entity-scoped org bundle on the core SDK. (The lower-level
client.org(orgId).batchPayroll(input) pays an ad-hoc list of recipients
without a roster; see the client reference.)