> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flowpayroll.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Salary API overview

> Turn an employee's effective-dated salary history into pay-run lines, pro-rated by calendar or working days, with a dry run you can call before anything is posted.

The Salary API turns the annual salary you record against an employee into the lines that appear on their pay run. It reads the effective-dated salary history held on the employee in the [Pay API](/api-reference/pay-api/overview), works out what is owed for the days they were employed in the pay period, and posts the result onto the open pay run. You configure how the pro-rata is worked out and what happens to the salary during statutory leave, and call a dry run to see what a period would produce before it is produced. For the product view, see [Salary](/guides/people/salary).

All endpoint paths on this page are relative to the service base path `/v1/salary`, appended to the gateway base URLs listed in the [API reference introduction](/api-reference/introduction).

<Note>
  The salary history itself lives on the employee, not here. Read it with `GET /employees/{employeeId}/salary` and change it with `PUT /employees/{employeeId}/salary` in the Pay API. This service only decides what that history is worth in a given pay period.
</Note>

## Key concepts

* **Salary history** — the employee's annual salary as a list of effective-dated versions, owned by the Pay API. The version in force on a day is the one with the latest `effectiveFrom` on or before it.
* **Enablement** — the organisation configuration's `enabled` flag. While it is `false`, or while no organisation configuration exists, the service is dormant: it posts nothing to a pay run and changes nothing already there. Turning it on is what starts salary lines appearing.
* **Calculation method** — `CalendarDays` or `WorkingDays`, deciding which days of a part period count. Calendar days count every day; working days count only the days the employee works, taken from their working pattern.
* **Method resolution** — the method for an employee is the first of: their own employee configuration, then the organisation configuration, then a built-in default of `CalendarDays`. Every response that resolves a method says which level answered, in `source`: `Employee`, `Organisation` or `Default`.
* **Segment** — a stretch of the pay period over which one salary version and one employment status apply. A period with no change has one segment; a salary change part-way through splits the period into two, and each becomes its own line.
* **Divisor** — for a part period, the number of qualifying days of the same kind in the **UK tax year (6 April to 5 April) containing the segment's first day**. That is 365 or 366 for calendar days, and the employee's own working days counted through the tax year for working days — so a three-day week divides by roughly 156, not 260.
* **Salary line** — a line item posted onto the pay run, with an id starting `internal_salary_`. It is posted with `canEdit: false`, so it is recalculated rather than edited; adjustments are separate manual lines.

## API structure

### Organisation configuration

Set how the organisation pro-rates salary, and whether the service runs at all, at `/organisation`. `GET` returns the configuration and `404`s when there is none, `PUT` creates or replaces it with `calculationMethod` and `enabled`, and `DELETE` removes it and returns the configuration it removed (`404` when there was none) — after which the service goes dormant for the organisation.

### Employee configuration

Override the method for one employee at `/employees/{employeeId}`. `GET` always returns `200`: an employee with no override has `calculationMethod: null` alongside the `effectiveCalculationMethod` and the `source` it came from. `PUT` sets the override, and `DELETE` removes it so the employee falls back to the organisation, returning the configuration now in force as the `GET` would.

### Statutory leave

Decide what happens to the salary on the days an employee is paid statutory pay, at `/organisation/leave` and `/employees/{employeeId}/leave`. The document has `sickness` (Statutory Sick Pay), `familyLeave` (the six family-leave payments) and `byType` (an exception for one family-leave payment, keyed by its name, such as `StatutoryPaternityPay`). Each policy is `DeductAbsentDays` (the default), with optional top-up `tiers`, each a `duration` (`{ "value": 6, "unit": "Week" }`) and a percentage of salary, or `FullPay`, which tops every day of the leave up to 100% and takes no tiers. Both take the days on leave back. `GET` always returns `200` with the stored document and `effective`, the setting each of the seven payments resolves to and its `source`. `PUT` replaces the whole document, and `DELETE` removes it and returns what now applies. See [Salary during statutory leave](/guides/people/salary-during-statutory-leave) for how the adjustment and top-up are worked out.

### Dry run

`POST /employees/{employeeId}/calculate` works out what a period would produce and returns it **without posting anything**. Send `payrollConfigId`, `periodStartDate`, `periodEndDate` and `frequency`; get back the resolved `calculationMethod`, its `source`, and a line per segment carrying `units`, `payRate`, `amount`, the `divisor` used, and the `segmentStart` and `segmentEnd` it covers. Use it to check a joiner, a leaver or a mid-period rise before the pay run is opened.

To preview statutory leave, add `statutoryLines`: each one's `statutoryType`, `units`, `unitName` and `amount`, and the `from` and `to` dates it pays for. Add `leaveStart` when a top-up has tiers, since they count from it. The response then also carries the adjustment and any top-up, told apart by `kind` (`Salary`, `StatutoryAbsenceAdjustment` or `StatutoryTopUp`) and naming the `statutoryType` they respond to.

## Typical workflow

1. Turn the service on for the organisation with `PUT /organisation`, choosing `calculationMethod` and `enabled: true`.
2. Override the method for any employee whose pro-rata differs, with `PUT /employees/{employeeId}`.
3. Record salary against the employee in the Pay API with `PUT /employees/{employeeId}/salary`, dated from when it applies.
4. Check an awkward period with `POST /employees/{employeeId}/calculate` before the pay run opens — a mid-month joiner, or a rise part-way through.
5. Set what happens during statutory leave with `PUT /organisation/leave`, if the default (deduct the days on leave, no top-up) is not your policy.
6. Open the pay run. Salary lines are posted as each payslip is previewed, and re-checked on every later preview.

## How a period is worked out

<Steps>
  <Step title="The employment window">
    The period is narrowed to the days the employee was actually employed: from the later of the period start and their start date, to the earlier of the period end and their leaving date. An employee employed for none of the period gets no lines.
  </Step>

  <Step title="Segments">
    The window is split at each salary `effectiveFrom` that falls inside it. Days before the employee's first salary version are unpaid, and a segment whose salary is 0 produces no line.
  </Step>

  <Step title="A full period">
    One segment covering the whole period is paid as a fraction of the year: the annual salary divided by the number of periods in the year — 52 weekly, 26 fortnightly, 13 four-weekly, 12 monthly, 4 quarterly, 2 twice-yearly, 1 annually. The line is a month, a week or a year of salary, not a count of days.
  </Step>

  <Step title="A part period">
    Anything else is paid per day: the qualifying days in the segment, at a rate of the annual salary divided by the qualifying days in the tax year. Which days qualify is the calculation method's answer, and both sides of the division use the same kind of day, so the two always agree.
  </Step>
</Steps>

A salary change part-way through a period therefore produces **two** lines — the old salary to the day before the change, the new one from it — and each says so in its description.

## Notes and best practices

### Changes reach open pay runs asynchronously

<Note>
  A configuration or salary write returns as soon as it is saved. Updating the salary lines on open pay runs happens afterwards, in the background, so don't read the payslip straight after a write and expect the new lines to be there.
</Note>

* **Every write triggers its own recalculation.** You don't need to call anything to refresh a pay run after changing a configuration or a salary. An employee-level change recalculates that employee's preview payslips on every open pay run they're on. An organisation-level change recalculates every employee, so on a large organisation expect the updates to finish over a short period rather than all at once.
* **Poll the payslip, not the configuration.** To confirm a change has landed, read the employee's payslip lines on the pay run and look for the updated salary line. The configuration endpoints only tell you what is saved.
* **Check lines before you lock.** Locking waits for recalculations already in progress, but nothing is written to a period once it is locked. After a batch of changes, confirm the payslip lines are what you expect before you lock the pay run.
* **Use the dry run to check figures.** `POST /employees/{employeeId}/calculate` uses the same configuration and employee record as the pay run, so its figures match what will be posted, and it returns them straight away without writing anything.

### Working with salary lines

* **Identify lines by their id prefix.** Salary lines start `internal_salary_`, statutory leave adjustments `internal_salary_adjustment_`, and top-ups `internal_salary_topup_`. Filter on these prefixes to tell salary lines apart from the rest of a payslip. Treat the part after the prefix as opaque.
* **Ids are stable across recalculations.** The same employee, period and segment always produce the same id, so recalculating replaces a line rather than duplicating it, and you can match lines between reads by id.
* **Don't edit salary lines — add to them.** They're posted with `canEdit: false`, like statutory payments, so they can always be recalculated from the salary history. To pay more or less than the calculated salary, add a separate manual line.
* **No salary lines isn't an error.** An employee with no salary version, or a period that starts after their leaving date, gets no salary lines. Pay a late bonus or final holiday pay as its own line.
* **Working days follow the working pattern.** The `WorkingDays` method uses the employee's own pattern, then the pay run's default, then the organisation's, then Monday to Friday. See [Working patterns](/guides/people/working-patterns).

### Requests and responses

* **`GET` on employee and leave configuration always returns `200`.** Read `effectiveCalculationMethod` or `effective`, and its `source`, to find out what applies — you don't need to handle a `404` or walk the fallback yourself. Only `GET /organisation` returns `404` when nothing is configured.
* **`DELETE` returns what now applies.** A delete answers `200` with the response envelope rather than `204`, so you don't need a second request to see the fallback now in force.
* **`PUT /…/leave` replaces the whole document.** Send every policy you want to keep, not just the one you're changing — anything you leave out falls back to the next level, as `effective` shows.

## Authentication

Every request needs an `X-Auth-Token` header, and credentials with access to more than one organisation also send `X-Org-Id` — see [Authentication](/api-reference/authentication). The organisation is always taken from those credentials, never from a request body. Responses use the shared envelope described in [Response format](/api-reference/response-format).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.