Create a Contractor payroll run and finalize it in one call. The body is the same as a Contractor create, except that externalId is required. The run is funded and its payables start paying out, as with POST /payments/payroll-runs/{payrollRunId}/finalize. Returns 201 with the new run.
Replaces V1/V2 POST /payments/pay-approved. To pay every approved payable, send {"type": "Contractor", "currency": "USD", "selection": {"scope": "ApprovedPayables"}, "externalId": "<your id>"}. A run pays payables in one currency, so make one call per currency.
externalId identifies the request. If the account already has a payroll run with this externalId, the call creates, funds and changes nothing, and answers by that run:
-
Same
type,currencyandselection, and the run isPaid,ProcessingorFailed:
200with the run. -
Same request, and the run is a
Draft:409 ResourceConflictwithdetailCode
payments.PayrollRunExternalIdDraftExists; itsdetailnames the run. The Draft still
holds its payables, so nobody is paid until you finalize it
(POST /payments/payroll-runs/{payrollRunId}/finalize) or delete it, then retry. -
Same request, and the run is
Cancelled:409 ResourceConflictwithdetailCode
payments.PayrollRunExternalIdCancelled. Use a newexternalId. -
A different
type,currencyorselection:409 ResourceConflictwithdetailCode
payments.PayrollRunExternalIdConflict.
This is not an upsert: the existing run is never updated. A new externalId starts a new payroll; use one to pay again after a Failed run.
Retrying: after a 5xx, a timeout or no response, send the same body with the same externalId. The funding may already have happened, and the same externalId cannot pay twice. A retry with the same Idempotency-Key within 10 minutes returns 409 IdempotencyKeyConflict with retryAfter (seconds to wait). A retry with a new Idempotency-Key returns 409 ResourceConflict while the first call is still running, and then answers by the run as described above (200 once it was funded or failed).
Outcomes when the call does not return a funded run. In each case no Draft run is left holding payables:
-
No payroll funding source, or an account that cannot fund payroll yet:
422, normally
before any run is created. -
No eligible payable matches the selection:
422withdetailCode
payments.PayrollRunNoEligiblePayablesMatched; no run is created. -
A selected payable stopped being payable after the run was created (paid, changed,
unapproved, or claimed by another run): the run is funded without it. If none is left,
the call returns422withdetailCodepayments.PayrollRunNoEligiblePayablesAtFinalize
and the run is deleted. -
Funding failed: the run is left
Failed, its payables are released, and the422
carries the run's failure reason as itsdetailCode. List that run with
filter[failureCode][anyOf]orfilter[externalId][eq]. -
Another create-and-finalize call is running for the account:
409 ResourceConflict. -
A payable changed at the moment funding started (a race):
409 ResourceConflict, and
the run is deleted, so a retry with the sameexternalIdtries again. -
Funding started but its outcome could not be confirmed: the run is left
Processingand
the call returns409 ResourceConflictwithdetailCode
payments.PayrollRunOutcomeUnknown; itsdetailnames the run. Do not run the payroll
again for these payables: get the run, and contact support if it staysProcessing.
Requires a session with recent MFA step-up for HighRiskWriteAction. If step-up is missing or expired, this operation returns 403 StepUpMfaRequired; create and verify an MFA challenge at /v3/platform/mfa-challenges with requiredFor: "HighRiskWriteAction", then retry.
| Time | Status | User Agent | |
|---|---|---|---|
Retrieving recent requests… | |||