Skip to content

Overview

The REST API for systems integrating with Payloom: HRIS, accounting, data warehouses, and platforms that offer payroll to their own customers.

The key is the tenant. An organization’s key identifies both the caller and the organization, so its requests never name an organization (a header is ignored).

Money is always an object: {"amount_minor": 50000, "currency": "GHS"}. amount_minor is an integer in the currency’s minor unit (pesewas, cents, kobo). Zero-decimal currencies such as XOF have a 1:1 minor unit. Payloom never sends floats and never sums across currencies.

Lists are cursor-paginated. Pass the previous response’s next_cursor as starting_after; cursors stay valid while rows are inserted, which offsets do not. Use updated_since to sync incrementally between webhook deliveries.

Retries. Send an Idempotency-Key header on every POST and PATCH. A retry with the same key and body returns the original response (with Idempotent-Replay: true) instead of acting twice, which matters because a 429 explicitly invites you to retry. Reusing a key for a different body is refused. Keys are remembered for 24 hours.

Where Payloom is not available. A request from a country Payloom does not serve is refused with 451 and the code region_unavailable. Retrying does not help.

A key feeds and reads; people decide. A key reads what its scopes cover and submits inputs a person later acts on (employees, pay, one-off earnings, leave requests). It never makes a decision a person is accountable for (approving, reopening or paying a run, choosing the bank account): those stay in the console.

Webhooks

Rather than polling, register an endpoint in the Payloom console and we POST events to it as they happen. Every event is listed under webhooks below, with the resource it carries. payslip.published fires once per payslip when its pay run is marked paid; leave.requested and leave.decided fire when a request is submitted and when it is approved or declined.

Each request carries:

Payloom-Signature: t=1753440000,v1=<hex hmac>
Payloom-Event-Id: evt_9f2c...
Payloom-Event-Type: pay_run.approved
Payloom-Delivery-Id: ...
Payloom-Attempt: 1

Verify every request. Compute HMAC-SHA256(your_signing_secret, "<t>.<raw request body>") and compare it in constant time to a v1 value. Reject anything where t is more than five minutes old. The timestamp is inside the signed string precisely so a captured request cannot be replayed later. During a secret rotation the header carries several v1 values; a match against any one is valid, which is what lets you roll a secret without dropping deliveries.

The body is an envelope:

{
  "id": "evt_9f2c...", "type": "pay_run.approved",
  "api_version": "2026-07-25", "created_at": "2026-07-25T10:00:00Z",
  "organization_id": "...", "livemode": true,
  "data": { "object": { ... } }
}

data.object is the same representation this API returns for that resource, frozen at the moment the event occurred: a replay resends the original bytes, not the resource’s current state.

Respond 2xx quickly and do the work asynchronously. Anything else is retried eight times over roughly 24 hours (30s, 2m, 10m, 1h, 3h, 6h, 12h, with jitter); 410 Gone stops delivery immediately, and twenty consecutive failures disables the endpoint. Redirects are not followed. Deliveries can be inspected and replayed from the console.

Events can arrive more than once (a retry after your 2xx was lost) and are not ordered. Use Payloom-Event-Id to deduplicate.

Information

  • OpenAPI version: 3.1.0

Authorization: Bearer plm_live_<id>_<secret>. An organization’s keys are minted in the Payloom console by a member holding integrations.manage, and carry a subset of that member’s own permissions. A partner’s keys are minted by Payloom. The secret is shown once.

Keys are server-side credentials: never ship one in a browser or mobile client. They are rejected on the GraphQL endpoint by design.

Security scheme type: http