Prepare your first payroll draft
Prepare an isolated Test draft, verify it and stop before approval or payment.
Before you start
You are the company’s integration developer. Call https://api.kuahr.com with a Test key with payroll:write and payroll:read. If you create an employee first, also grant employees:write and follow employee creation.
An authorised company administrator must prepare an eligible payroll roster in the same company and Test partition: employment type, active employment, an effective salary structure, supported country calculator and required statutory profile information. Ask them to provision salary setup for the intended Test employee or provide a prepared Test fixture. The public API has no salary-setting endpoint; an employee-creation response alone cannot make a payroll-ready roster.
Create the draft
Choose the intended month and year for the prepared roster. Store a unique PAYROLL_OPERATION_KEY and the exact request body before sending it; reuse both on a retry. This example uses November 2026, so adjust the period deliberately if your fixture uses another month.
curl --fail-with-body https://api.kuahr.com/v1/payroll/runs \
-X POST -H "X-Api-Key: $KUA_API_KEY" \
-H "Idempotency-Key: $PAYROLL_OPERATION_KEY" \
-H "Content-Type: application/json" \
-d '{"year":2026,"month":11}'import { Kua } from "@kuahr/node";
const kua = new Kua({
apiKey: process.env.KUA_API_KEY!,
});
const run = await kua.payrollRuns.create(
{ year: 2026, month: 11 },
{ idempotencyKey: process.env.PAYROLL_OPERATION_KEY! },
);
console.log(run.id, run.status);import os
from kua import Kua
with Kua(api_key=os.environ["KUA_API_KEY"]) as kua:
run = kua.payroll_runs.create(
year=2026, month=11,
idempotency_key=os.environ["PAYROLL_OPERATION_KEY"],
)
print(run.id, run.status)HTTP 201 returns the run ID, period and status: "Draft". Keep the ID in your integration record. Creating a draft moves no money.
Verify it in the Test run list
curl --fail-with-body https://api.kuahr.com/v1/payroll/runs \
-H "X-Api-Key: $KUA_API_KEY"
Find the returned run ID in the array and check its period and Draft status. The list contains only your company’s Test runs. The Node equivalent is kua.payrollRuns.list(); Python is kua.payroll_runs.list().
Resolve an unsuccessful draft
| Result | What to check |
|---|---|
PAYROLL_RUN_EMPTY | No eligible salaried Test roster for this period. Ask the administrator to check active employment, mode and effective salary setup. |
| Country/statutory validation error | Resolve the returned profile or calculator prerequisite with the administrator. Do not assume an NGN example applies to every country. |
| Scope or workspace denial | Check the key’s grants and approval for that company. |
| Timeout or lost 201 | Reuse the same credential, operation key and exact body; then list runs before starting another operation. |
| Idempotency conflict | Follow the specific conflict code in retry guidance. |
Stop at the right outcome
Done when: the run ID appears as a Test Draft in the list. Approval, funding, disbursement, employee-wallet credit and bank withdrawal are separate outcomes, performed through authorised product flows. The public payroll API here does not expose an approve or pay operation.
Events and webhooks are Live-key only, so this Test draft journey does not promise an event. For a separately authorised receiver integration, follow webhook setup. Before any live integration, review go-live readiness.