A payroll moves through a series of statuses from creation to completion. This page covers what happens at each stage, the webhook events you’ll receive, and how multi-currency payrolls are handled.Documentation Index
Fetch the complete documentation index at: https://docs.cadanapay.com/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Only 3 API calls needed — everything after approval is automatic.Create a payroll
Select the worker type (employee/contractor) and create a payroll.
POST /v1/payrolls → Webhook: payroll.createdSave entries
Provide the pay date, pay period, and compensation for each worker.
POST /v1/payrolls/{id}/save → Webhook: payroll.status.updated (saved)Approve
Approve the payroll to trigger fund collection and scheduling.
POST /v1/payrolls/{id}/approve → Webhook: payroll.status.updated (approved)What Happens After Approval
Once you callPOST /v1/payrolls/{id}/approve, the rest is automatic:
Balance Check
Cadana checks whether the business account has sufficient funds to cover the payroll.- Sufficient funds — the payroll moves to
Scheduledand is queued for the payroll date. Webhook:payroll.status.updated(scheduled) - Insufficient funds — the payroll moves to
Awaiting Funds. If a bank account is connected, an ACH debit initiates automatically. Once the account is funded, the payroll proceeds — no need to re-approve.
Scheduling
If the payroll date is in the future, the payroll stays inScheduled until that date. If the payroll date is today or in the past, disbursement begins immediately.
Disbursement
On the payroll date, Cadana triggers disbursements for each worker. The payroll moves toProcessing. Each worker’s payment is handled independently — if one worker’s payment fails, the others continue. Webhook: payroll.status.updated (processing)
Once the payroll reaches Processing, each entry on the GET /v1/payrolls/{payrollId} response includes a transactionIds array linking it to its underlying disbursement transactions. This is a polling-friendly alternative to the per-worker transaction.* webhook events for clients that prefer to fetch state on demand.
Completion
Once all disbursements are confirmed, the payroll moves toCompleted. Webhook: payroll.status.updated (completed)
After completion, the payroll response includes an invoiceId. Fetch the invoice for a detailed breakdown of fees charged for the payroll run.
Status Reference
These are the values returned in thestatus field on GET /v1/payrolls and GET /v1/payrolls/{id}.
| Status | Meaning |
|---|---|
Created | Empty payroll shell, no entries yet — returned right after POST /v1/payrolls |
Saved | Entries added, ready for approval |
Pending Approval | Submitted for an approver to action. You will only see this when the dashboard is used to submit a payroll; the POST /v1/payrolls/{id}/approve endpoint accepts payrolls in either Saved or Pending Approval. |
Awaiting Funds | Approved but the business balance is insufficient — payroll proceeds automatically once funded |
Scheduled | Funded and queued for the payroll date |
Processing | Disbursements are being sent to workers |
Completed | All disbursements confirmed (terminal) |
Rejected | An approver declined the payroll (terminal) |
Deleted | Caller deleted the payroll via DELETE /v1/payrolls/{id} before disbursement started (terminal) |
POST /v1/payrolls/{id}/save returns 204 immediately, but the new Saved status takes a few seconds to be reflected on GET /v1/payrolls/{id}. A tight poll loop right after save may still see Created briefly. POST /v1/payrolls/{id}/approve is strongly consistent — a follow-up GET will reflect the new status immediately.Saved and Awaiting Funds are not auto-cancelled — they sit indefinitely until you explicitly approve, delete, or (for Awaiting Funds) fund the business balance.Deleting a Payroll
You can delete a payroll at any point before it starts processing. Returns204 on success. The payroll moves to Deleted.
Webhook Events
Cadana emits two payroll webhook event types. Subscribe via the Dashboard or see Webhooks for setup.payroll.created
Fired when a new payroll is created.JSON
payroll.status.updated
Fired when the payroll moves into one of the values below.JSON
status value | Meaning |
|---|---|
saved | Entries saved, ready for approval |
approved | Payroll approved |
scheduled | Funds collected, queued for the payroll date |
processing | Disbursements being sent to workers |
completed | All disbursements confirmed |
No webhook fires for the
Awaiting Funds, Rejected, or Deleted states. Poll GET /v1/payrolls/{id} if you need to detect them.Per-Worker Transaction Events
Each worker’s payment fires individual transaction events:transaction.initiated, transaction.succeeded, and transaction.failed. These let you track each worker’s payout independently of the overall payroll status.
The transaction’s reference field contains the payrollId. recipientId is the worker’s identifier — use recipientType to interpret it: a userId when recipientType: "USER" (Cadana wallet payments), or a personId when EMPLOYEE or CONTRACTOR (direct bank payments).
JSON
Multi-Currency Payrolls
When a worker’s salary currency differs from the business’s funding currency (e.g., a US company paying a contractor in BRL), FX conversion is involved.How It Works
FX rates captured at save time
Cadana captures FX rates and calculates the debit amount in the funding currency. Each entry stores its conversion rate individually. Pass
?includeFxRates=true on the save call to receive the captured rates in the response (200 OK with { "fxRates": { "INR-USD": 0.0120, ... } }) instead of polling the payroll.Rates may refresh at disbursement time
If there’s a delay between save and disbursement (future payroll date, awaiting funds, etc.), rates may be refreshed with current market rates.
Recommended Approach
- Poll after save — check the
debitamount on the payroll to understand the total cost in your funding currency. - Fund with headroom — if your payroll date is days away, consider funding slightly above the quoted debit to absorb potential rate movement.
- Monitor
Awaiting Funds— if a rate refresh causes the debit to exceed your balance, the payroll pauses until you top up.
Edge Cases
Individual Worker Payment Fails
If one worker’s disbursement fails (e.g., invalid bank details), the other workers’ payments continue. The payroll still moves toCompleted once all disbursements are resolved. Use transaction.failed webhooks to identify which worker’s payment needs attention. The payroll itself does not have a failed status — that string only appears on per-worker transaction.* events.
Multiple Payrolls Awaiting Funds
When multiple payrolls are inAwaiting Funds and the business adds funds, Cadana schedules them in priority order:
- Earliest payroll date first
- Creation time as a tiebreaker
Scheduled. The rest remain in Awaiting Funds until more funds are added.
Payroll Stuck in Awaiting Funds
The payroll remains inAwaiting Funds indefinitely until the business account is funded. Once sufficient funds are available, the payroll proceeds automatically. See Fund Your Account for funding options.
Re-saving Before Approval
You can call save multiple times before approving. Each save replaces the previous entries entirely — there is no incremental add/remove of individual entries.Next Steps
Pay Workers via Payroll
Step-by-step guide to create, save, and approve a payroll
Fund Your Account
Add funds via bank transfer, ACH, or crypto
Webhooks
Configure your webhook endpoint
Events
All event types and payload schemas